diff --git a/DEPS b/DEPS
index af356e3..9767383 100644
--- a/DEPS
+++ b/DEPS
@@ -129,11 +129,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '61a5f0aef8244af79a77b58360e9f660691e1886',
+  'skia_revision': '84a53268af92ca5a620c000a6199513350fdde36',
   # 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': '97e48306cddc4ce94bc2db8f2b0f344fbd0df9f1',
+  'v8_revision': 'd39b71f2cd84b3e5616fef16e309ec0fc8a0bb0e',
   # 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.
@@ -141,15 +141,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': '2e5afde1d68b68ab543e508c311c94f09921c07c',
+  'angle_revision': '6446c8882fa3efe151b1ee451554e68d10802cc7',
   # 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': '0839cbda698f3c4191dfb1bd76a0418b42dd2366',
+  'swiftshader_revision': '5bb034db62435bf943043dcb6e4fef4a131c7113',
   # 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': '466c9dadca6bed6518fae0687ae996a780d20a2e',
+  'pdfium_revision': 'ec1bd168d4942fd25ad808e7fff238a3e1e24d9d',
   # 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.
@@ -268,7 +268,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': '339bd9d4470db2d0ccf11343240bdc462a10aa3c',
+  'dawn_revision': '10c24684ab9cd1c747e251d7cb4590c43eecad6b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -805,7 +805,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd5a7a435d52663e5a5301194203ea786e023d47a',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8089b19ec11e9d4d0353415e35b746968c5341cb',
       'condition': 'checkout_linux',
   },
 
@@ -830,7 +830,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '51c0f388a154eb0e3c10ce6db73ad7aa128a9238',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd19589ff81c38ecc60228d0429cf39bfb4381ce6',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1063,7 +1063,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '0d2299c1ee04b9fb7c30e3ad555bf12e95157dfa',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'ecae7f8f81d866ac340834de3422f8c02d46a995',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1',
@@ -1172,7 +1172,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'be209a115315d3c5ca61104fa53ddb429343dd60',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '16e861080db99e8569d1ec07c80cf43c4bfa98d8',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1343,7 +1343,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '688fbfe33779392aa210d67d4aa12cb012f112c2',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '20393ee9b7ba622f254908646a9c31bf87349fc7',
+    Var('webrtc_git') + '/src.git' + '@' + 'b118d428499844749df6dd28aa3dbc8d5e1484fe',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1384,7 +1384,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@32283d398e23418d8347d5850dc9ecb9dd6736cc',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@bba4432cb3593398a9933f6cdbb9186e7f842261',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index d9970e0..8e1a84c6 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -582,6 +582,15 @@
       (),
     ),
     (
+      r'base::SharedMemory(|Handle)',
+      (
+          'base::SharedMemory is deprecated. Please use',
+          '{Writable,ReadOnly}SharedMemoryRegion instead.',
+      ),
+      False,
+      (),
+    ),
+    (
       r'RunMessageLoop',
       (
           'RunMessageLoop is deprecated, use RunLoop instead.',
@@ -806,9 +815,8 @@
     'build/android/test_runner.pydeps',
     'build/android/test_wrapper/logdog_wrapper.pydeps',
     'build/protoc_java.pydeps',
-    ('build/secondary/third_party/android_platform/'
-     'development/scripts/stack.pydeps'),
     'net/tools/testserver/testserver.pydeps',
+    'third_party/android_platform/development/scripts/stack.pydeps',
 ]
 
 
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc
index 992bc97e..c37f068 100644
--- a/android_webview/browser/aw_metrics_service_client.cc
+++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -20,7 +20,7 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/guid.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/i18n/rtl.h"
 #include "base/lazy_instance.h"
 #include "base/path_service.h"
diff --git a/android_webview/browser/icon_helper.cc b/android_webview/browser/icon_helper.cc
index e258f36..8ebd20cc 100644
--- a/android_webview/browser/icon_helper.cc
+++ b/android_webview/browser/icon_helper.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
diff --git a/android_webview/glue/BUILD.gn b/android_webview/glue/BUILD.gn
index 884c91c6..ec3fac7 100644
--- a/android_webview/glue/BUILD.gn
+++ b/android_webview/glue/BUILD.gn
@@ -21,7 +21,7 @@
   srcjar_deps = [ ":glue_resource_rewriter" ]
 
   alternative_android_sdk_dep =
-      "//third_party/android_system_sdk:public_framework_system_java"
+      "//third_party/android_sdk:public_framework_system_java"
 
   java_files = [
     "java/src/com/android/webview/chromium/CallbackConverter.java",
diff --git a/android_webview/tools/automated_ui_tests/BUILD.gn b/android_webview/tools/automated_ui_tests/BUILD.gn
index eda759cb..c6f0d1a 100644
--- a/android_webview/tools/automated_ui_tests/BUILD.gn
+++ b/android_webview/tools/automated_ui_tests/BUILD.gn
@@ -58,9 +58,9 @@
     "//base:base_java",
     "//base:base_java_test_support",
     "//third_party/android_deps:com_android_support_support_annotations_java",
+    "//third_party/android_sdk:android_test_base_java",
     "//third_party/android_support_test_runner:rules_java",
     "//third_party/android_support_test_runner:runner_java",
-    "//third_party/android_tools:android_test_base_java",
     "//third_party/espresso:espresso_all_java",
     "//third_party/hamcrest:hamcrest_java",
     "//third_party/junit",
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 8b39423b..a743306 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -1670,6 +1670,9 @@
 
   // If true then we should expect the action will handle the media keys.
   bool eligible_action = false;
+
+  // If true then we should force forwarding the action to the client.
+  bool force_key_handling = false;
 };
 
 }  // namespace
@@ -1703,6 +1706,8 @@
     media_controller->SetClient(client_->CreateAssociatedPtrInfo());
     media_controller->SetMediaSessionControllerForTest(
         controller_->CreateMediaControllerPtr());
+    media_controller->SetForceMediaClientKeyHandling(
+        GetParam().force_key_handling);
     media_controller->FlushForTesting();
   }
 
@@ -1735,6 +1740,8 @@
 
   bool eligible_action() const { return GetParam().eligible_action; }
 
+  bool force_key_handling() const { return GetParam().force_key_handling; }
+
   void ExpectActionRecorded(ui::MediaHardwareKeyAction action) {
     histogram_tester_.ExpectBucketCount(
         ui::kMediaHardwareKeyActionHistogramName,
@@ -1791,7 +1798,15 @@
                                           MediaSessionAction::kSeekBackward},
         MediaSessionAcceleratorTestConfig{false,
                                           MediaSessionAction::kSeekForward},
-        MediaSessionAcceleratorTestConfig{false, MediaSessionAction::kStop}));
+        MediaSessionAcceleratorTestConfig{false, MediaSessionAction::kStop},
+        MediaSessionAcceleratorTestConfig{true, MediaSessionAction::kPlay,
+                                          false, true},
+        MediaSessionAcceleratorTestConfig{true, MediaSessionAction::kPause,
+                                          false, true},
+        MediaSessionAcceleratorTestConfig{true, MediaSessionAction::kNextTrack,
+                                          false, true},
+        MediaSessionAcceleratorTestConfig{
+            true, MediaSessionAction::kPreviousTrack, false, true}));
 
 TEST_P(MediaSessionAcceleratorTest, MediaPlaybackAcceleratorsBehavior) {
   const ui::KeyboardCode media_keys[] = {ui::VKEY_MEDIA_NEXT_TRACK,
@@ -1838,7 +1853,7 @@
   ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE));
   Shell::Get()->media_controller()->FlushForTesting();
 
-  if (service_enabled() && eligible_action()) {
+  if (service_enabled() && eligible_action() && !force_key_handling()) {
     EXPECT_EQ(0, client()->handle_media_next_track_count());
     EXPECT_EQ(1, controller()->next_track_count());
   } else {
@@ -1884,7 +1899,7 @@
   ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE));
   Shell::Get()->media_controller()->FlushForTesting();
 
-  if (service_enabled() && eligible_action()) {
+  if (service_enabled() && eligible_action() && !force_key_handling()) {
     EXPECT_EQ(0, client()->handle_media_play_pause_count());
     EXPECT_EQ(1, controller()->suspend_count());
 
@@ -1910,7 +1925,7 @@
   ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE));
   Shell::Get()->media_controller()->FlushForTesting();
 
-  if (service_enabled() && eligible_action()) {
+  if (service_enabled() && eligible_action() && !force_key_handling()) {
     EXPECT_EQ(0, client()->handle_media_prev_track_count());
     EXPECT_EQ(1, controller()->previous_track_count());
   } else {
@@ -1931,7 +1946,7 @@
   ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE));
   Shell::Get()->media_controller()->FlushForTesting();
 
-  if (service_enabled() && eligible_action()) {
+  if (service_enabled() && eligible_action() && !force_key_handling()) {
     EXPECT_EQ(0, client()->handle_media_next_track_count());
     EXPECT_EQ(1, controller()->next_track_count());
   } else {
@@ -1944,7 +1959,7 @@
   ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE));
   Shell::Get()->media_controller()->FlushForTesting();
 
-  if (service_enabled() && eligible_action()) {
+  if (service_enabled() && eligible_action() && !force_key_handling()) {
     EXPECT_EQ(1, client()->handle_media_next_track_count());
     EXPECT_EQ(1, controller()->next_track_count());
   } else {
@@ -1969,7 +1984,7 @@
   ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE));
   Shell::Get()->media_controller()->FlushForTesting();
 
-  if (service_enabled() && eligible_action()) {
+  if (service_enabled() && eligible_action() && !force_key_handling()) {
     EXPECT_EQ(1, client()->handle_media_next_track_count());
     EXPECT_EQ(1, controller()->next_track_count());
   } else {
@@ -1978,4 +1993,50 @@
   }
 }
 
+TEST_P(MediaSessionAcceleratorTest,
+       MediaGlobalAccelerators_UpdateForceKeyHandling) {
+  MaybeEnableMediaSession(media_session::mojom::MediaPlaybackState::kPaused);
+
+  EXPECT_EQ(0, client()->handle_media_next_track_count());
+  EXPECT_EQ(0, controller()->next_track_count());
+
+  ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE));
+  Shell::Get()->media_controller()->FlushForTesting();
+
+  if (service_enabled() && eligible_action() && !force_key_handling()) {
+    EXPECT_EQ(0, client()->handle_media_next_track_count());
+    EXPECT_EQ(1, controller()->next_track_count());
+  } else {
+    EXPECT_EQ(1, client()->handle_media_next_track_count());
+    EXPECT_EQ(0, controller()->next_track_count());
+  }
+
+  // Update the force media client key handling setting. It may have been
+  // previously set if |force_key_handling| is true.
+  Shell::Get()->media_controller()->SetForceMediaClientKeyHandling(false);
+
+  ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE));
+  Shell::Get()->media_controller()->FlushForTesting();
+
+  if (service_enabled() && force_key_handling()) {
+    // If we had |force_key_handling| true the first time we pressed the play
+    // pause key then we should see the previous action that was forward to the
+    // client. Since the service is enabled, the second action will be handled
+    // by the controller.
+    EXPECT_EQ(1, client()->handle_media_next_track_count());
+    EXPECT_EQ(1, controller()->next_track_count());
+  } else if (service_enabled() && eligible_action()) {
+    // If we had |force_key_handling| disabled the whole time and the service
+    // enabled then both actions should be handled in the controller.
+    EXPECT_EQ(0, client()->handle_media_next_track_count());
+    EXPECT_EQ(2, controller()->next_track_count());
+  } else {
+    // If we had |force_key_handling| disabled the whole time and the service
+    // disabled then both actions should fallback to the client because there is
+    // nothing in Ash to handle them.
+    EXPECT_EQ(2, client()->handle_media_next_track_count());
+    EXPECT_EQ(0, controller()->next_track_count());
+  }
+}
+
 }  // namespace ash
diff --git a/ash/accelerators/accelerator_table_unittest.cc b/ash/accelerators/accelerator_table_unittest.cc
index 9c18c17..8fcb3c2 100644
--- a/ash/accelerators/accelerator_table_unittest.cc
+++ b/ash/accelerators/accelerator_table_unittest.cc
@@ -6,8 +6,8 @@
 #include <tuple>
 
 #include "ash/accelerators/accelerator_table.h"
+#include "base/hash/md5.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ash/accessibility/accessibility_panel_layout_manager.cc b/ash/accessibility/accessibility_panel_layout_manager.cc
index a95c99b7..4c1af0e7 100644
--- a/ash/accessibility/accessibility_panel_layout_manager.cc
+++ b/ash/accessibility/accessibility_panel_layout_manager.cc
@@ -34,6 +34,9 @@
 void AccessibilityPanelLayoutManager::SetPanelBounds(
     const gfx::Rect& bounds,
     mojom::AccessibilityPanelState state) {
+  if (!panel_window_)
+    return;
+
   panel_bounds_ = bounds;
   panel_state_ = state;
   UpdateWindowBounds();
@@ -88,7 +91,7 @@
 
 void AccessibilityPanelLayoutManager::OnFullscreenStateChanged(
     bool is_fullscreen,
-    aura::Window* root_window) {
+    aura::Window* container) {
   UpdateWindowBounds();
 }
 
diff --git a/ash/accessibility/accessibility_panel_layout_manager.h b/ash/accessibility/accessibility_panel_layout_manager.h
index ffa5b048..70c90c2a 100644
--- a/ash/accessibility/accessibility_panel_layout_manager.h
+++ b/ash/accessibility/accessibility_panel_layout_manager.h
@@ -65,7 +65,7 @@
 
   // ShellObserver:
   void OnFullscreenStateChanged(bool is_fullscreen,
-                                aura::Window* root_window) override;
+                                aura::Window* container) override;
 
   aura::Window* panel_window_for_test() { return panel_window_; }
 
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index 117b4507..b2dddca 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -284,6 +284,10 @@
   return false;
 }
 
+void SearchResultView::ChildPreferredSizeChanged(views::View* child) {
+  Layout();
+}
+
 void SearchResultView::PaintButtonContents(gfx::Canvas* canvas) {
   gfx::Rect rect(GetContentsBounds());
   if (rect.IsEmpty())
diff --git a/ash/app_list/views/search_result_view.h b/ash/app_list/views/search_result_view.h
index f9b7cd2..b3b88c8 100644
--- a/ash/app_list/views/search_result_view.h
+++ b/ash/app_list/views/search_result_view.h
@@ -102,6 +102,7 @@
   gfx::Size CalculatePreferredSize() const override;
   void Layout() override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
+  void ChildPreferredSizeChanged(views::View* child) override;
   void PaintButtonContents(gfx::Canvas* canvas) override;
   void OnFocus() override;
   void OnBlur() override;
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 65d4bf8..dd453897 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -817,6 +817,33 @@
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_DISCONNECTED_SUBLABEL" desc="The sub label text used when network is not connected.">
         No networks
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_ONE_X" desc="The sub label text used when a cellular connection is using the 1xRTT connectivity type.">
+        1X
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_GSM" desc="The sub label text used when a cellular connection is using the GSM connectivity type.">
+        GSM
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_GPRS" desc="The sub label text used when a cellular connection is using the GPRS connectivity type.">
+        GPRS
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_EDGE" desc="The sub label text used when a cellular connection is using the EDGE connectivity type.">
+        EDGE
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_THREE_G" desc="The sub label text used when a cellular connection is using the 3G connectivity type.">
+        3G
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_HSPA" desc="The sub label text used when a cellular connection is using the HSPA connectivity type.">
+        HSPA
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_HSPA_PLUS" desc="The sub label text used when a cellular connection is using the HSPA+ connectivity type.">
+        H+
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_LTE" desc="The sub label text used when a cellular connection is using the LTE connectivity type.">
+        LTE
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_LTE_PLUS" desc="The sub label text used when a cellular connection is using the LTE Advanced connectivity type.">
+        LTE+
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_WEAK_SUBLABEL" desc="The sub label text used when WiFi signal strength is weak (among weak, medium, and strong.)">
         Weak
       </message>
diff --git a/ash/assistant/assistant_alarm_timer_controller.cc b/ash/assistant/assistant_alarm_timer_controller.cc
index 248a0f32..38c1a2c 100644
--- a/ash/assistant/assistant_alarm_timer_controller.cc
+++ b/ash/assistant/assistant_alarm_timer_controller.cc
@@ -146,6 +146,34 @@
   model_.RemoveAllAlarmsTimers();
 }
 
+void AssistantAlarmTimerController::OnAlarmTimerStateChanged(
+    mojom::AssistantAlarmTimerEventPtr event) {
+  if (!event) {
+    // Nothing is ringing. Remove all alarms and timers.
+    model_.RemoveAllAlarmsTimers();
+    return;
+  }
+
+  switch (event->type) {
+    case mojom::AssistantAlarmTimerEventType::kTimer:
+      if (event->data->get_timer_data()->state ==
+          mojom::AssistantTimerState::kFired) {
+        // Remove all timers/alarms since there will be only one timer/alarm
+        // firing.
+        // TODO(llin): Handle multiple timers firing when the API is supported.
+        model_.RemoveAllAlarmsTimers();
+
+        AlarmTimer timer;
+        timer.id = event->data->get_timer_data()->timer_id;
+        timer.type = AlarmTimerType::kTimer;
+        timer.end_time = base::TimeTicks::Now();
+        model_.AddAlarmTimer(timer);
+      }
+      break;
+      // TODO(llin): Handle alarm event.
+  }
+}
+
 void AssistantAlarmTimerController::OnAlarmTimerAdded(
     const AlarmTimer& alarm_timer,
     const base::TimeDelta& time_remaining) {
diff --git a/ash/assistant/assistant_alarm_timer_controller.h b/ash/assistant/assistant_alarm_timer_controller.h
index ac3a1b7..9ee5c7a 100644
--- a/ash/assistant/assistant_alarm_timer_controller.h
+++ b/ash/assistant/assistant_alarm_timer_controller.h
@@ -38,6 +38,8 @@
   // mojom::AssistantAlarmTimerController:
   void OnTimerSoundingStarted() override;
   void OnTimerSoundingFinished() override;
+  void OnAlarmTimerStateChanged(
+      mojom::AssistantAlarmTimerEventPtr event) override;
 
   // AssistantAlarmTimerModelObserver:
   void OnAlarmTimerAdded(const AlarmTimer& alarm_timer,
diff --git a/ash/login/ui/scrollable_users_list_view.cc b/ash/login/ui/scrollable_users_list_view.cc
index 5c1a14bb..586c0bc3 100644
--- a/ash/login/ui/scrollable_users_list_view.cc
+++ b/ash/login/ui/scrollable_users_list_view.cc
@@ -23,8 +23,8 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_analysis.h"
 #include "ui/gfx/color_utils.h"
-#include "ui/views/controls/scrollbar/base_scroll_bar.h"
 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
+#include "ui/views/controls/scrollbar/scroll_bar.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
 
@@ -94,7 +94,7 @@
 
 class ScrollBarThumb : public views::BaseScrollBarThumb {
  public:
-  explicit ScrollBarThumb(views::BaseScrollBar* scroll_bar)
+  explicit ScrollBarThumb(views::ScrollBar* scroll_bar)
       : BaseScrollBarThumb(scroll_bar) {}
   ~ScrollBarThumb() override = default;
 
@@ -155,10 +155,10 @@
 
 // Shows a scrollbar that automatically displays and hides itself when content
 // is scrolled.
-class UsersListScrollBar : public views::BaseScrollBar {
+class UsersListScrollBar : public views::ScrollBar {
  public:
   explicit UsersListScrollBar(bool horizontal)
-      : BaseScrollBar(horizontal),
+      : ScrollBar(horizontal),
         hide_scrollbar_timer_(
             FROM_HERE,
             kScrollThumbHideTimeout,
@@ -172,7 +172,7 @@
   }
   ~UsersListScrollBar() override = default;
 
-  // views::BaseScrollBar:
+  // views::ScrollBar:
   gfx::Rect GetTrackBounds() const override { return GetLocalBounds(); }
   bool OverlapsContent() const override { return true; }
   int GetThickness() const override {
@@ -189,7 +189,7 @@
   }
   void ScrollToPosition(int position) override {
     ShowScrollbar();
-    views::BaseScrollBar::ScrollToPosition(position);
+    views::ScrollBar::ScrollToPosition(position);
   }
   void ObserveScrollEvent(const ui::ScrollEvent& event) override {
     // Scroll fling events are generated by moving a single finger over the
diff --git a/ash/media/media_controller.cc b/ash/media/media_controller.cc
index 49424bd9..e3591a7a 100644
--- a/ash/media/media_controller.cc
+++ b/ash/media/media_controller.cc
@@ -51,6 +51,17 @@
 
 void MediaController::SetClient(mojom::MediaClientAssociatedPtrInfo client) {
   client_.Bind(std::move(client));
+
+  // When |client_| is changed or encounters an error we should reset the
+  // |force_media_client_key_handling_| bit.
+  ResetForceMediaClientKeyHandling();
+  client_.set_connection_error_handler(
+      base::BindOnce(&MediaController::ResetForceMediaClientKeyHandling,
+                     base::Unretained(this)));
+}
+
+void MediaController::SetForceMediaClientKeyHandling(bool enabled) {
+  force_media_client_key_handling_ = enabled;
 }
 
 void MediaController::NotifyCaptureState(
@@ -60,6 +71,13 @@
 }
 
 void MediaController::HandleMediaPlayPause() {
+  // If the |client_| is force handling the keys then we should forward them.
+  if (client_ && force_media_client_key_handling_) {
+    ui::RecordMediaHardwareKeyAction(ui::MediaHardwareKeyAction::kPlayPause);
+    client_->HandleMediaPlayPause();
+    return;
+  }
+
   // If media session media key handling is enabled. Toggle play pause using the
   // media session service.
   if (ShouldUseMediaSession()) {
@@ -92,6 +110,12 @@
   ui::RecordMediaHardwareKeyAction(
       ui::MediaHardwareKeyAction::kNextTrack);
 
+  // If the |client_| is force handling the keys then we should forward them.
+  if (client_ && force_media_client_key_handling_) {
+    client_->HandleMediaNextTrack();
+    return;
+  }
+
   // If media session media key handling is enabled. Fire next track using the
   // media session service.
   if (ShouldUseMediaSession()) {
@@ -107,6 +131,12 @@
   ui::RecordMediaHardwareKeyAction(
       ui::MediaHardwareKeyAction::kPreviousTrack);
 
+  // If the |client_| is force handling the keys then we should forward them.
+  if (client_ && force_media_client_key_handling_) {
+    client_->HandleMediaPrevTrack();
+    return;
+  }
+
   // If media session media key handling is enabled. Fire previous track using
   // the media session service.
   if (ShouldUseMediaSession()) {
@@ -196,4 +226,8 @@
          !media_session_info_.is_null();
 }
 
+void MediaController::ResetForceMediaClientKeyHandling() {
+  force_media_client_key_handling_ = false;
+}
+
 }  // namespace ash
diff --git a/ash/media/media_controller.h b/ash/media/media_controller.h
index 13650f8d..d01984e3 100644
--- a/ash/media/media_controller.h
+++ b/ash/media/media_controller.h
@@ -50,6 +50,7 @@
 
   // mojom::MediaController:
   void SetClient(mojom::MediaClientAssociatedPtrInfo client) override;
+  void SetForceMediaClientKeyHandling(bool enabled) override;
   void NotifyCaptureState(
       const base::flat_map<AccountId, mojom::MediaCaptureState>& capture_states)
       override;
@@ -91,6 +92,8 @@
                            MediaGlobalAccelerators_UpdateAction_Disable);
   FRIEND_TEST_ALL_PREFIXES(MediaSessionAcceleratorTest,
                            MediaGlobalAccelerators_UpdateAction_Enable);
+  FRIEND_TEST_ALL_PREFIXES(MediaSessionAcceleratorTest,
+                           MediaGlobalAccelerators_UpdateForceKeyHandling);
 
   void SetMediaSessionControllerForTest(
       media_session::mojom::MediaControllerPtr controller);
@@ -107,6 +110,8 @@
   // Returns true if we should use the media session service for key handling.
   bool ShouldUseMediaSession();
 
+  void ResetForceMediaClientKeyHandling();
+
   // Whether the active media session currently supports any action that has a
   // media key.
   bool supported_media_session_action_ = false;
@@ -115,6 +120,10 @@
   // a current session.
   media_session::mojom::MediaSessionInfoPtr media_session_info_;
 
+  // If true then the media keys should be forwarded to the client instead of
+  // being handled in ash.
+  bool force_media_client_key_handling_ = false;
+
   // Mojo pointer to the active media session controller.
   media_session::mojom::MediaControllerPtr media_session_controller_ptr_;
 
diff --git a/ash/media/media_notification_background.cc b/ash/media/media_notification_background.cc
index 4aba362..57eb40d 100644
--- a/ash/media/media_notification_background.cc
+++ b/ash/media/media_notification_background.cc
@@ -5,8 +5,12 @@
 #include "ash/media/media_notification_background.h"
 
 #include <algorithm>
+#include <vector>
 
+#include "skia/ext/image_operations.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/color_analysis.h"
+#include "ui/gfx/color_utils.h"
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/views/view.h"
 
@@ -16,7 +20,66 @@
 
 constexpr int kMediaImageGradientWidth = 40;
 
-constexpr SkColor kMediaNotificationBackgroundColor = SK_ColorWHITE;
+constexpr SkColor kMediaNotificationDefaultBackgroundColor = SK_ColorWHITE;
+
+// The ratio for a background color option to be considered very popular.
+constexpr double kMediaNotificationBackgroundColorVeryPopularRatio = 2.5;
+
+bool IsNearlyWhiteOrBlack(SkColor color) {
+  color_utils::HSL hsl;
+  color_utils::SkColorToHSL(color, &hsl);
+  return hsl.l >= 0.9 || hsl.l <= 0.08;
+}
+
+base::Optional<SkColor> GetNotificationBackgroundColor(const SkBitmap* source) {
+  if (!source || source->empty() || source->isNull())
+    return base::nullopt;
+
+  std::vector<color_utils::Swatch> swatches =
+      color_utils::CalculateColorSwatches(
+          *source, 16, gfx::Rect(source->width() / 2, source->height()),
+          false /* exclude_uninteresting */);
+
+  if (swatches.empty())
+    return base::nullopt;
+
+  base::Optional<color_utils::Swatch> most_popular;
+  base::Optional<color_utils::Swatch> non_white_black;
+
+  // Find the most popular color with the most weight and the color which
+  // is the color with the most weight that is not white or black.
+  for (auto& swatch : swatches) {
+    if (!IsNearlyWhiteOrBlack(swatch.color) &&
+        (!non_white_black || swatch.population > non_white_black->population)) {
+      non_white_black = swatch;
+    }
+
+    if (most_popular && swatch.population < most_popular->population)
+      continue;
+
+    most_popular = swatch;
+  }
+
+  DCHECK(most_popular);
+
+  // If the most popular color is not white or black then we should use that.
+  if (!IsNearlyWhiteOrBlack(most_popular->color))
+    return most_popular->color;
+
+  // If we could not find a color that is not white or black then we should
+  // use the most popular color.
+  if (!non_white_black)
+    return most_popular->color;
+
+  // If the most popular color is very popular then we should use that color.
+  if (static_cast<double>(most_popular->population) /
+          non_white_black->population >
+      kMediaNotificationBackgroundColorVeryPopularRatio) {
+    return most_popular->color;
+  }
+
+  return non_white_black->color;
+}
 
 }  // namespace
 
@@ -32,6 +95,8 @@
   DCHECK(owner);
 }
 
+MediaNotificationBackground::~MediaNotificationBackground() = default;
+
 void MediaNotificationBackground::Paint(gfx::Canvas* canvas,
                                         views::View* view) const {
   DCHECK(view);
@@ -70,18 +135,16 @@
 
   // Draw a filled rectangle which will act as the main background of the
   // notification. This may cover up some of the artwork.
-  canvas->FillRect(GetFilledBackgroundBounds(bounds),
-                   kMediaNotificationBackgroundColor);
+  const SkColor background_color =
+      background_color_.value_or(kMediaNotificationDefaultBackgroundColor);
+  canvas->FillRect(GetFilledBackgroundBounds(bounds), background_color);
 
   {
     // Draw a gradient to fade the color background and the image together.
     gfx::Rect draw_bounds = GetGradientBounds(bounds);
 
-    const SkColor transparent =
-        SkColorSetA(kMediaNotificationBackgroundColor, 0);
-
-    const SkColor colors[2] = {kMediaNotificationBackgroundColor, transparent};
-
+    const SkColor colors[2] = {
+        background_color, SkColorSetA(background_color, SK_AlphaTRANSPARENT)};
     const SkPoint points[2] = {gfx::PointToSkPoint(draw_bounds.left_center()),
                                gfx::PointToSkPoint(draw_bounds.right_center())};
 
@@ -100,6 +163,7 @@
     return;
 
   artwork_ = image;
+  background_color_ = GetNotificationBackgroundColor(artwork_.bitmap());
   owner_->SchedulePaint();
 }
 
diff --git a/ash/media/media_notification_background.h b/ash/media/media_notification_background.h
index c412964..60858e5e 100644
--- a/ash/media/media_notification_background.h
+++ b/ash/media/media_notification_background.h
@@ -6,6 +6,7 @@
 #define ASH_MEDIA_MEDIA_NOTIFICATION_BACKGROUND_H_
 
 #include "ash/ash_export.h"
+#include "base/optional.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/background.h"
 
@@ -29,6 +30,7 @@
                               int top_radius,
                               int bottom_radius,
                               double artwork_max_width_pct);
+  ~MediaNotificationBackground() override;
 
   // views::Background
   void Paint(gfx::Canvas* canvas, views::View* view) const override;
@@ -38,6 +40,7 @@
   void UpdateArtworkMaxWidthPct(double max_width_pct);
 
  private:
+  friend class MediaNotificationBackgroundTest;
   friend class MediaNotificationViewTest;
   FRIEND_TEST_ALL_PREFIXES(MediaNotificationBackgroundTest, BoundsSanityCheck);
 
@@ -56,6 +59,8 @@
   gfx::ImageSkia artwork_;
   double artwork_max_width_pct_;
 
+  base::Optional<SkColor> background_color_;
+
   DISALLOW_COPY_AND_ASSIGN(MediaNotificationBackground);
 };
 
diff --git a/ash/media/media_notification_background_unittest.cc b/ash/media/media_notification_background_unittest.cc
index f8ee418..4025ab4 100644
--- a/ash/media/media_notification_background_unittest.cc
+++ b/ash/media/media_notification_background_unittest.cc
@@ -11,53 +11,173 @@
 
 namespace ash {
 
+namespace {
+
+gfx::ImageSkia CreateTestBackgroundImage(SkColor first_color,
+                                         SkColor second_color,
+                                         int second_height) {
+  constexpr SkColor kRightHandSideColor = SK_ColorMAGENTA;
+
+  DCHECK_NE(kRightHandSideColor, first_color);
+  DCHECK_NE(kRightHandSideColor, second_color);
+
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(100, 100);
+
+  int first_height = bitmap.height() - second_height;
+  int right_width = bitmap.width() / 2;
+
+  // Fill the right hand side of the image with a constant color. The color
+  // derivation algorithm does not look at the right hand side so we should
+  // never see |kRightHandSideColor|.
+  bitmap.erase(kRightHandSideColor,
+               {right_width, 0, bitmap.width(), bitmap.height()});
+
+  // Fill the left hand side with |first_color|.
+  bitmap.erase(first_color, {0, 0, right_width, first_height});
+
+  // Fill the left hand side with |second_color|.
+  bitmap.erase(second_color, {0, first_height, right_width, bitmap.height()});
+
+  return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+}
+
+gfx::ImageSkia CreateTestBackgroundImage(SkColor color) {
+  return CreateTestBackgroundImage(color, SK_ColorTRANSPARENT, 0);
+}
+
+}  // namespace
+
 class MediaNotificationBackgroundTest : public AshTestBase {
  public:
   MediaNotificationBackgroundTest() = default;
   ~MediaNotificationBackgroundTest() override = default;
 
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    owner_ = std::make_unique<views::StaticSizedView>();
+    background_ = std::make_unique<MediaNotificationBackground>(owner_.get(),
+                                                                10, 10, 0.1);
+
+    EXPECT_FALSE(GetBackgroundColor().has_value());
+  }
+
+  void TearDown() override {
+    background_.reset();
+    owner_.reset();
+
+    AshTestBase::TearDown();
+  }
+
+  MediaNotificationBackground* background() const { return background_.get(); }
+
+  base::Optional<SkColor> GetBackgroundColor() const {
+    return background_->background_color_;
+  }
+
  private:
+  std::unique_ptr<views::StaticSizedView> owner_;
+  std::unique_ptr<MediaNotificationBackground> background_;
+
   DISALLOW_COPY_AND_ASSIGN(MediaNotificationBackgroundTest);
 };
 
 TEST_F(MediaNotificationBackgroundTest, BoundsSanityCheck) {
-  views::StaticSizedView owner;
-  MediaNotificationBackground background(&owner, 10, 10, 0.1);
-
   // The test notification will have a width of 200 and a height of 50.
   gfx::Rect bounds(0, 0, 200, 50);
 
   // Check the artwork is not visible by default.
-  EXPECT_EQ(0, background.GetArtworkWidth(bounds.size()));
-  EXPECT_EQ(0, background.GetArtworkVisibleWidth(bounds.size()));
-  EXPECT_EQ(gfx::Rect(200, 0, 0, 50), background.GetArtworkBounds(bounds));
+  EXPECT_EQ(0, background()->GetArtworkWidth(bounds.size()));
+  EXPECT_EQ(0, background()->GetArtworkVisibleWidth(bounds.size()));
+  EXPECT_EQ(gfx::Rect(200, 0, 0, 50), background()->GetArtworkBounds(bounds));
   EXPECT_EQ(gfx::Rect(0, 0, 200, 50),
-            background.GetFilledBackgroundBounds(bounds));
-  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), background.GetGradientBounds(bounds));
+            background()->GetFilledBackgroundBounds(bounds));
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), background()->GetGradientBounds(bounds));
 
   // The background artwork image will have an aspect ratio of 2:1.
   SkBitmap bitmap;
   bitmap.allocN32Pixels(20, 10);
-  background.UpdateArtwork(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
+  bitmap.eraseColor(SK_ColorWHITE);
+  background()->UpdateArtwork(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
 
   // The artwork width will be 2x the height of the notification and the visible
   // width will be limited to 10% the width of the notification.
-  EXPECT_EQ(100, background.GetArtworkWidth(bounds.size()));
-  EXPECT_EQ(20, background.GetArtworkVisibleWidth(bounds.size()));
+  EXPECT_EQ(100, background()->GetArtworkWidth(bounds.size()));
+  EXPECT_EQ(20, background()->GetArtworkVisibleWidth(bounds.size()));
 
   // Update the visible width % to be greater than the width of the image.
-  background.UpdateArtworkMaxWidthPct(0.6);
-  EXPECT_EQ(100, background.GetArtworkVisibleWidth(bounds.size()));
+  background()->UpdateArtworkMaxWidthPct(0.6);
+  EXPECT_EQ(100, background()->GetArtworkVisibleWidth(bounds.size()));
 
   // Check the artwork is positioned to the right.
-  EXPECT_EQ(gfx::Rect(100, 0, 100, 50), background.GetArtworkBounds(bounds));
+  EXPECT_EQ(gfx::Rect(100, 0, 100, 50), background()->GetArtworkBounds(bounds));
 
   // Check the filled background is to the left of the image.
   EXPECT_EQ(gfx::Rect(0, 0, 100, 50),
-            background.GetFilledBackgroundBounds(bounds));
+            background()->GetFilledBackgroundBounds(bounds));
 
   // Check the gradient is positioned above the artwork.
-  EXPECT_EQ(gfx::Rect(100, 0, 40, 50), background.GetGradientBounds(bounds));
+  EXPECT_EQ(gfx::Rect(100, 0, 40, 50), background()->GetGradientBounds(bounds));
+}
+
+// If we have no artwork then we should use the default background color.
+TEST_F(MediaNotificationBackgroundTest, DeriveBackgroundColor_NoArtwork) {
+  background()->UpdateArtwork(gfx::ImageSkia());
+  EXPECT_FALSE(GetBackgroundColor().has_value());
+}
+
+// If we have artwork with no popular color then we should use the default
+// background color.
+TEST_F(MediaNotificationBackgroundTest, DeriveBackgroundColor_NoPopularColor) {
+  background()->UpdateArtwork(CreateTestBackgroundImage(SK_ColorTRANSPARENT));
+  EXPECT_FALSE(GetBackgroundColor().has_value());
+}
+
+// If the most popular color is not white or black then we should use that
+// color.
+TEST_F(MediaNotificationBackgroundTest,
+       DeriveBackgroundColor_PopularNonWhiteBlackColor) {
+  constexpr SkColor kTestColor = SK_ColorYELLOW;
+  background()->UpdateArtwork(CreateTestBackgroundImage(kTestColor));
+  EXPECT_EQ(kTestColor, GetBackgroundColor());
+}
+
+// MediaNotificationBackgroundBlackWhiteTest will repeat these tests with a
+// parameter that is either black or white.
+class MediaNotificationBackgroundBlackWhiteTest
+    : public MediaNotificationBackgroundTest,
+      public testing::WithParamInterface<SkColor> {};
+
+INSTANTIATE_TEST_SUITE_P(,
+                         MediaNotificationBackgroundBlackWhiteTest,
+                         testing::Values(SK_ColorBLACK, SK_ColorWHITE));
+
+// If the most popular color is black or white but there is no secondary color
+// we should use the most popular color.
+TEST_P(MediaNotificationBackgroundBlackWhiteTest,
+       DeriveBackgroundColor_PopularBlackWhiteNoSecondaryColor) {
+  background()->UpdateArtwork(CreateTestBackgroundImage(GetParam()));
+  EXPECT_EQ(GetParam(), GetBackgroundColor());
+}
+
+// If the most popular color is black or white and there is a secondary color
+// that is very minor then we should use the most popular color.
+TEST_P(MediaNotificationBackgroundBlackWhiteTest,
+       DeriveBackgroundColor_VeryPopularBlackWhite) {
+  background()->UpdateArtwork(
+      CreateTestBackgroundImage(GetParam(), SK_ColorYELLOW, 20));
+  EXPECT_EQ(GetParam(), GetBackgroundColor());
+}
+
+// If the most popular color is black or white but it is not that popular then
+// we should use the secondary color.
+TEST_P(MediaNotificationBackgroundBlackWhiteTest,
+       DeriveBackgroundColor_NotVeryPopularBlackWhite) {
+  constexpr SkColor kTestColor = SK_ColorYELLOW;
+  background()->UpdateArtwork(
+      CreateTestBackgroundImage(GetParam(), kTestColor, 40));
+  EXPECT_EQ(kTestColor, GetBackgroundColor());
 }
 
 }  // namespace ash
diff --git a/ash/media/media_notification_view_unittest.cc b/ash/media/media_notification_view_unittest.cc
index f5f1041..91ff2b0 100644
--- a/ash/media/media_notification_view_unittest.cc
+++ b/ash/media/media_notification_view_unittest.cc
@@ -687,6 +687,7 @@
 
   SkBitmap image;
   image.allocN32Pixels(10, 10);
+  image.eraseColor(SK_ColorWHITE);
 
   EXPECT_TRUE(GetArtworkImage().isNull());
 
diff --git a/ash/public/cpp/presentation_time_recorder.cc b/ash/public/cpp/presentation_time_recorder.cc
index c7949ec..4162e348 100644
--- a/ash/public/cpp/presentation_time_recorder.cc
+++ b/ash/public/cpp/presentation_time_recorder.cc
@@ -57,10 +57,8 @@
   if (!compositor_)
     return false;
 
-  if (state_ == REQUESTED) {
-    LOG(ERROR) << "Skipped";
+  if (state_ == REQUESTED)
     return false;
-  }
 
   const base::TimeTicks now = base::TimeTicks::Now();
 
diff --git a/ash/public/interfaces/assistant_controller.mojom b/ash/public/interfaces/assistant_controller.mojom
index 75ec09c..ae6eeab 100644
--- a/ash/public/interfaces/assistant_controller.mojom
+++ b/ash/public/interfaces/assistant_controller.mojom
@@ -8,6 +8,7 @@
 import "ash/public/interfaces/assistant_setup.mojom";
 import "chromeos/services/assistant/public/mojom/assistant.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
+import "mojo/public/mojom/base/time.mojom";
 
 // Interface to AssistantController which is owned by Shell in Ash. This is
 // typically used by the Assistant service to provide the controller with an
@@ -37,6 +38,47 @@
     string screenshot_png);
 };
 
+enum AssistantTimerState {
+  kUnknown,
+  // The timer is scheduled to fire at some future date.
+  kScheduled,
+  // The timer will not fire but is kept in the queue of scheduled events;
+  // it can be resumed after which it will fire in |remaining_duration_ms|.
+  kPaused,
+  // The timer has fired. In the simplest case this means the timer has
+  // begun ringing.
+  kFired,
+};
+
+struct AssistantTimer {
+  string timer_id;
+
+  // The current state of this timer.
+  AssistantTimerState state;
+
+  // TODO(llin): Add more timer data.
+};
+
+// Assistant alarm/timer event type.
+// Currently, the AlarmTimerManager maintains only one firing alarm/timer,
+// the previous one will be dismissed if the second one firing.
+enum AssistantAlarmTimerEventType {
+  kTimer
+  // TODO(llin): Add alarm event type.
+};
+
+union AlarmTimerData {
+  AssistantTimer timer_data;
+  // TODO(llin): Add alarm data.
+};
+
+// A composite struct that will hold exactly one alarm or timer.
+struct AssistantAlarmTimerEvent {
+  AssistantAlarmTimerEventType type;
+
+  AlarmTimerData? data;
+};
+
 // Interface to the AssistantAlarmTimerController which is owned by the
 // AssistantController. Currently used by the Assistant service to notify Ash
 // of changes to the underlying alarm/timer state in LibAssistant.
@@ -46,6 +88,10 @@
 
   // Invoked when a timer has finished sounding.
   OnTimerSoundingFinished();
+
+  // Invoked when an alarm/timer state changed. No alarm/timer is ringing if
+  // |event| is nullptr.
+  OnAlarmTimerStateChanged(AssistantAlarmTimerEvent? event);
 };
 
 // Interface to the AssistantNotificationController which is owned by the
diff --git a/ash/public/interfaces/media.mojom b/ash/public/interfaces/media.mojom
index 474f5a0..14866ff1 100644
--- a/ash/public/interfaces/media.mojom
+++ b/ash/public/interfaces/media.mojom
@@ -20,6 +20,10 @@
   // Sets the client interface.
   SetClient(associated MediaClient client);
 
+  // Forces media shortcut key handling in MediaClient instead of in ash. This
+  // defaults to false and will be reset if the client encounters an error.
+  SetForceMediaClientKeyHandling(bool enabled);
+
   // Called when the media capture state changes on the client, or in response
   // to a RequestCaptureState() request. Returns a map from AccountId to
   // MediaCaptureState representing every user's state.
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index 7a524a2..cf5e219 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -193,6 +193,8 @@
 
   // Returns the topmost window or one of its transient parents, if any of them
   // are in fullscreen mode.
+  // TODO(afakhry): Rename this to imply getting the fullscreen window on the
+  // currently active desk on this root.
   aura::Window* GetWindowForFullscreenMode();
 
   // If touch exploration is enabled, update the touch exploration
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 4b6ab23..1a8bd2e 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -58,6 +58,7 @@
 #include "ui/events/event_utils.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/gfx/transform_util.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/animation/bounds_animator.h"
@@ -1295,8 +1296,7 @@
         (i <= kAppListButtonIndex) ? kShelfControlSize : kShelfButtonSize;
     const int size_secondary = kShelfButtonSize;
 
-    if (i < first_visible_index_) {
-      // This happens for the overflow view.
+    if (is_overflow_mode() && i < first_visible_index_) {
       view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0));
       continue;
     }
@@ -1633,9 +1633,7 @@
   }
 
   int target_index = views::ViewModelUtils::DetermineMoveIndex(
-      *view_model_, drag_view_,
-      shelf_->IsHorizontalAlignment() ? views::ViewModelUtils::HORIZONTAL
-                                      : views::ViewModelUtils::VERTICAL,
+      *view_model_, drag_view_, shelf_->IsHorizontalAlignment(),
       drag_view_->x(), drag_view_->y());
   target_index =
       std::min(indices.second, std::max(target_index, indices.first));
@@ -2534,12 +2532,11 @@
       Shell::Get()->system_tray_model()->virtual_keyboard()->visible();
   gfx::Transform rotation;
   // Rotate the back button when virtual keyboard is visible.
-  if (virtual_keyboard_visible) {
+  if (virtual_keyboard_visible)
     rotation.Rotate(270.0);
-    rotation.Translate(-GetBackButton()->height(), 0);
-  }
   GetBackButton()->layer()->SetOpacity(IsTabletModeEnabled() ? 1.f : 0.f);
-  GetBackButton()->layer()->SetTransform(rotation);
+  GetBackButton()->layer()->SetTransform(
+      TransformAboutPivot(GetBackButton()->GetCenterPoint(), rotation));
   GetBackButton()->SetFocusBehavior(
       IsTabletModeEnabled() ? FocusBehavior::ALWAYS : FocusBehavior::NEVER);
 }
diff --git a/ash/shell.cc b/ash/shell.cc
index 6fe4d8a..5a28ef66 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -601,9 +601,9 @@
 }
 
 void Shell::NotifyFullscreenStateChanged(bool is_fullscreen,
-                                         aura::Window* root_window) {
+                                         aura::Window* container) {
   for (auto& observer : shell_observers_)
-    observer.OnFullscreenStateChanged(is_fullscreen, root_window);
+    observer.OnFullscreenStateChanged(is_fullscreen, container);
 }
 
 void Shell::NotifyPinnedStateChanged(aura::Window* pinned_window) {
diff --git a/ash/shell.h b/ash/shell.h
index f3f29391..ff0dd10 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -621,9 +621,10 @@
   // Notifies observers that split view mode has ended.
   void NotifySplitViewModeEnded();
 
-  // Notifies observers that fullscreen mode has changed for |root_window|.
+  // Notifies observers that fullscreen mode has changed for |container|.
+  // |container| is always the active desk container.
   void NotifyFullscreenStateChanged(bool is_fullscreen,
-                                    aura::Window* root_window);
+                                    aura::Window* container);
 
   // Notifies observers that |pinned_window| changed its pinned window state.
   void NotifyPinnedStateChanged(aura::Window* pinned_window);
diff --git a/ash/shell_observer.h b/ash/shell_observer.h
index 435c851..8cdfeaf 100644
--- a/ash/shell_observer.h
+++ b/ash/shell_observer.h
@@ -35,9 +35,10 @@
   // Invoked when the shelf auto-hide behavior in |root_window| is changed.
   virtual void OnShelfAutoHideBehaviorChanged(aura::Window* root_window) {}
 
-  // Invoked when entering or exiting fullscreen mode in |root_window|.
+  // Invoked when entering or exiting fullscreen mode in |container|.
+  // |container| is always the active desk container.
   virtual void OnFullscreenStateChanged(bool is_fullscreen,
-                                        aura::Window* root_window) {}
+                                        aura::Window* container) {}
 
   // Invoked when |pinned_window| enter or exit pinned mode.
   virtual void OnPinnedStateChanged(aura::Window* pinned_window) {}
diff --git a/ash/system/message_center/fullscreen_notification_blocker.cc b/ash/system/message_center/fullscreen_notification_blocker.cc
index f97441ac..2dc29a9d 100644
--- a/ash/system/message_center/fullscreen_notification_blocker.cc
+++ b/ash/system/message_center/fullscreen_notification_blocker.cc
@@ -44,7 +44,8 @@
 
 void FullscreenNotificationBlocker::OnFullscreenStateChanged(
     bool is_fullscreen,
-    aura::Window* root_window) {
+    aura::Window* container) {
+  aura::Window* root_window = container->GetRootWindow();
   if (root_window != Shell::GetRootWindowForNewWindows())
     return;
 
diff --git a/ash/system/message_center/fullscreen_notification_blocker.h b/ash/system/message_center/fullscreen_notification_blocker.h
index 36f4c72..02eddfd 100644
--- a/ash/system/message_center/fullscreen_notification_blocker.h
+++ b/ash/system/message_center/fullscreen_notification_blocker.h
@@ -27,7 +27,7 @@
  private:
   // ShellObserver:
   void OnFullscreenStateChanged(bool is_fullscreen,
-                                aura::Window* root_window) override;
+                                aura::Window* container) override;
 
   bool should_block_ = false;
 
diff --git a/ash/system/network/network_feature_pod_button.cc b/ash/system/network/network_feature_pod_button.cc
index 41b7b454..e5b2ed33 100644
--- a/ash/system/network/network_feature_pod_button.cc
+++ b/ash/system/network/network_feature_pod_button.cc
@@ -15,6 +15,7 @@
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
+#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using chromeos::NetworkConnectionHandler;
@@ -60,6 +61,72 @@
   return nullptr;
 }
 
+base::string16 GetSubLabelForConnectedNetwork(const NetworkState* network) {
+  DCHECK(network && network->IsConnectedState());
+
+  if (NetworkTypePattern::Cellular().MatchesType(network->type())) {
+    if (network->network_technology() == shill::kNetworkTechnology1Xrtt) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_ONE_X);
+    }
+    if (network->network_technology() == shill::kNetworkTechnologyGsm) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_GSM);
+    }
+    if (network->network_technology() == shill::kNetworkTechnologyGprs) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_GPRS);
+    }
+    if (network->network_technology() == shill::kNetworkTechnologyEdge) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_EDGE);
+    }
+    if (network->network_technology() == shill::kNetworkTechnologyEvdo ||
+        network->network_technology() == shill::kNetworkTechnologyUmts) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_THREE_G);
+    }
+    if (network->network_technology() == shill::kNetworkTechnologyHspa) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_HSPA);
+    }
+    if (network->network_technology() == shill::kNetworkTechnologyHspaPlus) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_HSPA_PLUS);
+    }
+    if (network->network_technology() == shill::kNetworkTechnologyLte) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_LTE);
+    }
+    if (network->network_technology() == shill::kNetworkTechnologyLteAdvanced) {
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CELLULAR_TYPE_LTE_PLUS);
+    }
+
+    // All connectivity types exposed by Shill should be covered above. However,
+    // as a fail-safe, return the default "Connected" string here to protect
+    // against Shill providing an unexpected value.
+    NOTREACHED();
+    return l10n_util::GetStringUTF16(
+        IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
+  }
+
+  switch (network_icon::GetSignalStrengthForNetwork(network)) {
+    case network_icon::SignalStrength::WEAK:
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_WEAK_SUBLABEL);
+    case network_icon::SignalStrength::MEDIUM:
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_MEDIUM_SUBLABEL);
+    case network_icon::SignalStrength::STRONG:
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_STRONG_SUBLABEL);
+    default:
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
+  }
+}
+
 }  // namespace
 
 NetworkFeaturePodButton::NetworkFeaturePodButton(
@@ -128,26 +195,7 @@
   }
 
   if (network->IsConnectedState()) {
-    switch (network_icon::GetSignalStrengthForNetwork(network)) {
-      case network_icon::SignalStrength::WEAK:
-        SetSubLabel(l10n_util::GetStringUTF16(
-            IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_WEAK_SUBLABEL));
-        break;
-      case network_icon::SignalStrength::MEDIUM:
-        SetSubLabel(l10n_util::GetStringUTF16(
-            IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_MEDIUM_SUBLABEL));
-        break;
-      case network_icon::SignalStrength::STRONG:
-        SetSubLabel(l10n_util::GetStringUTF16(
-            IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_STRONG_SUBLABEL));
-        break;
-      case network_icon::SignalStrength::NONE:
-        FALLTHROUGH;
-      case network_icon::SignalStrength::NOT_WIRELESS:
-        SetSubLabel(l10n_util::GetStringUTF16(
-            IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED));
-        break;
-    }
+    SetSubLabel(GetSubLabelForConnectedNetwork(network));
     SetTooltipState(l10n_util::GetStringFUTF16(
         IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP, network_name));
     return;
diff --git a/ash/wallpaper/wallpaper_view.cc b/ash/wallpaper/wallpaper_view.cc
index 7af3ec83..240231b 100644
--- a/ash/wallpaper/wallpaper_view.cc
+++ b/ash/wallpaper/wallpaper_view.cc
@@ -13,6 +13,7 @@
 #include "ash/wallpaper/wallpaper_controller.h"
 #include "ash/wallpaper/wallpaper_widget_controller.h"
 #include "ash/wm/overview/overview_controller.h"
+#include "ash/wm/overview/overview_utils.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "cc/paint/render_surface_filters.h"
 #include "ui/aura/window.h"
@@ -104,15 +105,56 @@
 
 }  // namespace
 
+// This event handler receives events in the pre-target phase and takes care of
+// the following:
+//   - Disabling overview mode on touch release.
+//   - Disabling overview mode on mouse release.
+class PreEventDispatchHandler : public ui::EventHandler {
+ public:
+  PreEventDispatchHandler() = default;
+  ~PreEventDispatchHandler() override = default;
+
+ private:
+  // ui::EventHandler:
+  void OnMouseEvent(ui::MouseEvent* event) override {
+    if (event->type() == ui::ET_MOUSE_RELEASED)
+      HandleClickOrTap(event);
+  }
+
+  void OnGestureEvent(ui::GestureEvent* event) override {
+    if (event->type() == ui::ET_GESTURE_TAP)
+      HandleClickOrTap(event);
+  }
+
+  void HandleClickOrTap(ui::Event* event) {
+    CHECK_EQ(ui::EP_PRETARGET, event->phase());
+    OverviewController* controller = Shell::Get()->overview_controller();
+    if (!controller->IsSelecting())
+      return;
+    // Events that happen while app list is sliding out during overview should
+    // be ignored to prevent overview from disappearing out from under the user.
+    if (!IsSlidingOutOverviewFromShelf())
+      controller->ToggleOverview();
+    event->StopPropagation();
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(PreEventDispatchHandler);
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // WallpaperView, public:
 
 WallpaperView::WallpaperView(int blur, float opacity)
-    : repaint_blur_(blur), repaint_opacity_(opacity) {
+    : repaint_blur_(blur),
+      repaint_opacity_(opacity),
+      pre_dispatch_handler_(std::make_unique<PreEventDispatchHandler>()) {
   set_context_menu_controller(this);
+  AddPreTargetHandler(pre_dispatch_handler_.get());
 }
 
-WallpaperView::~WallpaperView() = default;
+WallpaperView::~WallpaperView() {
+  RemovePreTargetHandler(pre_dispatch_handler_.get());
+}
 
 void WallpaperView::RepaintBlurAndOpacity(int repaint_blur,
                                           float repaint_opacity) {
diff --git a/ash/wallpaper/wallpaper_view.h b/ash/wallpaper/wallpaper_view.h
index dfde111..f3a45ff3 100644
--- a/ash/wallpaper/wallpaper_view.h
+++ b/ash/wallpaper/wallpaper_view.h
@@ -14,6 +14,8 @@
 
 namespace ash {
 
+class PreEventDispatchHandler;
+
 class WallpaperView : public views::View, public views::ContextMenuController {
  public:
   WallpaperView(int blur, float opacity);
@@ -51,6 +53,11 @@
   int repaint_blur_;
   float repaint_opacity_;
 
+  // A event handler that handles taps and closes overview if we are in that
+  // mode.
+  // TODO: See if we can move this logic into ash/wm/overview.
+  std::unique_ptr<PreEventDispatchHandler> pre_dispatch_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(WallpaperView);
 };
 
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 838072b..74e6dce1 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -327,40 +327,6 @@
   bool IsLabelVisible() const { return label_container_->visible(); }
 
  private:
-  // ui::EventHandler:
-  void OnMouseEvent(ui::MouseEvent* event) override {
-    if (event->type() == ui::ET_MOUSE_PRESSED) {
-      // In order to receive subsequent mouse release events in this view, we
-      // must mark the event as handled in this view.
-      event->SetHandled();
-      return;
-    }
-
-    HandleClickReleaseOrTap(event);
-  }
-
-  void OnGestureEvent(ui::GestureEvent* event) override {
-    HandleClickReleaseOrTap(event);
-  }
-
-  void HandleClickReleaseOrTap(ui::Event* event) {
-    if (event->type() != ui::ET_MOUSE_RELEASED &&
-        event->type() != ui::ET_GESTURE_TAP) {
-      return;
-    }
-
-    OverviewController* controller = Shell::Get()->overview_controller();
-    if (!controller->IsSelecting())
-      return;
-
-    // Events that happen while app list is sliding out during overview should
-    // be ignored to prevent overview from disappearing out from under the user.
-    if (!IsSlidingOutOverviewFromShelf())
-      controller->ToggleOverview();
-
-    event->StopPropagation();
-  }
-
   // Owned by views heirarchy.
   RoundedRectView* label_container_ = nullptr;
   views::Label* label_ = nullptr;
@@ -1409,7 +1375,7 @@
   shield_widget_ = CreateBackgroundWidget(
       root_window_, ui::LAYER_NOT_DRAWN, SK_ColorTRANSPARENT, 0, 0,
       SK_ColorTRANSPARENT, initial_opacity, /*parent=*/nullptr,
-      /*stack_on_top=*/true, /*accept_events=*/true);
+      /*stack_on_top=*/true, /*accept_events=*/false);
   aura::Window* widget_window = shield_widget_->GetNativeWindow();
   aura::Window* parent_window = widget_window->parent();
   const gfx::Rect bounds = ash::screen_util::SnapBoundsToDisplayEdge(
diff --git a/ash/wm/splitview/split_view_drag_indicators.cc b/ash/wm/splitview/split_view_drag_indicators.cc
index 47c4987..979a3c9 100644
--- a/ash/wm/splitview/split_view_drag_indicators.cc
+++ b/ash/wm/splitview/split_view_drag_indicators.cc
@@ -479,6 +479,15 @@
     right_rotated_view_->OnBoundsUpdated(right_rotated_bounds,
                                          /*angle=*/-left_rotation_angle);
 
+    // Avoid animating label transforms in a case where each label might have
+    // zero opacity and could start fading in if the indicator state changes.
+    // https://crbug.com/946683
+    if (indicator_state_ == IndicatorState::kNone) {
+      left_rotated_view_->layer()->SetTransform(gfx::Transform());
+      right_rotated_view_->layer()->SetTransform(gfx::Transform());
+      return;
+    }
+
     // Compute the transform for the labels. The labels slide in and out when
     // moving between states.
     gfx::Transform main_rotated_transform, other_rotated_transform;
diff --git a/ash/wm/video_detector.cc b/ash/wm/video_detector.cc
index 8e9c1728..edfd63e 100644
--- a/ash/wm/video_detector.cc
+++ b/ash/wm/video_detector.cc
@@ -56,9 +56,9 @@
 }
 
 void VideoDetector::OnWindowDestroying(aura::Window* window) {
-  if (fullscreen_root_windows_.count(window)) {
+  if (fullscreen_desks_containers_.count(window)) {
     window_observer_manager_.Remove(window);
-    fullscreen_root_windows_.erase(window);
+    fullscreen_desks_containers_.erase(window);
     UpdateState();
   }
 }
@@ -74,15 +74,17 @@
 }
 
 void VideoDetector::OnFullscreenStateChanged(bool is_fullscreen,
-                                             aura::Window* root_window) {
-  if (is_fullscreen && !fullscreen_root_windows_.count(root_window)) {
-    fullscreen_root_windows_.insert(root_window);
-    if (!window_observer_manager_.IsObserving(root_window))
-      window_observer_manager_.Add(root_window);
+                                             aura::Window* container) {
+  const bool has_fullscreen_in_container =
+      fullscreen_desks_containers_.count(container);
+  if (is_fullscreen && !has_fullscreen_in_container) {
+    fullscreen_desks_containers_.insert(container);
+    if (!window_observer_manager_.IsObserving(container))
+      window_observer_manager_.Add(container);
     UpdateState();
-  } else if (!is_fullscreen && fullscreen_root_windows_.count(root_window)) {
-    fullscreen_root_windows_.erase(root_window);
-    window_observer_manager_.Remove(root_window);
+  } else if (!is_fullscreen && has_fullscreen_in_container) {
+    fullscreen_desks_containers_.erase(container);
+    window_observer_manager_.Remove(container);
     UpdateState();
   }
 }
@@ -90,8 +92,9 @@
 void VideoDetector::UpdateState() {
   State new_state = State::NOT_PLAYING;
   if (video_is_playing_) {
-    new_state = fullscreen_root_windows_.empty() ? State::PLAYING_WINDOWED
-                                                 : State::PLAYING_FULLSCREEN;
+    new_state = fullscreen_desks_containers_.empty()
+                    ? State::PLAYING_WINDOWED
+                    : State::PLAYING_FULLSCREEN;
   }
 
   if (state_ != new_state) {
diff --git a/ash/wm/video_detector.h b/ash/wm/video_detector.h
index b4179ab..1a2bcf4 100644
--- a/ash/wm/video_detector.h
+++ b/ash/wm/video_detector.h
@@ -79,7 +79,7 @@
 
   // ShellObserver overrides.
   void OnFullscreenStateChanged(bool is_fullscreen,
-                                aura::Window* root_window) override;
+                                aura::Window* container) override;
 
   // viz::mojom::VideoDetectorObserver implementation.
   void OnVideoActivityStarted() override;
@@ -102,8 +102,8 @@
   // True if video has been observed in the last |kVideoTimeoutMs|.
   bool video_is_playing_;
 
-  // Currently-fullscreen root windows.
-  std::set<aura::Window*> fullscreen_root_windows_;
+  // Currently-fullscreen desks containers windows.
+  std::set<aura::Window*> fullscreen_desks_containers_;
 
   base::ObserverList<Observer>::Unchecked observers_;
 
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index d5ab367..a658d5d72 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -398,13 +398,23 @@
 //////////////////////////////////////////////////////////////////////////////
 // WorkspaceLayoutManager, ShellObserver implementation:
 
-void WorkspaceLayoutManager::OnFullscreenStateChanged(
-    bool is_fullscreen,
-    aura::Window* root_window) {
-  if (root_window != root_window_ || is_fullscreen_ == is_fullscreen)
+void WorkspaceLayoutManager::OnFullscreenStateChanged(bool is_fullscreen,
+                                                      aura::Window* container) {
+  // Note that only the active desk's container broadcasts this event, but all
+  // containers' workspaces (active desk's and inactive desks' as well the
+  // always-on-top container) receive it.
+  // TODO(afakhry): dcheck that |container| is always the active desk container.
+
+  // If |container| is the one associated with this workspace, then fullscreen
+  // state must match.
+  DCHECK(window_ != container || is_fullscreen == is_fullscreen_);
+
+  // This notification may come from active desk containers on other displays.
+  // No need to update the always-on-top states if the fullscreen state change
+  // happened on a different root window.
+  if (container->GetRootWindow() != root_window_)
     return;
 
-  is_fullscreen_ = is_fullscreen;
   if (Shell::Get()->screen_pinning_controller()->IsPinned()) {
     // If this is in pinned mode, then this event does not trigger the
     // always-on-top state change, because it is kept disabled regardless of
@@ -412,8 +422,14 @@
     return;
   }
 
-  UpdateAlwaysOnTop(is_fullscreen_ ? wm::GetWindowForFullscreenMode(window_)
-                                   : nullptr);
+  // We need to update the always-on-top states even for inactive desks
+  // containers, because inactive desks may have a previously demoted
+  // always-on-top windows that we need to promote back to the always-on-top
+  // container if there no longer fullscreen windows on this root window.
+
+  // TODO(afakhry): Use a function that gets the fullscreen window in the entire
+  // root window instead of GetWindowForFullscreenMode() below.
+  UpdateAlwaysOnTop(wm::GetWindowForFullscreenMode(window_));
 }
 
 void WorkspaceLayoutManager::OnPinnedStateChanged(aura::Window* pinned_window) {
@@ -467,21 +483,25 @@
 }
 
 void WorkspaceLayoutManager::UpdateFullscreenState() {
-  // TODO(flackr): The fullscreen state is currently tracked per workspace
-  // but the shell notification implies a per root window state. Currently
-  // only windows in the default workspace container will go fullscreen but
-  // this should really be tracked by the RootWindowController since
-  // technically any container could get a fullscreen window.
+  // Note that we don't allow always-on-top or PiP containers to have fullscreen
+  // windows, and we only update the fullscreen state for the active desk
+  // container.
+  // TODO(afakhry): Change this to check if this is the active desk container.
   if (window_->id() != kShellWindowId_DefaultContainer)
     return;
-  bool is_fullscreen = wm::GetWindowForFullscreenMode(window_) != nullptr;
-  if (is_fullscreen != is_fullscreen_) {
-    Shell::Get()->NotifyFullscreenStateChanged(is_fullscreen, root_window_);
-    is_fullscreen_ = is_fullscreen;
-  }
+
+  // TODO(afakhry): Use a function that gets the fullscreen window in |window_|
+  // only instead of GetWindowForFullscreenMode() below.
+  const bool is_fullscreen = wm::GetWindowForFullscreenMode(window_) != nullptr;
+  if (is_fullscreen == is_fullscreen_)
+    return;
+
+  is_fullscreen_ = is_fullscreen;
+  Shell::Get()->NotifyFullscreenStateChanged(is_fullscreen, window_);
 }
 
-void WorkspaceLayoutManager::UpdateAlwaysOnTop(aura::Window* window_on_top) {
+void WorkspaceLayoutManager::UpdateAlwaysOnTop(
+    aura::Window* active_desk_fullscreen_window) {
   // Changing always on top state may change window's parent. Iterate on a copy
   // of |windows_| to avoid invalidating an iterator. Since both workspace and
   // always_on_top containers' layouts are managed by this class all the
@@ -489,8 +509,8 @@
   WindowSet windows(windows_);
   for (aura::Window* window : windows) {
     wm::WindowState* window_state = wm::GetWindowState(window);
-    if (window_on_top)
-      window_state->DisableAlwaysOnTop(window_on_top);
+    if (active_desk_fullscreen_window)
+      window_state->DisableAlwaysOnTop(active_desk_fullscreen_window);
     else
       window_state->RestoreAlwaysOnTop();
   }
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h
index 11c838e..d39b5b6 100644
--- a/ash/wm/workspace/workspace_layout_manager.h
+++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -102,7 +102,7 @@
 
   // ShellObserver:
   void OnFullscreenStateChanged(bool is_fullscreen,
-                                aura::Window* root_window) override;
+                                aura::Window* container) override;
   void OnPinnedStateChanged(aura::Window* pinned_window) override;
 
   // ShelfObserver:
@@ -159,7 +159,7 @@
 
   // Updates the always-on-top state for windows managed by this layout
   // manager.
-  void UpdateAlwaysOnTop(aura::Window* window_on_top);
+  void UpdateAlwaysOnTop(aura::Window* active_desk_fullscreen_window);
 
   // Notifies windows about a change in a system ui area. This could be
   // the keyboard or any window in the SettingsBubbleContainer. Windows will
@@ -179,7 +179,13 @@
   // The work area in the coordinates of |window_|.
   gfx::Rect work_area_in_parent_;
 
-  // True if this workspace is currently in fullscreen mode.
+  // True if this workspace is currently in fullscreen mode. Tracks the
+  // fullscreen state of the container |window_| associated with this workspace
+  // rather than the root window.
+  // Note that in the case of a workspace of a PiP or always-on-top containers,
+  // |is_fullscreen_| doesn't make sense since we don't allow windows on those
+  // containers to go fullscreen. Hence, |is_fullscreen_| is always false on
+  // those workspaces.
   bool is_fullscreen_;
 
   // A window which covers the full container and which gets inserted behind the
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 1b1307b4..2fc488f9 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -105,7 +105,7 @@
   ~TestShellObserver() override { Shell::Get()->RemoveShellObserver(this); }
 
   void OnFullscreenStateChanged(bool is_fullscreen,
-                                aura::Window* root_window) override {
+                                aura::Window* container) override {
     call_count_++;
     is_fullscreen_ = is_fullscreen;
   }
diff --git a/base/BUILD.gn b/base/BUILD.gn
index be6e5b4..c2db5856 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1392,7 +1392,7 @@
 
     deps += [
       ":base_jni_headers",
-      "//third_party/android_tools:cpu_features",
+      "//third_party/android_sdk:cpu_features",
       "//third_party/ashmem",
     ]
 
@@ -3202,12 +3202,12 @@
       "//testing/android/reporter:reporter_java",
       "//third_party/android_deps:com_android_support_support_annotations_java",
       "//third_party/android_deps:com_android_support_support_compat_java",
+      "//third_party/android_sdk:android_support_chromium_java",
+      "//third_party/android_sdk:android_test_base_java",
+      "//third_party/android_sdk:android_test_mock_java",
       "//third_party/android_support_test_runner:exposed_instrumentation_api_publish_java",
       "//third_party/android_support_test_runner:rules_java",
       "//third_party/android_support_test_runner:runner_java",
-      "//third_party/android_tools:android_support_chromium_java",
-      "//third_party/android_tools:android_test_base_java",
-      "//third_party/android_tools:android_test_mock_java",
       "//third_party/hamcrest:hamcrest_core_java",
       "//third_party/junit",
       "//third_party/ub-uiautomator:ub_uiautomator_java",
diff --git a/base/debug/elf_reader.cc b/base/debug/elf_reader.cc
index 7cd00c6..3af4ced 100644
--- a/base/debug/elf_reader.cc
+++ b/base/debug/elf_reader.cc
@@ -9,7 +9,7 @@
 
 #include "base/bits.h"
 #include "base/containers/span.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/strings/safe_sprintf.h"
 #include "build/build_config.h"
 
diff --git a/base/debug/elf_reader.h b/base/debug/elf_reader.h
index 8e0f48e6..e0bec9d 100644
--- a/base/debug/elf_reader.h
+++ b/base/debug/elf_reader.h
@@ -9,8 +9,8 @@
 
 #include "base/base_export.h"
 #include "base/containers/span.h"
+#include "base/hash/sha1.h"
 #include "base/optional.h"
-#include "base/sha1.h"
 #include "base/strings/string_piece.h"
 
 // Functions for querying metadata from ELF binaries.
diff --git a/base/files/file_path.h b/base/files/file_path.h
index 1447482e..e99bdeb 100644
--- a/base/files/file_path.h
+++ b/base/files/file_path.h
@@ -104,6 +104,7 @@
 
 #include <stddef.h>
 
+#include <functional>
 #include <iosfwd>
 #include <string>
 #include <vector>
diff --git a/base/json/json_perftest.cc b/base/json/json_perftest.cc
index 309913ca..d58f034 100644
--- a/base/json/json_perftest.cc
+++ b/base/json/json_perftest.cc
@@ -18,10 +18,10 @@
 // list.
 std::unique_ptr<DictionaryValue> GenerateDict() {
   auto root = std::make_unique<DictionaryValue>();
-  root->SetDouble("Double", 3.141);
-  root->SetBoolean("Bool", true);
-  root->SetInteger("Int", 42);
-  root->SetString("String", "Foo");
+  root->SetDoubleKey("Double", 3.141);
+  root->SetBoolKey("Bool", true);
+  root->SetIntKey("Int", 42);
+  root->SetStringKey("String", "Foo");
 
   auto list = std::make_unique<ListValue>();
   list->Set(0, std::make_unique<Value>(2.718));
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
index 2d81af3..cfe0f60 100644
--- a/base/json/json_writer_unittest.cc
+++ b/base/json/json_writer_unittest.cc
@@ -59,7 +59,7 @@
   DictionaryValue root_dict;
   std::unique_ptr<ListValue> list(new ListValue());
   std::unique_ptr<DictionaryValue> inner_dict(new DictionaryValue());
-  inner_dict->SetInteger("inner int", 10);
+  inner_dict->SetIntKey("inner int", 10);
   list->Append(std::move(inner_dict));
   list->Append(std::make_unique<ListValue>());
   list->AppendBoolean(true);
@@ -91,17 +91,17 @@
   std::string output_js;
 
   DictionaryValue period_dict;
-  period_dict.SetKey("a.b", base::Value(3));
-  period_dict.SetKey("c", base::Value(2));
+  period_dict.SetIntKey("a.b", 3);
+  period_dict.SetIntKey("c", 2);
   std::unique_ptr<DictionaryValue> period_dict2(new DictionaryValue());
-  period_dict2->SetKey("g.h.i.j", base::Value(1));
+  period_dict2->SetIntKey("g.h.i.j", 1);
   period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
   EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js));
   EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
 
   DictionaryValue period_dict3;
   period_dict3.SetInteger("a.b", 2);
-  period_dict3.SetKey("a.b", base::Value(1));
+  period_dict3.SetIntKey("a.b", 1);
   EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js));
   EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
 }
@@ -130,9 +130,9 @@
 
   DictionaryValue binary_dict;
   binary_dict.Set("a", Value::CreateWithCopiedBuffer("asdf", 4));
-  binary_dict.SetInteger("b", 5);
+  binary_dict.SetIntKey("b", 5);
   binary_dict.Set("c", Value::CreateWithCopiedBuffer("asdf", 4));
-  binary_dict.SetInteger("d", 2);
+  binary_dict.SetIntKey("d", 2);
   binary_dict.Set("e", Value::CreateWithCopiedBuffer("asdf", 4));
   EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js));
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
diff --git a/base/location.h b/base/location.h
index 14fe2fa6b..491cdda 100644
--- a/base/location.h
+++ b/base/location.h
@@ -8,11 +8,12 @@
 #include <stddef.h>
 
 #include <cassert>
+#include <functional>
 #include <string>
 
 #include "base/base_export.h"
 #include "base/debug/debugging_buildflags.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 
 namespace base {
 
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h
index 10495bd..bd97f11b 100644
--- a/base/memory/shared_memory.h
+++ b/base/memory/shared_memory.h
@@ -10,7 +10,7 @@
 #include <string>
 
 #include "base/base_export.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/memory/shared_memory_handle.h"
 #include "base/process/process_handle.h"
@@ -65,6 +65,9 @@
 // SharedMemory consumes a SharedMemoryHandle [potentially one that it created]
 // to map a shared memory OS resource into the virtual address space of the
 // current process.
+//
+// DEPRECATED - Use {Writable,ReadOnly}SharedMemoryRegion instead.
+// http://crbug.com/795291
 class BASE_EXPORT SharedMemory {
  public:
   SharedMemory();
diff --git a/base/memory/shared_memory_handle.h b/base/memory/shared_memory_handle.h
index 9d854a7..4f1fcec 100644
--- a/base/memory/shared_memory_handle.h
+++ b/base/memory/shared_memory_handle.h
@@ -33,6 +33,9 @@
 // address space of the current process.
 // TODO(erikchen): This class should have strong ownership semantics to prevent
 // leaks of the underlying OS resource. https://crbug.com/640840.
+//
+// DEPRECATED - Use {Writable,ReadOnly}SharedMemoryRegion instead.
+// http://crbug.com/795291
 class BASE_EXPORT SharedMemoryHandle {
  public:
   // The default constructor returns an invalid SharedMemoryHandle.
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index e514014f..378fc44d 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -810,9 +810,9 @@
 
 void Histogram::GetParameters(DictionaryValue* params) const {
   params->SetString("type", HistogramTypeToString(GetHistogramType()));
-  params->SetInteger("min", declared_min());
-  params->SetInteger("max", declared_max());
-  params->SetInteger("bucket_count", static_cast<int>(bucket_count()));
+  params->SetIntKey("min", declared_min());
+  params->SetIntKey("max", declared_max());
+  params->SetIntKey("bucket_count", static_cast<int>(bucket_count()));
 }
 
 void Histogram::GetCountAndBucketData(Count* count,
@@ -826,10 +826,10 @@
     Sample count_at_index = snapshot->GetCountAtIndex(i);
     if (count_at_index > 0) {
       std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue());
-      bucket_value->SetInteger("low", ranges(i));
+      bucket_value->SetIntKey("low", ranges(i));
       if (i != bucket_count() - 1)
-        bucket_value->SetInteger("high", ranges(i + 1));
-      bucket_value->SetInteger("count", count_at_index);
+        bucket_value->SetIntKey("high", ranges(i + 1));
+      bucket_value->SetIntKey("count", count_at_index);
       buckets->Set(index, std::move(bucket_value));
       ++index;
     }
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
index 990d9f5..deaa36e 100644
--- a/base/metrics/histogram_base.cc
+++ b/base/metrics/histogram_base.cc
@@ -152,14 +152,14 @@
 
   JSONStringValueSerializer serializer(output);
   DictionaryValue root;
-  root.SetString("name", histogram_name());
-  root.SetInteger("count", count);
-  root.SetDouble("sum", static_cast<double>(sum));
-  root.SetInteger("flags", flags());
+  root.SetStringKey("name", histogram_name());
+  root.SetIntKey("count", count);
+  root.SetDoubleKey("sum", static_cast<double>(sum));
+  root.SetIntKey("flags", flags());
   root.Set("params", std::move(parameters));
   if (verbosity_level != JSON_VERBOSITY_LEVEL_OMIT_BUCKETS)
     root.Set("buckets", std::move(buckets));
-  root.SetInteger("pid", GetUniqueIdForProcess());
+  root.SetIntKey("pid", GetUniqueIdForProcess());
   serializer.Serialize(root);
 }
 
diff --git a/base/metrics/metrics_hashes.cc b/base/metrics/metrics_hashes.cc
index 5672b06d..ef7072a 100644
--- a/base/metrics/metrics_hashes.cc
+++ b/base/metrics/metrics_hashes.cc
@@ -4,8 +4,8 @@
 
 #include "base/metrics/metrics_hashes.h"
 
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/sys_byteorder.h"
 
 namespace base {
diff --git a/base/pending_task.h b/base/pending_task.h
index a609a910..c3df29d 100644
--- a/base/pending_task.h
+++ b/base/pending_task.h
@@ -16,7 +16,7 @@
 
 namespace base {
 
-enum class Nestable {
+enum class Nestable : uint8_t {
   kNonNestable,
   kNestable,
 };
@@ -57,11 +57,12 @@
   // Chain of symbols of the parent tasks which led to this one being posted.
   static constexpr size_t kTaskBacktraceLength = 4;
   std::array<const void*, kTaskBacktraceLength> task_backtrace = {};
-  bool task_backtrace_overflow = false;
 
   // Secondary sort key for run time.
   int sequence_num = 0;
 
+  bool task_backtrace_overflow = false;
+
   // OK to dispatch from a nested loop.
   Nestable nestable;
 
diff --git a/base/process/process_metrics.cc b/base/process/process_metrics.cc
index bc843a4..d53c086 100644
--- a/base/process/process_metrics.cc
+++ b/base/process/process_metrics.cc
@@ -74,7 +74,7 @@
 std::unique_ptr<Value> SystemMetrics::ToValue() const {
   std::unique_ptr<DictionaryValue> res(new DictionaryValue());
 
-  res->SetInteger("committed_memory", static_cast<int>(committed_memory_));
+  res->SetIntKey("committed_memory", static_cast<int>(committed_memory_));
 #if defined(OS_LINUX) || defined(OS_ANDROID)
   std::unique_ptr<DictionaryValue> meminfo = memory_info_.ToValue();
   std::unique_ptr<DictionaryValue> vmstat = vmstat_info_.ToValue();
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
index 16cde35..0c119bd 100644
--- a/base/process/process_metrics_linux.cc
+++ b/base/process/process_metrics_linux.cc
@@ -470,25 +470,25 @@
 
 std::unique_ptr<DictionaryValue> SystemMemoryInfoKB::ToValue() const {
   auto res = std::make_unique<DictionaryValue>();
-  res->SetInteger("total", total);
-  res->SetInteger("free", free);
-  res->SetInteger("available", available);
-  res->SetInteger("buffers", buffers);
-  res->SetInteger("cached", cached);
-  res->SetInteger("active_anon", active_anon);
-  res->SetInteger("inactive_anon", inactive_anon);
-  res->SetInteger("active_file", active_file);
-  res->SetInteger("inactive_file", inactive_file);
-  res->SetInteger("swap_total", swap_total);
-  res->SetInteger("swap_free", swap_free);
-  res->SetInteger("swap_used", swap_total - swap_free);
-  res->SetInteger("dirty", dirty);
-  res->SetInteger("reclaimable", reclaimable);
+  res->SetIntKey("total", total);
+  res->SetIntKey("free", free);
+  res->SetIntKey("available", available);
+  res->SetIntKey("buffers", buffers);
+  res->SetIntKey("cached", cached);
+  res->SetIntKey("active_anon", active_anon);
+  res->SetIntKey("inactive_anon", inactive_anon);
+  res->SetIntKey("active_file", active_file);
+  res->SetIntKey("inactive_file", inactive_file);
+  res->SetIntKey("swap_total", swap_total);
+  res->SetIntKey("swap_free", swap_free);
+  res->SetIntKey("swap_used", swap_total - swap_free);
+  res->SetIntKey("dirty", dirty);
+  res->SetIntKey("reclaimable", reclaimable);
 #ifdef OS_CHROMEOS
-  res->SetInteger("shmem", shmem);
-  res->SetInteger("slab", slab);
-  res->SetInteger("gem_objects", gem_objects);
-  res->SetInteger("gem_size", gem_size);
+  res->SetIntKey("shmem", shmem);
+  res->SetIntKey("slab", slab);
+  res->SetIntKey("gem_objects", gem_objects);
+  res->SetIntKey("gem_size", gem_size);
 #endif
 
   return res;
@@ -635,9 +635,9 @@
 
 std::unique_ptr<DictionaryValue> VmStatInfo::ToValue() const {
   auto res = std::make_unique<DictionaryValue>();
-  res->SetInteger("pswpin", pswpin);
-  res->SetInteger("pswpout", pswpout);
-  res->SetInteger("pgmajfault", pgmajfault);
+  res->SetIntKey("pswpin", pswpin);
+  res->SetIntKey("pswpout", pswpout);
+  res->SetIntKey("pgmajfault", pgmajfault);
   return res;
 }
 
diff --git a/base/task/sequence_manager/task_queue.cc b/base/task/sequence_manager/task_queue.cc
index faf894e..7ad8d40 100644
--- a/base/task/sequence_manager/task_queue.cc
+++ b/base/task/sequence_manager/task_queue.cc
@@ -174,7 +174,7 @@
 }
 
 scoped_refptr<SingleThreadTaskRunner> TaskQueue::CreateTaskRunner(
-    int task_type) {
+    TaskType task_type) {
   // We only need to lock if we're not on the main thread.
   base::internal::AutoSchedulerLockMaybe lock(IsOnMainThread() ? &impl_lock_
                                                                : nullptr);
diff --git a/base/task/sequence_manager/task_queue.h b/base/task/sequence_manager/task_queue.h
index c54f6c04..62cf3e8 100644
--- a/base/task/sequence_manager/task_queue.h
+++ b/base/task/sequence_manager/task_queue.h
@@ -316,7 +316,7 @@
   // NOTE: Task runners don't hold a reference to a TaskQueue, hence,
   // it's required to retain that reference to prevent automatic graceful
   // shutdown. Unique ownership of task queues will fix this issue soon.
-  scoped_refptr<SingleThreadTaskRunner> CreateTaskRunner(int task_type);
+  scoped_refptr<SingleThreadTaskRunner> CreateTaskRunner(TaskType task_type);
 
   // Default task runner which doesn't annotate tasks with a task type.
   scoped_refptr<SingleThreadTaskRunner> task_runner() const {
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc
index 482e744..314fd48 100644
--- a/base/task/sequence_manager/task_queue_impl.cc
+++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -60,7 +60,7 @@
 TaskQueueImpl::TaskRunner::TaskRunner(
     scoped_refptr<GuardedTaskPoster> task_poster,
     scoped_refptr<AssociatedThreadId> associated_thread,
-    int task_type)
+    TaskType task_type)
     : task_poster_(std::move(task_poster)),
       associated_thread_(std::move(associated_thread)),
       task_type_(task_type) {}
@@ -143,7 +143,7 @@
 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() = default;
 
 scoped_refptr<SingleThreadTaskRunner> TaskQueueImpl::CreateTaskRunner(
-    int task_type) const {
+    TaskType task_type) const {
   return MakeRefCounted<TaskRunner>(task_poster_, associated_thread_,
                                     task_type);
 }
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h
index c759083..9a7f77f 100644
--- a/base/task/sequence_manager/task_queue_impl.h
+++ b/base/task/sequence_manager/task_queue_impl.h
@@ -96,7 +96,8 @@
       RepeatingCallback<void(const Task&, const TaskQueue::TaskTiming&)>;
 
   // May be called from any thread.
-  scoped_refptr<SingleThreadTaskRunner> CreateTaskRunner(int task_type) const;
+  scoped_refptr<SingleThreadTaskRunner> CreateTaskRunner(
+      TaskType task_type) const;
 
   // TaskQueue implementation.
   const char* GetName() const;
@@ -262,7 +263,7 @@
    public:
     explicit TaskRunner(scoped_refptr<GuardedTaskPoster> task_poster,
                         scoped_refptr<AssociatedThreadId> associated_thread,
-                        int task_type);
+                        TaskType task_type);
 
     bool PostDelayedTask(const Location& location,
                          OnceClosure callback,
@@ -279,7 +280,7 @@
 
     const scoped_refptr<GuardedTaskPoster> task_poster_;
     const scoped_refptr<AssociatedThreadId> associated_thread_;
-    const int task_type_;
+    const TaskType task_type_;
   };
 
   // A queue for holding delayed tasks before their delay has expired.
diff --git a/base/task/sequence_manager/tasks.cc b/base/task/sequence_manager/tasks.cc
index f5eae81..1006762 100644
--- a/base/task/sequence_manager/tasks.cc
+++ b/base/task/sequence_manager/tasks.cc
@@ -34,7 +34,7 @@
                        Location location,
                        TimeDelta delay,
                        Nestable nestable,
-                       int task_type)
+                       TaskType task_type)
     : callback(std::move(callback)),
       location(location),
       delay(delay),
diff --git a/base/task/sequence_manager/tasks.h b/base/task/sequence_manager/tasks.h
index 1e981a6..a261969 100644
--- a/base/task/sequence_manager/tasks.h
+++ b/base/task/sequence_manager/tasks.h
@@ -11,7 +11,8 @@
 namespace base {
 namespace sequence_manager {
 
-constexpr int kTaskTypeNone = 0;
+using TaskType = uint8_t;
+constexpr TaskType kTaskTypeNone = 0;
 
 namespace internal {
 
@@ -24,7 +25,7 @@
                       Location location = Location(),
                       TimeDelta delay = TimeDelta(),
                       Nestable nestable = Nestable::kNestable,
-                      int task_type = kTaskTypeNone);
+                      TaskType task_type = kTaskTypeNone);
   PostedTask(PostedTask&& move_from) noexcept;
   ~PostedTask();
 
@@ -32,7 +33,7 @@
   Location location;
   TimeDelta delay;
   Nestable nestable;
-  int task_type;
+  TaskType task_type;
   // The time at which the task was queued.
   TimeTicks queue_time;
 
@@ -94,7 +95,7 @@
 
   bool enqueue_order_set() const { return enqueue_order_; }
 
-  int task_type;
+  TaskType task_type;
 
  private:
   // Similar to |sequence_num|, but ultimately the |enqueue_order| is what
diff --git a/base/task/sequence_manager/test/fake_task.cc b/base/task/sequence_manager/test/fake_task.cc
index 6fb40d7..ba0e6d6 100644
--- a/base/task/sequence_manager/test/fake_task.cc
+++ b/base/task/sequence_manager/test/fake_task.cc
@@ -9,7 +9,7 @@
 
 FakeTask::FakeTask() : FakeTask(0 /* task_type */) {}
 
-FakeTask::FakeTask(int task_type)
+FakeTask::FakeTask(TaskType task_type)
     : Task(internal::PostedTask(OnceClosure(),
                                 FROM_HERE,
                                 TimeDelta(),
diff --git a/base/task/sequence_manager/test/fake_task.h b/base/task/sequence_manager/test/fake_task.h
index 6de56a6c..134e2da 100644
--- a/base/task/sequence_manager/test/fake_task.h
+++ b/base/task/sequence_manager/test/fake_task.h
@@ -14,7 +14,7 @@
 class FakeTask : public Task {
  public:
   FakeTask();
-  explicit FakeTask(int task_type);
+  explicit FakeTask(TaskType task_type);
 };
 
 class FakeTaskTiming : public TaskQueue::TaskTiming {
diff --git a/base/task/task_scheduler/task_tracker.cc b/base/task/task_scheduler/task_tracker.cc
index 3629c56..921aafa 100644
--- a/base/task/task_scheduler/task_tracker.cc
+++ b/base/task/task_scheduler/task_tracker.cc
@@ -64,11 +64,11 @@
 void TaskTracingInfo::AppendAsTraceFormat(std::string* out) const {
   DictionaryValue dict;
 
-  dict.SetString("task_priority",
-                 base::TaskPriorityToString(task_traits_.priority()));
-  dict.SetString("execution_mode", execution_mode_);
+  dict.SetStringKey("task_priority",
+                    base::TaskPriorityToString(task_traits_.priority()));
+  dict.SetStringKey("execution_mode", execution_mode_);
   if (sequence_token_.IsValid())
-    dict.SetInteger("sequence_token", sequence_token_.ToInternalValue());
+    dict.SetIntKey("sequence_token", sequence_token_.ToInternalValue());
 
   std::string tmp;
   JSONWriter::Write(dict, &tmp);
diff --git a/base/test/gtest_util.cc b/base/test/gtest_util.cc
index d483d2df..5eeda39 100644
--- a/base/test/gtest_util.cc
+++ b/base/test/gtest_util.cc
@@ -56,10 +56,10 @@
   ListValue root;
   for (const auto& i : tests) {
     std::unique_ptr<DictionaryValue> test_info(new DictionaryValue);
-    test_info->SetString("test_case_name", i.test_case_name);
-    test_info->SetString("test_name", i.test_name);
-    test_info->SetString("file", i.file);
-    test_info->SetInteger("line", i.line);
+    test_info->SetStringKey("test_case_name", i.test_case_name);
+    test_info->SetStringKey("test_name", i.test_name);
+    test_info->SetStringKey("file", i.file);
+    test_info->SetIntKey("line", i.line);
     root.Append(std::move(test_info));
   }
 
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index ccecde3..ecf1f45 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -19,7 +19,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/format_macros.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
diff --git a/base/test/launcher/test_launcher_tracer.cc b/base/test/launcher/test_launcher_tracer.cc
index d525df752..26fbf00 100644
--- a/base/test/launcher/test_launcher_tracer.cc
+++ b/base/test/launcher/test_launcher_tracer.cc
@@ -37,11 +37,11 @@
     json_event->SetString("ph", "X");
     json_event->SetInteger(
         "ts", (event.timestamp - trace_start_time_).InMicroseconds());
-    json_event->SetInteger("dur", event.duration.InMicroseconds());
-    json_event->SetInteger("tid", event.thread_id);
+    json_event->SetIntKey("dur", event.duration.InMicroseconds());
+    json_event->SetIntKey("tid", event.thread_id);
 
     // Add fake values required by the trace viewer.
-    json_event->SetInteger("pid", 0);
+    json_event->SetIntKey("pid", 0);
 
     json_events->Append(std::move(json_event));
   }
diff --git a/base/test/launcher/test_results_tracker.cc b/base/test/launcher/test_results_tracker.cc
index b2a06be..9d7c658 100644
--- a/base/test/launcher/test_results_tracker.cc
+++ b/base/test/launcher/test_results_tracker.cc
@@ -404,7 +404,7 @@
 
         std::unique_ptr<DictionaryValue> test_result_value(new DictionaryValue);
 
-        test_result_value->SetString("status", test_result.StatusAsString());
+        test_result_value->SetStringKey("status", test_result.StatusAsString());
         test_result_value->SetInteger(
             "elapsed_time_ms",
             static_cast<int>(test_result.elapsed_time.InMilliseconds()));
@@ -422,7 +422,7 @@
 
         // TODO(phajdan.jr): Fix typo in JSON key (losless -> lossless)
         // making sure not to break any consumers of this data.
-        test_result_value->SetBoolean("losless_snippet", lossless_snippet);
+        test_result_value->SetBoolKey("losless_snippet", lossless_snippet);
 
         // Also include the raw version (base64-encoded so that it can be safely
         // JSON-serialized - there are no guarantees about character encoding
@@ -430,43 +430,43 @@
         // debugging a test failure related to character encoding.
         std::string base64_output_snippet;
         Base64Encode(test_result.output_snippet, &base64_output_snippet);
-        test_result_value->SetString("output_snippet_base64",
-                                     base64_output_snippet);
+        test_result_value->SetStringKey("output_snippet_base64",
+                                        base64_output_snippet);
 
         std::unique_ptr<ListValue> test_result_parts(new ListValue);
         for (const TestResultPart& result_part :
              test_result.test_result_parts) {
           std::unique_ptr<DictionaryValue> result_part_value(
               new DictionaryValue);
-          result_part_value->SetString("type", result_part.TypeAsString());
-          result_part_value->SetString("file", result_part.file_name);
-          result_part_value->SetInteger("line", result_part.line_number);
+          result_part_value->SetStringKey("type", result_part.TypeAsString());
+          result_part_value->SetStringKey("file", result_part.file_name);
+          result_part_value->SetIntKey("line", result_part.line_number);
 
           bool lossless_summary = IsStringUTF8(result_part.summary);
           if (lossless_summary) {
-            result_part_value->SetString("summary", result_part.summary);
+            result_part_value->SetStringKey("summary", result_part.summary);
           } else {
             result_part_value->SetString(
                 "summary", "<non-UTF-8 snippet, see summary_base64>");
           }
-          result_part_value->SetBoolean("lossless_summary", lossless_summary);
+          result_part_value->SetBoolKey("lossless_summary", lossless_summary);
 
           std::string encoded_summary;
           Base64Encode(result_part.summary, &encoded_summary);
-          result_part_value->SetString("summary_base64", encoded_summary);
+          result_part_value->SetStringKey("summary_base64", encoded_summary);
 
           bool lossless_message = IsStringUTF8(result_part.message);
           if (lossless_message) {
-            result_part_value->SetString("message", result_part.message);
+            result_part_value->SetStringKey("message", result_part.message);
           } else {
             result_part_value->SetString(
                 "message", "<non-UTF-8 snippet, see message_base64>");
           }
-          result_part_value->SetBoolean("lossless_message", lossless_message);
+          result_part_value->SetBoolKey("lossless_message", lossless_message);
 
           std::string encoded_message;
           Base64Encode(result_part.message, &encoded_message);
-          result_part_value->SetString("message_base64", encoded_message);
+          result_part_value->SetStringKey("message_base64", encoded_message);
 
           test_result_parts->Append(std::move(result_part_value));
         }
@@ -487,8 +487,8 @@
     std::string test_name = item.first;
     CodeLocation location = item.second;
     std::unique_ptr<DictionaryValue> location_value(new DictionaryValue);
-    location_value->SetString("file", location.file);
-    location_value->SetInteger("line", location.line);
+    location_value->SetStringKey("file", location.file);
+    location_value->SetIntKey("line", location.line);
     test_locations->SetWithoutPathExpansion(test_name,
                                             std::move(location_value));
   }
diff --git a/base/test/type_id_test_support_a.cc b/base/test/type_id_test_support_a.cc
index 143c28e5..7701209d 100644
--- a/base/test/type_id_test_support_a.cc
+++ b/base/test/type_id_test_support_a.cc
@@ -23,4 +23,8 @@
   return TypeId::From<std::unique_ptr<int>>();
 }
 
+TypeId TypeIdTestSupportA::GetTypeIdForUniquePtrTestType() {
+  return TypeId::From<std::unique_ptr<TestType>>();
+}
+
 }  // namespace base
diff --git a/base/test/type_id_test_support_a.h b/base/test/type_id_test_support_a.h
index 22b80b5..17c81b7 100644
--- a/base/test/type_id_test_support_a.h
+++ b/base/test/type_id_test_support_a.h
@@ -10,10 +10,13 @@
 
 namespace base {
 
+struct COMPONENT_EXPORT(BASE_TEST) TestType {};
+
 // This is here to help test base::TypeId.
 struct COMPONENT_EXPORT(BASE_TEST) TypeIdTestSupportA {
   static TypeId GetTypeIdForTypeInAnonymousNameSpace();
   static TypeId GetTypeIdForUniquePtrInt();
+  static TypeId GetTypeIdForUniquePtrTestType();
 };
 
 }  // namespace base
diff --git a/base/token.h b/base/token.h
index 0d47584..e2843a6d 100644
--- a/base/token.h
+++ b/base/token.h
@@ -11,7 +11,7 @@
 #include <tuple>
 
 #include "base/base_export.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 
 namespace base {
 
diff --git a/base/trace_event/heap_profiler_allocation_context.cc b/base/trace_event/heap_profiler_allocation_context.cc
index bdc3c58..546b1f4 100644
--- a/base/trace_event/heap_profiler_allocation_context.cc
+++ b/base/trace_event/heap_profiler_allocation_context.cc
@@ -6,7 +6,7 @@
 
 #include <cstring>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 
 namespace base {
diff --git a/base/trace_event/memory_allocator_dump_guid.cc b/base/trace_event/memory_allocator_dump_guid.cc
index 08ac677..ff7aa9b 100644
--- a/base/trace_event/memory_allocator_dump_guid.cc
+++ b/base/trace_event/memory_allocator_dump_guid.cc
@@ -5,7 +5,7 @@
 #include "base/trace_event/memory_allocator_dump_guid.h"
 
 #include "base/format_macros.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/strings/stringprintf.h"
 
 namespace base {
diff --git a/base/trace_event/traced_value.cc b/base/trace_event/traced_value.cc
index 9fb4b91..b1ea5aab 100644
--- a/base/trace_event/traced_value.cc
+++ b/base/trace_event/traced_value.cc
@@ -380,44 +380,40 @@
         case kTypeBool: {
           bool value;
           CHECK(it.ReadBool(&value));
-          base::Value new_bool(value);
           if (cur_dict) {
-            cur_dict->SetKey(ReadKeyName(it), std::move(new_bool));
+            cur_dict->SetBoolKey(ReadKeyName(it), value);
           } else {
-            cur_list->GetList().push_back(std::move(new_bool));
+            cur_list->GetList().emplace_back(value);
           }
         } break;
 
         case kTypeInt: {
           int value;
           CHECK(it.ReadInt(&value));
-          base::Value new_int(value);
           if (cur_dict) {
-            cur_dict->SetKey(ReadKeyName(it), std::move(new_int));
+            cur_dict->SetIntKey(ReadKeyName(it), value);
           } else {
-            cur_list->GetList().push_back(std::move(new_int));
+            cur_list->GetList().emplace_back(value);
           }
         } break;
 
         case kTypeDouble: {
           double value;
           CHECK(it.ReadDouble(&value));
-          base::Value new_double(value);
           if (cur_dict) {
-            cur_dict->SetKey(ReadKeyName(it), std::move(new_double));
+            cur_dict->SetDoubleKey(ReadKeyName(it), value);
           } else {
-            cur_list->GetList().push_back(std::move(new_double));
+            cur_list->GetList().emplace_back(value);
           }
         } break;
 
         case kTypeString: {
           std::string value;
           CHECK(it.ReadString(&value));
-          base::Value new_str(std::move(value));
           if (cur_dict) {
-            cur_dict->SetKey(ReadKeyName(it), std::move(new_str));
+            cur_dict->SetStringKey(ReadKeyName(it), std::move(value));
           } else {
-            cur_list->GetList().push_back(std::move(new_str));
+            cur_list->GetList().emplace_back(std::move(value));
           }
         } break;
 
diff --git a/base/type_id.cc b/base/type_id.cc
index b041be4..0d7324b 100644
--- a/base/type_id.cc
+++ b/base/type_id.cc
@@ -33,6 +33,8 @@
   return function_name_;
 #elif defined(COMPILER_MSVC)
   return HexEncode(&unique_type_id_, sizeof(unique_type_id_));
+#elif defined(COMPONENT_BUILD)
+  return NumberToString(unique_type_id_);
 #else
   return NumberToString(reinterpret_cast<uintptr_t>(unique_type_id_));
 #endif
diff --git a/base/type_id.h b/base/type_id.h
index abfc41a..303e9b10 100644
--- a/base/type_id.h
+++ b/base/type_id.h
@@ -35,7 +35,68 @@
 inline TypeUniqueId UniqueIdFromType() {
   return std::type_index(typeid(Type));
 }
+#elif defined(COMPONENT_BUILD)
+// A substitute for RTTI that uses the hash of the PRETTY_FUNCTION and
+// __BASE_FILE__ to identify the type. Hash collisions can occur so don't use
+// this in production code. The reason we use this at all is the dynamic linker
+// can end up reserving two symbols for |dummy_var| below when the .SO is loaded
+// first. This only seems to affect templates with non-builtin types, e.g.
+// std::unique_ptr<int> is fine but |dummy_var| gets duplicated for
+// std::unique_ptr<MyType>.
+using TypeUniqueId = uint64_t;
 
+// TODO(alexclarke): Replace these when StringPiece gets more constexpr support.
+static constexpr bool string_starts_with(char const* s, char const* prefix) {
+  while (*prefix) {
+    if (*s++ != *prefix++)
+      return false;
+  }
+  return true;
+}
+
+static constexpr bool string_contains(char const* str, char const* fragment) {
+  while (*str) {
+    if (string_starts_with(str++, fragment))
+      return true;
+  }
+  return false;
+}
+
+template <typename Type>
+constexpr inline TypeUniqueId UniqueIdFromType() {
+  // This is an SDBM hash of PRETTY_FUNCTION, SMBD hash seems to be better than
+  // djb2 or other simple hashes, and should be good enough for our purposes.
+  // Source: http://www.cse.yorku.ca/~oz/hash.html
+  constexpr const char* function_name = PRETTY_FUNCTION;
+  uint64_t hash = 0;
+  for (uint64_t i = 0; function_name[i]; ++i) {
+    hash = function_name[i] + (hash << 6) + (hash << 16) - hash;
+  }
+
+  // There doesn't seem to be an official way of figuring out if a type is from
+  // an anonymous namespace so we fall back to inspecting the decorated function
+  // name.
+  constexpr const char* compiler_specific_anonymous_namespace_fragment =
+#if defined(__clang__)
+      "base::internal::UniqueIdFromType() [Type = (anonymous namespace)::";
+#elif defined(__clang__)
+      "base::internal::UniqueIdFromType() [with T = {anonymous}::";
+#elif defined(COMPILER_MSVC)
+      "base::internal::UniqueIdFromType<`anonymous namespace'::";
+#else
+#error Compiler unsupported
+#endif
+
+  // To disambiguate types in anonymous namespaces add __BASE_FILE_ to the hash.
+  if (string_contains(function_name,
+                      compiler_specific_anonymous_namespace_fragment)) {
+    constexpr auto* base_file = __BASE_FILE__;
+    for (uint64_t i = 0; base_file[i]; ++i) {
+      hash = base_file[i] + (hash << 6) + (hash << 16) - hash;
+    }
+  }
+  return hash;
+}
 #else
 // A substitute for RTTI that uses the linker to uniquely reserve an address in
 // the binary for each type.
diff --git a/base/type_id_unittest.cc b/base/type_id_unittest.cc
index aabf6bf2..8c32334 100644
--- a/base/type_id_unittest.cc
+++ b/base/type_id_unittest.cc
@@ -61,6 +61,11 @@
             TypeIdTestSupportB::GetTypeIdForTypeInAnonymousNameSpace());
 }
 
+TEST(TypeId, TemplateTypesfromDifferentSo) {
+  EXPECT_EQ(TypeIdTestSupportA::GetTypeIdForUniquePtrTestType(),
+            TypeId::From<std::unique_ptr<TestType>>());
+}
+
 // See http://crbug.com/914734
 #if defined(ADDRESS_SANITIZER)
 TEST(TypeId, DISABLED_IdenticalTypesFromDifferentCompilationUnitsMatch) {
diff --git a/base/unguessable_token.h b/base/unguessable_token.h
index 7f7b59a3..222177a9 100644
--- a/base/unguessable_token.h
+++ b/base/unguessable_token.h
@@ -11,7 +11,7 @@
 #include <tuple>
 
 #include "base/base_export.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/token.h"
 
diff --git a/base/values.cc b/base/values.cc
index 6f3a9e2..9fed5b5 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -381,11 +381,11 @@
   return dict_.erase(key) != 0;
 }
 
-Value* Value::SetKey(StringPiece key, Value&& value) {
+Value* Value::SetKeyInternal(StringPiece key,
+                             std::unique_ptr<Value>&& val_ptr) {
   CHECK(is_dict());
   // NOTE: We can't use |insert_or_assign| here, as only |try_emplace| does
   // an explicit conversion from StringPiece to std::string if necessary.
-  auto val_ptr = std::make_unique<Value>(std::move(value));
   auto result = dict_.try_emplace(key, std::move(val_ptr));
   if (!result.second) {
     // val_ptr is guaranteed to be still intact at this point.
@@ -394,6 +394,38 @@
   return result.first->second.get();
 }
 
+Value* Value::SetBoolKey(StringPiece key, bool value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetIntKey(StringPiece key, int value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetDoubleKey(StringPiece key, double value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetStringKey(StringPiece key, StringPiece value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetStringKey(StringPiece key, const char* value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetStringKey(StringPiece key, std::string&& value) {
+  return SetKeyInternal(key, std::make_unique<Value>(std::move(value)));
+}
+
+Value* Value::SetStringKey(StringPiece key, StringPiece16 value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetKey(StringPiece key, Value&& value) {
+  return SetKeyInternal(key, std::make_unique<Value>(std::move(value)));
+}
+
 Value* Value::SetKey(std::string&& key, Value&& value) {
   CHECK(is_dict());
   return dict_
@@ -403,7 +435,7 @@
 }
 
 Value* Value::SetKey(const char* key, Value&& value) {
-  return SetKey(StringPiece(key), std::move(value));
+  return SetKeyInternal(key, std::make_unique<Value>(std::move(value)));
 }
 
 Value* Value::FindPath(std::initializer_list<StringPiece> path) {
diff --git a/base/values.h b/base/values.h
index 7bc355e..486fe7f 100644
--- a/base/values.h
+++ b/base/values.h
@@ -222,6 +222,7 @@
   // value to |value|. If |key| could not be found, a new element is inserted.
   // A pointer to the modified item is returned.
   // Note: This fatally asserts if type() is not Type::DICTIONARY.
+  // Note: Prefer Set<Type>Key() for simple values.
   //
   // Example:
   //   SetKey("foo", std::move(myvalue));
@@ -231,6 +232,20 @@
   // This overload is necessary to avoid ambiguity for const char* arguments.
   Value* SetKey(const char* key, Value&& value);
 
+  // |Set<Type>Key| looks up |key| in the underlying dictionary and associates
+  // a corresponding Value() constructed from the second parameter. Compared
+  // to SetKey(), this avoids un-necessary temporary Value() creation, as well
+  // ambiguities in the value type.
+  Value* SetBoolKey(StringPiece key, bool val);
+  Value* SetIntKey(StringPiece key, int val);
+  Value* SetDoubleKey(StringPiece key, double val);
+  Value* SetStringKey(StringPiece key, StringPiece val);
+  // NOTE: These two overloads are provided as performance / code generation
+  // optimizations.
+  Value* SetStringKey(StringPiece key, const char* val);
+  Value* SetStringKey(StringPiece key, std::string&& val);
+  Value* SetStringKey(StringPiece key, StringPiece16 val);
+
   // This attemps to remove the value associated with |key|. In case of failure,
   // e.g. the key does not exist, |false| is returned and the underlying
   // dictionary is not changed. In case of success, |key| is deleted from the
@@ -469,6 +484,10 @@
   void InternalMoveConstructFrom(Value&& that);
   void InternalCleanup();
 
+  // NOTE: Using a movable reference here is done for performance (it avoids
+  // creating + moving + destroying a temporary unique ptr).
+  Value* SetKeyInternal(StringPiece key, std::unique_ptr<Value>&& val_ptr);
+
   DISALLOW_COPY_AND_ASSIGN(Value);
 };
 
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 2907dc0..2dd1c76 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -794,6 +794,97 @@
   EXPECT_EQ(Value(std::move(storage)), dict);
 }
 
+TEST(ValuesTest, SetBoolKey) {
+  base::Optional<bool> value;
+
+  DictionaryValue dict;
+  dict.SetBoolKey("true_key", true);
+  dict.SetBoolKey("false_key", false);
+
+  value = dict.FindBoolKey("true_key");
+  ASSERT_TRUE(value);
+  ASSERT_TRUE(*value);
+
+  value = dict.FindBoolKey("false_key");
+  ASSERT_TRUE(value);
+  ASSERT_FALSE(*value);
+
+  value = dict.FindBoolKey("missing_key");
+  ASSERT_FALSE(value);
+}
+
+TEST(ValuesTest, SetIntKey) {
+  base::Optional<int> value;
+
+  DictionaryValue dict;
+  dict.SetIntKey("one_key", 1);
+  dict.SetIntKey("minus_one_key", -1);
+
+  value = dict.FindIntKey("one_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ(1, *value);
+
+  value = dict.FindIntKey("minus_one_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ(-1, *value);
+
+  value = dict.FindIntKey("missing_key");
+  ASSERT_FALSE(value);
+}
+
+TEST(ValuesTest, SetDoubleKey) {
+  DictionaryValue dict;
+  dict.SetDoubleKey("one_key", 1.0);
+  dict.SetDoubleKey("minus_one_key", -1.0);
+  dict.SetDoubleKey("pi_key", 3.1415);
+
+  // NOTE: Use FindKey() instead of FindDoubleKey() because the latter will
+  // auto-convert integers to doubles as well.
+  const Value* value;
+
+  value = dict.FindKey("one_key");
+  ASSERT_TRUE(value);
+  EXPECT_TRUE(value->is_double());
+  EXPECT_EQ(1.0, value->GetDouble());
+
+  value = dict.FindKey("minus_one_key");
+  ASSERT_TRUE(value);
+  EXPECT_TRUE(value->is_double());
+  EXPECT_EQ(-1.0, value->GetDouble());
+
+  value = dict.FindKey("pi_key");
+  ASSERT_TRUE(value);
+  EXPECT_TRUE(value->is_double());
+  EXPECT_EQ(3.1415, value->GetDouble());
+}
+
+TEST(ValuesTest, SetStringKey) {
+  DictionaryValue dict;
+  dict.SetStringKey("one_key", "one");
+  dict.SetStringKey("hello_key", "hello world");
+
+  std::string movable_value("movable_value");
+  dict.SetStringKey("movable_key", std::move(movable_value));
+  ASSERT_TRUE(movable_value.empty());
+
+  const std::string* value;
+
+  value = dict.FindStringKey("one_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ("one", *value);
+
+  value = dict.FindStringKey("hello_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ("hello world", *value);
+
+  value = dict.FindStringKey("movable_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ("movable_value", *value);
+
+  value = dict.FindStringKey("missing_key");
+  ASSERT_FALSE(value);
+}
+
 TEST(ValuesTest, FindPath) {
   // Construct a dictionary path {root}.foo.bar = 123
   Value foo(Value::Type::DICTIONARY);
@@ -893,7 +984,7 @@
   ASSERT_EQ(std::string("http://google.com"), homepage);
 
   ASSERT_FALSE(settings.Get("global", nullptr));
-  settings.SetBoolean("global", true);
+  settings.SetBoolKey("global", true);
   ASSERT_TRUE(settings.Get("global", nullptr));
   settings.SetString("global.homepage", "http://scurvy.com");
   ASSERT_TRUE(settings.Get("global", nullptr));
@@ -911,8 +1002,8 @@
   ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
 
   std::unique_ptr<DictionaryValue> new_bookmark(new DictionaryValue);
-  new_bookmark->SetString("name", "Froogle");
-  new_bookmark->SetString("url", "http://froogle.com");
+  new_bookmark->SetStringKey("name", "Froogle");
+  new_bookmark->SetStringKey("url", "http://froogle.com");
   toolbar_bookmarks->Append(std::move(new_bookmark));
 
   ListValue* bookmark_list;
@@ -1276,7 +1367,7 @@
 
   DictionaryValue* dict_weak = original_dict.SetDictionary(
       "dictionary", std::make_unique<DictionaryValue>());
-  dict_weak->SetString("key", "value");
+  dict_weak->SetStringKey("key", "value");
 
   auto copy_dict = original_dict.CreateDeepCopy();
   ASSERT_TRUE(copy_dict.get());
@@ -1392,11 +1483,11 @@
   EXPECT_NE(*null1, boolean);
 
   DictionaryValue dv;
-  dv.SetBoolean("a", false);
-  dv.SetInteger("b", 2);
-  dv.SetDouble("c", 2.5);
-  dv.SetString("d1", "string");
-  dv.SetString("d2", ASCIIToUTF16("http://google.com"));
+  dv.SetBoolKey("a", false);
+  dv.SetIntKey("b", 2);
+  dv.SetDoubleKey("c", 2.5);
+  dv.SetStringKey("d1", "string");
+  dv.SetStringKey("d2", ASCIIToUTF16("http://google.com"));
   dv.Set("e", std::make_unique<Value>());
 
   auto copy = dv.CreateDeepCopy();
@@ -1419,7 +1510,7 @@
   copy = dv.CreateDeepCopy();
   EXPECT_EQ(dv, *copy);
   copy->Remove("a", nullptr);
-  copy->SetBoolean("aa", false);
+  copy->SetBoolKey("aa", false);
   EXPECT_NE(dv, *copy);
 }
 
@@ -1519,8 +1610,8 @@
   // Test Non Empty Dict Values.
   DictionaryValue int_dict1;
   DictionaryValue int_dict2;
-  int_dict1.SetInteger("key", 1);
-  int_dict2.SetInteger("key", 2);
+  int_dict1.SetIntKey("key", 1);
+  int_dict2.SetIntKey("key", 2);
   EXPECT_FALSE(int_dict1 == int_dict2);
   EXPECT_NE(int_dict1, int_dict2);
   EXPECT_LT(int_dict1, int_dict2);
@@ -1599,9 +1690,9 @@
   EXPECT_TRUE(root->empty());
 
   // Make sure we don't prune too much.
-  root->SetBoolean("bool", true);
+  root->SetBoolKey("bool", true);
   root->Set("empty_dict", std::make_unique<DictionaryValue>());
-  root->SetString("empty_string", std::string());
+  root->SetStringKey("empty_string", std::string());
   root = root->DeepCopyWithoutEmptyChildren();
   EXPECT_EQ(2U, root->size());
 
@@ -1668,19 +1759,20 @@
 
 TEST(ValuesTest, MergeDictionary) {
   std::unique_ptr<DictionaryValue> base(new DictionaryValue);
-  base->SetString("base_key", "base_key_value_base");
-  base->SetString("collide_key", "collide_key_value_base");
+  base->SetStringKey("base_key", "base_key_value_base");
+  base->SetStringKey("collide_key", "collide_key_value_base");
   std::unique_ptr<DictionaryValue> base_sub_dict(new DictionaryValue);
-  base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base");
-  base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base");
+  base_sub_dict->SetStringKey("sub_base_key", "sub_base_key_value_base");
+  base_sub_dict->SetStringKey("sub_collide_key", "sub_collide_key_value_base");
   base->Set("sub_dict_key", std::move(base_sub_dict));
 
   std::unique_ptr<DictionaryValue> merge(new DictionaryValue);
-  merge->SetString("merge_key", "merge_key_value_merge");
-  merge->SetString("collide_key", "collide_key_value_merge");
+  merge->SetStringKey("merge_key", "merge_key_value_merge");
+  merge->SetStringKey("collide_key", "collide_key_value_merge");
   std::unique_ptr<DictionaryValue> merge_sub_dict(new DictionaryValue);
-  merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge");
-  merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge");
+  merge_sub_dict->SetStringKey("sub_merge_key", "sub_merge_key_value_merge");
+  merge_sub_dict->SetStringKey("sub_collide_key",
+                               "sub_collide_key_value_merge");
   merge->Set("sub_dict_key", std::move(merge_sub_dict));
 
   base->MergeDictionary(merge.get());
@@ -1714,7 +1806,7 @@
 TEST(ValuesTest, MergeDictionaryDeepCopy) {
   std::unique_ptr<DictionaryValue> child(new DictionaryValue);
   DictionaryValue* original_child = child.get();
-  child->SetString("test", "value");
+  child->SetStringKey("test", "value");
   EXPECT_EQ(1U, child->size());
 
   std::string value;
@@ -1737,7 +1829,7 @@
   EXPECT_TRUE(ptr->GetString("test", &value));
   EXPECT_EQ("value", value);
 
-  original_child->SetString("test", "overwrite");
+  original_child->SetStringKey("test", "overwrite");
   base.reset();
   EXPECT_TRUE(ptr->GetString("test", &value));
   EXPECT_EQ("value", value);
@@ -2104,8 +2196,8 @@
 
 TEST(ValuesTest, FromToUniquePtrValue) {
   std::unique_ptr<DictionaryValue> dict = std::make_unique<DictionaryValue>();
-  dict->SetString("name", "Froogle");
-  dict->SetString("url", "http://froogle.com");
+  dict->SetStringKey("name", "Froogle");
+  dict->SetStringKey("url", "http://froogle.com");
   Value dict_copy = dict->Clone();
 
   Value dict_converted = Value::FromUniquePtrValue(std::move(dict));
diff --git a/base/win/scoped_handle_verifier.h b/base/win/scoped_handle_verifier.h
index 008e790c..0842a22 100644
--- a/base/win/scoped_handle_verifier.h
+++ b/base/win/scoped_handle_verifier.h
@@ -11,7 +11,7 @@
 
 #include "base/base_export.h"
 #include "base/debug/stack_trace.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/synchronization/lock_impl.h"
 #include "base/threading/thread_local.h"
 
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index d85585f2..e5a6e3c 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -129,7 +129,7 @@
   }
 
   webview_public_framework_dep =
-      "//third_party/android_system_sdk:public_framework_system_java"
+      "//third_party/android_sdk:public_framework_system_java"
   if (!defined(webview_framework_dep)) {
     webview_framework_dep = webview_public_framework_dep
   }
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index f7a8e97..4a93841 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -9,7 +9,6 @@
 import("//build/config/python.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build_overrides/build.gni")
-
 assert(is_android)
 
 # These identify targets that have .build_config files (except for android_apk,
@@ -3272,7 +3271,7 @@
         _emma_instrument = !invoker.emma_never_instrument && _emma_instrument
       }
       if (_emma_instrument) {
-        _accumulated_deps += [ "//third_party/android_tools:emma_device_java" ]
+        _accumulated_deps += [ "//third_party/android_sdk:emma_device_java" ]
       }
     }
 
@@ -3292,7 +3291,7 @@
       if (defined(invoker.alternative_android_sdk_dep)) {
         _accumulated_deps += [ invoker.alternative_android_sdk_dep ]
       } else {
-        _accumulated_deps += [ "//third_party/android_tools:android_sdk_java" ]
+        _accumulated_deps += [ "//third_party/android_sdk:android_sdk_java" ]
       }
     }
 
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index de36133..d8a5136 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -12,7 +12,6 @@
 import("//build/config/python.gni")
 import("//build/config/zip.gni")
 import("//build/toolchain/toolchain.gni")
-
 assert(is_android)
 
 declare_args() {
@@ -969,7 +968,7 @@
     if (defined(invoker.alternative_android_sdk_dep)) {
       _deps += [ invoker.alternative_android_sdk_dep ]
     } else {
-      _deps += [ "//third_party/android_tools:android_sdk_java" ]
+      _deps += [ "//third_party/android_sdk:android_sdk_java" ]
     }
 
     write_build_config(_build_config_target_name) {
@@ -1579,7 +1578,7 @@
       _deps = invoker.deps
     }
     if (_supports_android) {
-      _deps += [ "//third_party/android_tools:android_sdk_java" ]
+      _deps += [ "//third_party/android_sdk:android_sdk_java" ]
     }
     _enable_build_hooks =
         _supports_android &&
@@ -1676,7 +1675,7 @@
   #   }
   template("proguarded_dist_dex") {
     _deps = [
-      "//third_party/android_tools:android_sdk_java",
+      "//third_party/android_sdk:android_sdk_java",
       "//build/android/buildhooks:build_hooks_android_impl_java",
     ]
     if (defined(invoker.deps)) {
@@ -2216,7 +2215,8 @@
       }
     }
 
-    if (_shared_libraries_is_valid || _secondary_abi_shared_libraries_is_valid) {
+    if (_shared_libraries_is_valid ||
+        _secondary_abi_shared_libraries_is_valid) {
       _native_lib_version_rule = ""
       if (defined(invoker.native_lib_version_rule)) {
         _native_lib_version_rule = invoker.native_lib_version_rule
@@ -2296,7 +2296,7 @@
     if (defined(invoker.alternative_android_sdk_dep)) {
       _android_sdk_dep = invoker.alternative_android_sdk_dep
     } else {
-      _android_sdk_dep = "//third_party/android_tools:android_sdk_java"
+      _android_sdk_dep = "//third_party/android_sdk:android_sdk_java"
     }
 
     _optimize_resources =
@@ -4192,7 +4192,7 @@
     if (defined(invoker.proguard_android_sdk_dep)) {
       proguard_android_sdk_dep_ = invoker.proguard_android_sdk_dep
     } else {
-      proguard_android_sdk_dep_ = "//third_party/android_tools:android_sdk_java"
+      proguard_android_sdk_dep_ = "//third_party/android_sdk:android_sdk_java"
     }
     write_build_config(_build_config_target) {
       # We don't want async modules to be proguarded synchronously, so we leave
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index b37e8d1..08373b85 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -153,7 +153,7 @@
   # other architectures.
   #
   # lld doesn't have the bug.
-  use_icf = (is_posix || is_fuchsia) && !using_sanitizer &&
+  use_icf = (is_posix || is_fuchsia) && !is_debug && !using_sanitizer &&
             !use_clang_coverage && !(is_android && use_order_profiling) &&
             (use_lld ||
              (use_gold &&
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b15230f..4c84a8c5 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8917748162108050016
\ No newline at end of file
+8917689396081248048
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 1f00a9a9..5605e1c2 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8917756198278791120
\ No newline at end of file
+8917701052166833184
\ No newline at end of file
diff --git a/build/secondary/third_party/android_system_sdk/BUILD.gn b/build/secondary/third_party/android_system_sdk/BUILD.gn
deleted file mode 100644
index b8f665b..0000000
--- a/build/secondary/third_party/android_system_sdk/BUILD.gn
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/android/rules.gni")
-
-android_system_java_prebuilt("public_framework_system_java") {
-  jar_path = "//third_party/android_system_sdk/android_system.jar"
-}
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
index 41aaf08..0912d3f1 100644
--- a/build/secondary/third_party/android_tools/BUILD.gn
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -4,100 +4,33 @@
 
 import("//build/config/android/rules.gni")
 
-config("cpu_features_include") {
-  include_dirs = [ "$android_ndk_root/sources/android/cpufeatures" ]
-}
+# TODO(crbug.com/947060): All targets in this file are temporary aliases. They
+# will be removed once all downstream targets are switched over to using
+# //third_party/android_sdk.
 
-config("cpu_features_warnings") {
-  if (is_clang) {
-    # cpu-features.c has few unused functions on x86 b/26403333
-    cflags = [ "-Wno-unused-function" ]
-  }
-}
-
-source_set("cpu_features") {
-  sources = [
-    "$android_ndk_root/sources/android/cpufeatures/cpu-features.c",
-  ]
-  public_configs = [ ":cpu_features_include" ]
-
-  configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [
-    "//build/config/compiler:no_chromium_code",
-
-    # Must be after no_chromium_code for warning flags to be ordered correctly.
-    ":cpu_features_warnings",
+group("cpu_features") {
+  public_deps = [
+    "//third_party/android_sdk:cpu_features",
   ]
 }
 
 if (enable_java_templates) {
-  android_system_java_prebuilt("android_sdk_java") {
-    jar_path = android_sdk_jar
-  }
-
-  template("android_test_jar_with_manifest") {
-    _manifest_output_path = "$target_gen_dir/$target_name/AndroidManifest.xml"
-    _manifest_target = "${target_name}__manifest"
-    jinja_template(_manifest_target) {
-      testonly = true
-      input = "//build/secondary/third_party/android_tools/AndroidManifest.xml.jinja2"
-      output = _manifest_output_path
-      variables = [ "library_name=${invoker.library_name}" ]
-    }
-
-    _resources_target = "${target_name}__resources"
-    android_resources(_resources_target) {
-      testonly = true
-      resource_dirs = []
-      android_manifest = _manifest_output_path
-      android_manifest_dep = ":$_manifest_target"
-    }
-
-    java_group(target_name) {
-      testonly = true
-      deps = [
-        ":$_resources_target",
-      ]
-      input_jars_paths = [ "${android_sdk}/optional/${invoker.jar_name}" ]
-    }
-  }
-
-  # The android test libraries below are part of the main SDK jar
-  # and are linked by default on O and below. Starting in P, they
-  # exist in their own libraries that are present on device and are
-  # available to be linked against but aren't linked by default.
-  android_test_jar_with_manifest("android_test_base_java") {
-    library_name = "base"
-    jar_name = "android.test.base.jar"
-  }
-  android_test_jar_with_manifest("android_test_mock_java") {
-    library_name = "mock"
-    jar_name = "android.test.mock.jar"
-  }
-  android_test_jar_with_manifest("android_test_runner_java") {
-    library_name = "runner"
-    jar_name = "android.test.runner.jar"
-  }
-
-  android_library("android_support_chromium_java") {
+  java_group("android_test_base_java") {
     testonly = true
-    java_files = [ "//third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java" ]
+    deps = [
+      "//third_party/android_sdk:android_test_base_java",
+    ]
   }
-  android_java_prebuilt("android_gcm_java") {
-    jar_path = "//third_party/android_sdk/public/extras/google/gcm/gcm-client/dist/gcm.jar"
-  }
-  android_java_prebuilt("emma_device_java") {
-    jar_path = "//third_party/android_sdk/public/tools/lib/emma_device.jar"
-    include_java_resources = true
-  }
-
-  # The current version of //third_party/byte_buddy relies on an older
-  # version of dx.
-  java_prebuilt("dx_25_0_2_java") {
-    supports_android = true
-    requires_android = true
-    no_build_hooks = true
+  java_group("android_test_mock_java") {
     testonly = true
-    jar_path = "//third_party/android_sdk/public/build-tools/25.0.2/lib/dx.jar"
+    deps = [
+      "//third_party/android_sdk:android_test_mock_java",
+    ]
+  }
+  java_group("android_test_runner_java") {
+    testonly = true
+    deps = [
+      "//third_party/android_sdk:android_test_runner_java",
+    ]
   }
 }
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 0223c2b..70f0024 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -8,6 +8,8 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <utility>
+#include <vector>
 
 #include "base/atomic_sequence_num.h"
 #include "base/location.h"
@@ -272,6 +274,27 @@
   }
 }
 
+void Layer::ReorderChildren(LayerList* new_children_order) {
+#if DCHECK_IS_ON()
+  base::flat_set<Layer*> children_set;
+  for (const auto& child : *new_children_order) {
+    DCHECK_EQ(child->parent(), this);
+    children_set.insert(child.get());
+  }
+  for (const auto& child : inputs_.children)
+    DCHECK_GT(children_set.count(child.get()), 0u);
+#endif
+  inputs_.children = std::move(*new_children_order);
+
+  // We do not need to call SetSubtreePropertyChanged for each child here
+  // since SetSubtreePropertyChanged includes SetNeedsPushProperties, but this
+  // change is not included in properties pushing.
+  for (const auto& child : inputs_.children)
+    child->subtree_property_changed_ = true;
+
+  SetNeedsFullTreeSync();
+}
+
 void Layer::ReplaceChild(Layer* reference, scoped_refptr<Layer> new_layer) {
   DCHECK(reference);
   DCHECK_EQ(reference->parent(), this);
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 42eee59..826ba6f 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -175,6 +175,12 @@
   void SetPosition(const gfx::PointF& position);
   const gfx::PointF& position() const { return inputs_.position; }
 
+  // Reorder the entirety of the children() vector to follow new_children_order.
+  // All elements inside new_children_order must be inside children(), and vice
+  // versa. Will empty the |new_children_order| LayerList passed into this
+  // method.
+  void ReorderChildren(LayerList* new_children_order);
+
   // Set and get the layers bounds. This is specified in layer space, which
   // excludes device scale and page scale factors, and ignoring transforms for
   // this layer or ancestor layers.
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 2853ea5..f207739 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -524,6 +524,41 @@
   EXPECT_EQ(parent.get(), child->parent());
 }
 
+TEST_F(LayerTest, ReorderChildren) {
+  EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+
+  scoped_refptr<Layer> parent = Layer::Create();
+  scoped_refptr<Layer> child1 = Layer::Create();
+  scoped_refptr<Layer> child2 = Layer::Create();
+  scoped_refptr<Layer> child3 = Layer::Create();
+
+  layer_tree_host_->SetRootLayer(parent);
+
+  parent->AddChild(child1);
+  parent->AddChild(child2);
+  parent->AddChild(child3);
+  EXPECT_EQ(child1, parent->children()[0]);
+  EXPECT_EQ(child2, parent->children()[1]);
+  EXPECT_EQ(child3, parent->children()[2]);
+
+  layer_tree_host_->ClearLayersThatShouldPushProperties();
+
+  LayerList new_children_order;
+  new_children_order.emplace_back(child3);
+  new_children_order.emplace_back(child1);
+  new_children_order.emplace_back(child2);
+  parent->ReorderChildren(&new_children_order);
+  EXPECT_EQ(child3, parent->children()[0]);
+  EXPECT_EQ(child1, parent->children()[1]);
+  EXPECT_EQ(child2, parent->children()[2]);
+
+  for (const auto& child : parent->children()) {
+    EXPECT_FALSE(base::ContainsKey(
+        layer_tree_host_->LayersThatShouldPushProperties(), child.get()));
+    EXPECT_TRUE(child->subtree_property_changed());
+  }
+}
+
 TEST_F(LayerTest, InsertChild) {
   scoped_refptr<Layer> parent = Layer::Create();
   scoped_refptr<Layer> child1 = Layer::Create();
diff --git a/cc/paint/image_transfer_cache_entry.cc b/cc/paint/image_transfer_cache_entry.cc
index 9781218..d55d7a4 100644
--- a/cc/paint/image_transfer_cache_entry.cc
+++ b/cc/paint/image_transfer_cache_entry.cc
@@ -183,6 +183,10 @@
   PaintOpReader reader(data.data(), data.size(), options);
   SkColorType color_type;
   reader.Read(&color_type);
+
+  if (color_type == kUnknown_SkColorType || color_type > kLastEnum_SkColorType)
+    return false;
+
   uint32_t width;
   reader.Read(&width);
   uint32_t height;
diff --git a/cc/paint/paint_image.cc b/cc/paint/paint_image.cc
index 08f0012..1d79404 100644
--- a/cc/paint/paint_image.cc
+++ b/cc/paint/paint_image.cc
@@ -7,7 +7,7 @@
 #include <memory>
 
 #include "base/atomic_sequence_num.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "cc/paint/paint_image_builder.h"
 #include "cc/paint/paint_image_generator.h"
 #include "cc/paint/paint_record.h"
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 7b75bd8..a4433d4 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -365,6 +365,11 @@
   if (forced_redraw_state_ == ForcedRedrawOnTimeoutState::WAITING_FOR_DRAW)
     return true;
 
+  // Delay draws when we have pending animation worklet updates to give them
+  // time to produce output before we draw.
+  if (processing_animation_worklets_for_active_tree_)
+    return false;
+
   return needs_redraw_;
 }
 
@@ -1430,8 +1435,18 @@
     AnimationWorkletState state,
     TreeType tree) {
   if (tree == TreeType::ACTIVE) {
-    processing_animation_worklets_for_active_tree_ =
-        (state == AnimationWorkletState::PROCESSING);
+    switch (state) {
+      case AnimationWorkletState::PROCESSING:
+        DCHECK_GE(processing_animation_worklets_for_active_tree_, 0);
+        DCHECK_LE(processing_animation_worklets_for_active_tree_, 1);
+        processing_animation_worklets_for_active_tree_++;
+        break;
+
+      case AnimationWorkletState::IDLE:
+        DCHECK_LE(processing_animation_worklets_for_active_tree_, 2);
+        DCHECK_GE(processing_animation_worklets_for_active_tree_, 1);
+        processing_animation_worklets_for_active_tree_--;
+    }
   } else {
     processing_animation_worklets_for_pending_tree_ =
         (state == AnimationWorkletState::PROCESSING);
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index 76f3c18..091f1af3 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -444,7 +444,12 @@
   bool next_invalidation_needs_first_draw_on_activation_ = false;
   bool should_defer_invalidation_for_fast_main_frame_ = true;
   bool begin_frame_is_animate_only_ = false;
-  bool processing_animation_worklets_for_active_tree_ = false;
+
+  // Number of async mutation cycles for the active tree that are in-flight or
+  // queued.  Can be 0, 1 or 2.
+  int processing_animation_worklets_for_active_tree_ = 0;
+  // Indicates if an aysnc mutation cycle is in-flight or queued for the pending
+  // tree.  Only one can be running or queued at any time.
   bool processing_animation_worklets_for_pending_tree_ = false;
 
   // Set to true if the main thread fails to respond with a commit or abort the
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index 886529d..489cd11 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -161,9 +161,10 @@
     return needs_impl_side_invalidation_;
   }
 
+  using SchedulerStateMachine::ProactiveBeginFrameWanted;
+  using SchedulerStateMachine::ShouldDraw;
   using SchedulerStateMachine::ShouldPrepareTiles;
   using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately;
-  using SchedulerStateMachine::ProactiveBeginFrameWanted;
   using SchedulerStateMachine::WillCommit;
 
  protected:
@@ -2741,18 +2742,51 @@
   state.NotifyReadyToActivate();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
   EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
+  EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
+            state.CurrentBeginImplFrameDeadlineMode());
+  // Started async mutation cycle for animation worklets.
   state.NotifyAnimationWorkletStateChange(
       SchedulerStateMachine::AnimationWorkletState::PROCESSING,
       SchedulerStateMachine::TreeType::ACTIVE);
   EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
   EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::REGULAR,
             state.CurrentBeginImplFrameDeadlineMode());
+  // Second queued state change.
+  state.NotifyAnimationWorkletStateChange(
+      SchedulerStateMachine::AnimationWorkletState::PROCESSING,
+      SchedulerStateMachine::TreeType::ACTIVE);
+  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
+  EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::REGULAR,
+            state.CurrentBeginImplFrameDeadlineMode());
+  // First mutation cycle completes. Still waiting on queued mutation cycle
+  // before being ready to draw.
+  state.NotifyAnimationWorkletStateChange(
+      SchedulerStateMachine::AnimationWorkletState::IDLE,
+      SchedulerStateMachine::TreeType::ACTIVE);
+  EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
+  EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::REGULAR,
+            state.CurrentBeginImplFrameDeadlineMode());
+  // Queued mutation cycle completes. Now ready to draw.
   state.NotifyAnimationWorkletStateChange(
       SchedulerStateMachine::AnimationWorkletState::IDLE,
       SchedulerStateMachine::TreeType::ACTIVE);
   EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
   EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
             state.CurrentBeginImplFrameDeadlineMode());
+
+  state.SetNeedsRedraw(true);
+  state.OnBeginImplFrameDeadline();
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE);
+  EXPECT_TRUE(state.ShouldDraw());
+  state.NotifyAnimationWorkletStateChange(
+      SchedulerStateMachine::AnimationWorkletState::PROCESSING,
+      SchedulerStateMachine::TreeType::ACTIVE);
+  EXPECT_FALSE(state.ShouldDraw());
+  state.NotifyAnimationWorkletStateChange(
+      SchedulerStateMachine::AnimationWorkletState::IDLE,
+      SchedulerStateMachine::TreeType::ACTIVE);
+  EXPECT_TRUE(state.ShouldDraw());
 }
 
 TEST(SchedulerStateMachineTest, BlockActivationIfAnimationWorkletsPending) {
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 4f583e1e..96b32a6 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -9,7 +9,7 @@
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/debug/alias.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/memory/discardable_memory_allocator.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_math.h"
diff --git a/cc/tiles/software_image_decode_cache_utils.cc b/cc/tiles/software_image_decode_cache_utils.cc
index 16f5d11..fac25c22 100644
--- a/cc/tiles/software_image_decode_cache_utils.cc
+++ b/cc/tiles/software_image_decode_cache_utils.cc
@@ -5,7 +5,7 @@
 #include "cc/tiles/software_image_decode_cache_utils.h"
 
 #include "base/atomic_sequence_num.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/memory/discardable_memory_allocator.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
diff --git a/cc/trees/element_id.h b/cc/trees/element_id.h
index 482ed3e..b34782d9 100644
--- a/cc/trees/element_id.h
+++ b/cc/trees/element_id.h
@@ -12,7 +12,7 @@
 #include <iosfwd>
 #include <memory>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "cc/cc_export.h"
 
 namespace base {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 7758022..6dcf1d8 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -123,6 +123,13 @@
 // V1 saw errors of ~0.065 between computed window and content widths.
 const float kMobileViewportWidthEpsilon = 0.15f;
 
+// In BuildHitTestData we iterate all layers to find all layers that overlap
+// OOPIFs, but when the number of layers is greater than
+// |kAssumeOverlapThreshold|, it can be inefficient to accumulate layer bounds
+// for overlap checking. As a result, we are conservative and make OOPIFs
+// kHitTestAsk after the threshold is reached.
+const size_t kAssumeOverlapThreshold = 100;
+
 bool HasFixedPageScale(LayerTreeImpl* active_tree) {
   return active_tree->min_page_scale_factor() ==
          active_tree->max_page_scale_factor();
@@ -2612,6 +2619,11 @@
   float device_scale_factor = active_tree()->device_scale_factor();
 
   Region overlapping_region;
+  size_t num_iterated_layers = 0;
+  // If the layer tree contains more than 100 layers, we stop accumulating
+  // layers in |overlapping_region| to save compositor frame submitting time, as
+  // a result we do async hit test on any surface layers that
+  bool assume_overlap = false;
   for (const auto* layer : base::Reversed(*active_tree())) {
     if (!layer->ShouldHitTest())
       continue;
@@ -2624,7 +2636,7 @@
       if (!surface_layer->surface_hit_testable()) {
         // We collect any overlapped regions that does not have pointer-events:
         // none.
-        if (!surface_layer->has_pointer_events_none()) {
+        if (!surface_layer->has_pointer_events_none() && !assume_overlap) {
           overlapping_region.Union(MathUtil::MapEnclosingClippedRect(
               layer->ScreenSpaceTransform(),
               gfx::Rect(surface_layer->bounds())));
@@ -2644,7 +2656,8 @@
           viz::AsyncHitTestReasons::kNotAsyncHitTest;
       if (surface_layer->has_pointer_events_none())
         flag |= viz::HitTestRegionFlags::kHitTestIgnore;
-      if (overlapping_region.Intersects(layer_screen_space_rect)) {
+      if (assume_overlap ||
+          overlapping_region.Intersects(layer_screen_space_rect)) {
         flag |= viz::HitTestRegionFlags::kHitTestAsk;
         async_hit_test_reasons |= viz::AsyncHitTestReasons::kOverlappedRegion;
       }
@@ -2678,8 +2691,13 @@
     }
     // TODO(sunxd): Submit all overlapping layer bounds as hit test regions.
     // Also investigate if we can use visible layer rect as overlapping regions.
-    overlapping_region.Union(MathUtil::MapEnclosingClippedRect(
-        layer->ScreenSpaceTransform(), gfx::Rect(layer->bounds())));
+    num_iterated_layers++;
+    if (num_iterated_layers > kAssumeOverlapThreshold)
+      assume_overlap = true;
+    if (!assume_overlap) {
+      overlapping_region.Union(MathUtil::MapEnclosingClippedRect(
+          layer->ScreenSpaceTransform(), gfx::Rect(layer->bounds())));
+    }
   }
 
   return hit_test_region_list;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 53f81ed..6602005a 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -14262,6 +14262,87 @@
             hit_test_region_list->regions[0].rect.ToString());
 }
 
+TEST_F(HitTestRegionListGeneratingLayerTreeHostImplTest, ComplexPage) {
+  // Setup surface layers in LayerTreeHostImpl.
+  host_impl_->CreatePendingTree();
+  host_impl_->ActivateSyncTree();
+
+  // The structure of the layer tree:
+  // +-Root (1024x768)
+  // +---surface_child (0, 0), 100x100
+  // +---100x non overlapping layers (110, 110), 1x1
+  std::unique_ptr<SurfaceLayerImpl> surface_child =
+      SurfaceLayerImpl::Create(host_impl_->active_tree(), 2);
+
+  host_impl_->active_tree()->SetDeviceViewportSize(gfx::Size(1024, 768));
+
+  surface_child->test_properties()->position = gfx::PointF(0, 0);
+  surface_child->SetBounds(gfx::Size(100, 100));
+  surface_child->SetDrawsContent(true);
+  surface_child->SetSurfaceHitTestable(true);
+  surface_child->SetHasPointerEventsNone(false);
+
+  viz::LocalSurfaceId child_local_surface_id(2,
+                                             base::UnguessableToken::Create());
+  viz::FrameSinkId frame_sink_id(2, 0);
+  viz::SurfaceId child_surface_id(frame_sink_id, child_local_surface_id);
+  surface_child->SetRange(viz::SurfaceRange(base::nullopt, child_surface_id),
+                          base::nullopt);
+
+  std::unique_ptr<LayerImpl> root =
+      LayerImpl::Create(host_impl_->active_tree(), 1);
+  host_impl_->active_tree()->SetRootLayerForTesting(std::move(root));
+  host_impl_->active_tree()
+      ->root_layer_for_testing()
+      ->test_properties()
+      ->AddChild(std::move(surface_child));
+
+  // Create 101 non overlapping layers.
+  for (size_t i = 0; i <= 100; ++i) {
+    std::unique_ptr<LayerImpl> layer =
+        LayerImpl::Create(host_impl_->active_tree(), i + 3);
+    layer->test_properties()->position = gfx::PointF(110, 110);
+    layer->SetBounds(gfx::Size(1, 1));
+    layer->SetDrawsContent(true);
+    host_impl_->active_tree()
+        ->root_layer_for_testing()
+        ->test_properties()
+        ->AddChild(std::move(layer));
+  }
+
+  constexpr gfx::Rect kFrameRect(0, 0, 1024, 768);
+
+  host_impl_->active_tree()->BuildPropertyTreesForTesting();
+  host_impl_->active_tree()->UpdateDrawProperties();
+  base::Optional<viz::HitTestRegionList> hit_test_region_list =
+      host_impl_->BuildHitTestData();
+  // Generating HitTestRegionList should have been enabled for this test.
+  ASSERT_TRUE(hit_test_region_list);
+
+  uint32_t expected_flags = viz::HitTestRegionFlags::kHitTestMouse |
+                            viz::HitTestRegionFlags::kHitTestTouch |
+                            viz::HitTestRegionFlags::kHitTestMine;
+  EXPECT_EQ(expected_flags, hit_test_region_list->flags);
+  EXPECT_EQ(kFrameRect, hit_test_region_list->bounds);
+  EXPECT_EQ(1u, hit_test_region_list->regions.size());
+
+  EXPECT_EQ(child_surface_id.frame_sink_id(),
+            hit_test_region_list->regions[0].frame_sink_id);
+  // Since the layer count is greater than 100, in order to save time, we do not
+  // check whether each layer overlaps the surface layer, instead, we are being
+  // conservative and make the surface layer slow hit testing.
+  expected_flags = viz::HitTestRegionFlags::kHitTestMouse |
+                   viz::HitTestRegionFlags::kHitTestTouch |
+                   viz::HitTestRegionFlags::kHitTestChildSurface |
+                   viz::HitTestRegionFlags::kHitTestAsk;
+  EXPECT_EQ(expected_flags, hit_test_region_list->regions[0].flags);
+  gfx::Transform child1_transform;
+  EXPECT_TRUE(child1_transform.ApproximatelyEqual(
+      hit_test_region_list->regions[0].transform));
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
+            hit_test_region_list->regions[0].rect.ToString());
+}
+
 TEST_F(LayerTreeHostImplTest, ImplThreadPhaseUponImplSideInvalidation) {
   LayerTreeSettings settings = DefaultSettings();
   CreateHostImpl(settings, CreateLayerTreeFrameSink());
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 8a26def4..80cfc405 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -345,8 +345,8 @@
     "//third_party/android_deps:com_google_protobuf_protobuf_lite_java",
     "//third_party/android_deps:javax_inject_javax_inject_java",
     "//third_party/android_media:android_media_java",
+    "//third_party/android_sdk:android_gcm_java",
     "//third_party/android_swipe_refresh:android_swipe_refresh_java",
-    "//third_party/android_tools:android_gcm_java",
     "//third_party/blink/public:android_mojo_bindings_java",
     "//third_party/blink/public:blink_headers_java",
     "//third_party/blink/public/mojom:android_mojo_bindings_java",
@@ -428,11 +428,7 @@
   java_files += public_tab_management_java_sources
 
   if (enable_vr) {
-    deps += [
-      ":chrome_vr_java_resources",
-      "//device/vr:java",
-      "//third_party/gvr-android-keyboard:kb_java",
-    ]
+    deps += [ ":chrome_vr_java_resources" ]
   }
   srcjar_deps += [ ":chrome_vr_android_java_enums_srcjar" ]
   if (notouch_build) {
@@ -453,9 +449,7 @@
     proguard_configs = [ "//chrome/android/features/ar/proguard_async.flags" ]
   }
 
-  processor_args_javac = [
-    "dagger.fastInit=enabled"
-  ]
+  processor_args_javac = [ "dagger.fastInit=enabled" ]
 }
 
 # This is a list of all base module java dependencies. New features should be
@@ -783,11 +777,11 @@
     "//third_party/android_deps:com_android_support_support_annotations_java",
     "//third_party/android_deps:com_google_ar_core_java",
     "//third_party/android_deps:com_google_protobuf_protobuf_lite_java",
+    "//third_party/android_sdk:android_test_base_java",
+    "//third_party/android_sdk:android_test_mock_java",
+    "//third_party/android_sdk:android_test_runner_java",
     "//third_party/android_support_test_runner:rules_java",
     "//third_party/android_support_test_runner:runner_java",
-    "//third_party/android_tools:android_test_base_java",
-    "//third_party/android_tools:android_test_mock_java",
-    "//third_party/android_tools:android_test_runner_java",
     "//third_party/blink/public:android_mojo_bindings_java",
     "//third_party/blink/public:blink_headers_java",
     "//third_party/blink/public/mojom:android_mojo_bindings_java",
@@ -968,6 +962,7 @@
         "//components/test/data/js_dialogs/render_tests/",
         "//components/test/data/permission_dialogs/render_tests/",
         "//components/test/data/vr_browser_ui/render_tests/",
+        "//components/test/data/vr_browser_video/render_tests/",
         "//third_party/gvr-android-sdk/test-apks/",
       ]
     }
@@ -1893,9 +1888,9 @@
              ":chrome_apk_pak_assets",
              ":chrome_public_base_module_java_for_test",
              "//third_party/android_support_test_runner:runner_java",
-             "//third_party/android_tools:android_test_base_java",
-             "//third_party/android_tools:android_test_mock_java",
-             "//third_party/android_tools:android_test_runner_java",
+             "//third_party/android_sdk:android_test_base_java",
+             "//third_party/android_sdk:android_test_mock_java",
+             "//third_party/android_sdk:android_test_runner_java",
            ]
     if (enable_vr) {
       # Contains VrFirstRunActivity, which is referenced by AndroidManifest.xml.
@@ -1953,7 +1948,7 @@
 
     deps = [
       ":chrome_test_vr_java",
-      "//third_party/android_tools:android_test_mock_java",
+      "//third_party/android_sdk:android_test_mock_java",
     ]
   }
 
@@ -1982,7 +1977,7 @@
 
     deps = [
       ":chrome_test_ar_java",
-      "//third_party/android_tools:android_test_mock_java",
+      "//third_party/android_sdk:android_test_mock_java",
     ]
     additional_apks = [ "//net/android:net_test_support_apk" ]
     proguard_enabled = !is_java_debug
@@ -2251,7 +2246,6 @@
     "java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java",
     "java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java",
     "java/src/org/chromium/chrome/browser/autofill/CreditCardScannerBridge.java",
-    "java/src/org/chromium/chrome/browser/autofill/PasswordGenerationPopupBridge.java",
     "java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java",
     "java/src/org/chromium/chrome/browser/autofill/PhoneNumberUtil.java",
     "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AutofillKeyboardAccessoryBridge.java",
@@ -2415,6 +2409,7 @@
     "java/src/org/chromium/chrome/browser/password_manager/AutoSigninFirstRunDialog.java",
     "java/src/org/chromium/chrome/browser/password_manager/Credential.java",
     "java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogBridge.java",
+    "java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupBridge.java",
     "java/src/org/chromium/chrome/browser/payments/CanMakePaymentQuery.java",
     "java/src/org/chromium/chrome/browser/payments/JourneyLogger.java",
     "java/src/org/chromium/chrome/browser/payments/PaymentManifestWebDataService.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index b478e64b..cee44a8 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -92,12 +92,10 @@
   "java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java",
   "java/src/org/chromium/chrome/browser/autofill/CreditCardScanner.java",
   "java/src/org/chromium/chrome/browser/autofill/CreditCardScannerBridge.java",
-  "java/src/org/chromium/chrome/browser/autofill/PasswordGenerationAdapter.java",
-  "java/src/org/chromium/chrome/browser/autofill/PasswordGenerationPopupBridge.java",
   "java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java",
   "java/src/org/chromium/chrome/browser/autofill/PhoneNumberUtil.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AutofillKeyboardAccessoryBridge.java",
-  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java",
+  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMetricsRecorder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingBridge.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java",
@@ -108,6 +106,7 @@
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java",
+  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryRecyclerViewMcp.java",
@@ -120,10 +119,12 @@
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessoryPagerAdapter.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetMediator.java",
+  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetMetricsRecorder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetProperties.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetView.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetViewBinder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/AccessorySheetTabCoordinator.java",
+  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/AccessorySheetTabMetricsRecorder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/AccessorySheetTabModel.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/AccessorySheetTabViewBinder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetCoordinator.java",
@@ -271,6 +272,7 @@
   "java/src/org/chromium/chrome/browser/compositor/layouts/content/ContentOffsetProvider.java",
   "java/src/org/chromium/chrome/browser/compositor/layouts/content/InvalidationAwareThumbnailProvider.java",
   "java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java",
+  "java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManagerHandler.java",
   "java/src/org/chromium/chrome/browser/compositor/layouts/content/TitleBitmapFactory.java",
   "java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/AreaGestureEventFilter.java",
   "java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/BlackHoleEventFilter.java",
@@ -1159,6 +1161,8 @@
   "java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogMediator.java",
   "java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogModel.java",
   "java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java",
+  "java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupAdapter.java",
+  "java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupBridge.java",
   "java/src/org/chromium/chrome/browser/payments/AddressEditor.java",
   "java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java",
   "java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java",
@@ -1629,6 +1633,8 @@
   "java/src/org/chromium/chrome/browser/usage_stats/UsageStatsBridge.java",
   "java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentActivity.java",
   "java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentDialog.java",
+  "java/src/org/chromium/chrome/browser/usage_stats/UsageStatsMetricsEvent.java",
+  "java/src/org/chromium/chrome/browser/usage_stats/UsageStatsMetricsReporter.java",
   "java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java",
   "java/src/org/chromium/chrome/browser/usage_stats/WebsiteEvent.java",
   "java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java",
diff --git a/chrome/android/features/vr/BUILD.gn b/chrome/android/features/vr/BUILD.gn
index 57b5e54c..5db06f80 100644
--- a/chrome/android/features/vr/BUILD.gn
+++ b/chrome/android/features/vr/BUILD.gn
@@ -114,13 +114,14 @@
     "//third_party/android_deps:android_arch_lifecycle_runtime_java",
     "//third_party/android_deps:com_android_support_support_annotations_java",
     "//third_party/android_deps:android_support_v7_appcompat_java",
-    "//third_party/gvr-android-keyboard:kb_java",
     "//ui/android:ui_full_java",
     "//ui/android:ui_utils_java",
   ]
 
   deps = [
     ":java_resources",
+    "//device/vr:java",
+    "//third_party/gvr-android-keyboard:kb_java",
     "//third_party/gvr-android-sdk:gvr_common_java",
   ]
 }
diff --git a/chrome/android/java/res/layout/data_reduction_main_menu_item.xml b/chrome/android/java/res/layout/data_reduction_main_menu_item.xml
index f067c22..e8f44fc 100644
--- a/chrome/android/java/res/layout/data_reduction_main_menu_item.xml
+++ b/chrome/android/java/res/layout/data_reduction_main_menu_item.xml
@@ -44,13 +44,13 @@
                 android:id="@+id/menu_item_text"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:textAppearance="@style/TextAppearance.BlackTitle2" />
+                android:textAppearance="?android:attr/textAppearanceLargePopupMenu" />
 
             <TextView
                 android:id="@+id/menu_item_summary"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:textAppearance="@style/TextAppearance.BlackBody" />
+                android:textAppearance="@style/TextAppearance.BlackHint2" />
         </LinearLayout>
 
     </FrameLayout>
diff --git a/chrome/android/java/res/layout/fre_data_reduction_proxy_lite_mode.xml b/chrome/android/java/res/layout/fre_data_reduction_proxy_lite_mode.xml
index 16abb25..ac0c95cb 100644
--- a/chrome/android/java/res/layout/fre_data_reduction_proxy_lite_mode.xml
+++ b/chrome/android/java/res/layout/fre_data_reduction_proxy_lite_mode.xml
@@ -63,7 +63,7 @@
                         android:gravity="start"
                         android:lineSpacingMultiplier="1.4"
                         android:text="@string/data_reduction_promo_summary_lite_mode"
-                        android:textAppearance="@style/TextAppearance.BlackBodyDefault" />
+                        android:textAppearance="@style/TextAppearance.BlackHint2" />
 
                     <android.support.v7.widget.SwitchCompat
                         android:id="@+id/enable_data_saver_switch"
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 12545c2..6ca2a613 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -74,6 +74,7 @@
 import org.chromium.chrome.browser.compositor.layouts.SceneChangeObserver;
 import org.chromium.chrome.browser.compositor.layouts.content.ContentOffsetProvider;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManagerHandler;
 import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsModule;
 import org.chromium.chrome.browser.contextual_suggestions.PageViewTimer;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial;
@@ -1752,8 +1753,9 @@
      * Sets the {@link TabContentManager} owned by this {@link ChromeActivity}.
      * @param tabContentManager A {@link TabContentManager} instance.
      */
-    protected void setTabContentManager(TabContentManager tabContentManager) {
+    private void setTabContentManager(TabContentManager tabContentManager) {
         mTabContentManager = tabContentManager;
+        TabContentManagerHandler.create(tabContentManager, getTabModelSelector());
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 51794e2..2a89870 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -311,6 +311,7 @@
     public static final String TRUSTED_WEB_ACTIVITY_POST_MESSAGE = "TrustedWebActivityPostMessage";
     public static final String VIDEO_PERSISTENCE = "VideoPersistence";
     public static final String UNIFIED_CONSENT = "UnifiedConsent";
+    public static final String USAGE_STATS = "UsageStats";
     public static final String VR_BROWSING_FEEDBACK = "VrBrowsingFeedback";
     public static final String USER_ACTIVATION_V2 = "UserActivationV2";
     public static final String WEB_AUTH = "WebAuthentication";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 039c3449..1a26b5c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -729,7 +729,8 @@
                 FeedProcessScopeFactory.getFeedAppLifecycle();
             }
 
-            if (BuildInfo.isAtLeastQ()) {
+            if (BuildInfo.isAtLeastQ()
+                    && ChromeFeatureList.isEnabled(ChromeFeatureList.USAGE_STATS)) {
                 UsageStatsService.getInstance().createPageViewObserver(mTabModelSelectorImpl, this);
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
index ac0afc3..0b6f549 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
@@ -103,7 +103,7 @@
                           .build();
         }
 
-        tab.initialize(null, getTabContentManager(), createTabDelegateFactory(), false, unfreeze);
+        tab.initialize(null, createTabDelegateFactory(), false, unfreeze);
         return tab;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
deleted file mode 100644
index f8b45e8..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.autofill.keyboard_accessory;
-
-import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTrigger.MANUAL_OPEN;
-import static org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
-import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabModel.AccessorySheetDataPiece.Type.PASSWORD_INFO;
-import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabModel.AccessorySheetDataPiece.getType;
-
-import android.support.annotation.Nullable;
-
-import org.chromium.base.VisibleForTesting;
-import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryCoordinator;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BarItem;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.UserInfo;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_component.AccessorySheetProperties;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabModel.AccessorySheetDataPiece;
-import org.chromium.ui.modelutil.ListModel;
-import org.chromium.ui.modelutil.ListObservable;
-import org.chromium.ui.modelutil.PropertyKey;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.modelutil.PropertyObservable;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * This class provides helpers to record metrics related to the keyboard accessory and its sheets.
- * It can set up observers to observe {@link KeyboardAccessoryProperties}-based models, {@link
- * AccessorySheetProperties}-based models or {@link ListObservable<>}s, and records metrics
- * accordingly.
- */
-public class KeyboardAccessoryMetricsRecorder {
-    public static final String UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION =
-            "KeyboardAccessory.AccessoryActionImpression";
-    public static final String UMA_KEYBOARD_ACCESSORY_ACTION_SELECTED =
-            "KeyboardAccessory.AccessoryActionSelected";
-    public static final String UMA_KEYBOARD_ACCESSORY_BAR_SHOWN =
-            "KeyboardAccessory.AccessoryBarShown";
-    public static final String UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS =
-            "KeyboardAccessory.AccessorySheetSuggestionCount";
-    public static final String UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED =
-            "KeyboardAccessory.AccessorySheetSuggestionsSelected";
-    public static final String UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED =
-            "KeyboardAccessory.AccessorySheetTriggered";
-    public static final String UMA_KEYBOARD_ACCESSORY_SHEET_TYPE_SUFFIX_PASSWORDS = "Passwords";
-
-    /**
-     * The Recorder itself should be stateless and have no need for an instance.
-     */
-    private KeyboardAccessoryMetricsRecorder() {}
-
-    /**
-     * This observer will react to changes of the {@link KeyboardAccessoryProperties} and store each
-     * impression once per visibility change.
-     */
-    private static class AccessoryBarObserver
-            implements ListObservable.ListObserver<Void>,
-                       PropertyObservable.PropertyObserver<PropertyKey> {
-        private final Set<Integer> mRecordedBarBuckets = new HashSet<>();
-        private final Set<Integer> mRecordedActionImpressions = new HashSet<>();
-        private final PropertyModel mModel;
-        private final KeyboardAccessoryCoordinator.TabSwitchingDelegate mTabSwitcher;
-
-        AccessoryBarObserver(PropertyModel keyboardAccessoryModel,
-                KeyboardAccessoryCoordinator.TabSwitchingDelegate tabSwitcher) {
-            mModel = keyboardAccessoryModel;
-            mTabSwitcher = tabSwitcher;
-        }
-
-        @Override
-        public void onPropertyChanged(
-                PropertyObservable<PropertyKey> source, @Nullable PropertyKey propertyKey) {
-            if (propertyKey == KeyboardAccessoryProperties.VISIBLE) {
-                if (mModel.get(KeyboardAccessoryProperties.VISIBLE)) {
-                    recordFirstImpression();
-                    maybeRecordBarBucket(AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS);
-                    maybeRecordBarBucket(AccessoryBarContents.WITH_TABS);
-                    recordGeneralActionTypes();
-                } else {
-                    mRecordedBarBuckets.clear();
-                    mRecordedActionImpressions.clear();
-                }
-                return;
-            }
-            if (propertyKey == KeyboardAccessoryProperties.BOTTOM_OFFSET_PX
-                    || propertyKey == KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE
-                    || propertyKey == KeyboardAccessoryProperties.SHEET_TITLE
-                    || propertyKey == KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK) {
-                return;
-            }
-            assert false : "Every property update needs to be handled explicitly!";
-        }
-
-        /**
-         * If not done yet, this records an impression for the general type of list that was added.
-         * In addition, it records impressions for each new action type that changed in the list.
-         * @param list A list of {@link BarItem}s.
-         * @param first Index of the first element that changed.
-         * @param count Number of elements starting with |first| that were added or changed.
-         */
-        private void recordUnrecordedList(ListObservable list, int first, int count) {
-            assert list
-                    == mModel.get(BAR_ITEMS) : "Tried to record metrics for unknown list " + list;
-            // Record any unrecorded type, but not more than once (i.e. one set of suggestion).
-            for (int index = first; index < first + count; ++index) {
-                KeyboardAccessoryData.Action action = mModel.get(BAR_ITEMS).get(index).getAction();
-                if (action == null) continue; // Item is no relevant action.
-                maybeRecordBarBucket(action.getActionType() == AccessoryAction.AUTOFILL_SUGGESTION
-                                ? AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS
-                                : AccessoryBarContents.WITH_ACTIONS);
-                if (mRecordedActionImpressions.add(action.getActionType())) {
-                    recordActionImpression(action.getActionType());
-                }
-            }
-        }
-
-        private void recordGeneralActionTypes() {
-            if (!mModel.get(KeyboardAccessoryProperties.VISIBLE)) return;
-            // Record any unrecorded type, but not more than once (i.e. one set of suggestion).
-            for (int index = 0; index < mModel.get(BAR_ITEMS).size(); ++index) {
-                KeyboardAccessoryData.Action action = mModel.get(BAR_ITEMS).get(index).getAction();
-                if (action == null) continue; // Item is no relevant action.
-                maybeRecordBarBucket(action.getActionType() == AccessoryAction.AUTOFILL_SUGGESTION
-                                ? AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS
-                                : AccessoryBarContents.WITH_ACTIONS);
-            }
-        }
-
-        /**
-         * Records whether the first impression of the bar contained any contents (which it should).
-         */
-        private void recordFirstImpression() {
-            if (!mRecordedBarBuckets.isEmpty()) return;
-            @AccessoryBarContents
-            int bucketToRecord = AccessoryBarContents.NO_CONTENTS;
-            for (@AccessoryBarContents int bucket = 0; bucket < AccessoryBarContents.COUNT;
-                    ++bucket) {
-                if (shouldRecordAccessoryBarImpression(bucket)) {
-                    bucketToRecord = AccessoryBarContents.ANY_CONTENTS;
-                    break;
-                }
-            }
-            maybeRecordBarBucket(bucketToRecord);
-        }
-
-        @Override
-        public void onItemRangeInserted(ListObservable source, int index, int count) {
-            recordUnrecordedList(source, index, count);
-        }
-
-        @Override
-        public void onItemRangeRemoved(ListObservable source, int index, int count) {}
-
-        @Override
-        public void onItemRangeChanged(
-                ListObservable<Void> source, int index, int count, @Nullable Void payload) {
-            // Remove all actions that were changed, so changes are treated as new recordings.
-            for (int i = index; i < index + count; ++i) {
-                KeyboardAccessoryData.Action action = mModel.get(BAR_ITEMS).get(i).getAction();
-                if (action == null) continue; // Item is no recordable action.
-                mRecordedActionImpressions.remove(action.getActionType());
-            }
-            recordUnrecordedList(source, index, count);
-        }
-
-        /**
-         * Returns an impression for the accessory bar if it hasn't occurred yet.
-         * @param bucket The bucket to record.
-         */
-        private void maybeRecordBarBucket(@AccessoryBarContents int bucket) {
-            if (!shouldRecordAccessoryBarImpression(bucket)) return;
-            mRecordedBarBuckets.add(bucket);
-            RecordHistogram.recordEnumeratedHistogram(
-                    UMA_KEYBOARD_ACCESSORY_BAR_SHOWN, bucket, AccessoryBarContents.COUNT);
-        }
-
-        /**
-         * If a checks whether the given bucket should be recorded (i.e. the property it observes is
-         * not empty, the accessory is visible and it wasn't recorded yet).
-         * @param bucket
-         * @return
-         */
-        private boolean shouldRecordAccessoryBarImpression(int bucket) {
-            if (!mModel.get(KeyboardAccessoryProperties.VISIBLE)) return false;
-            if (mRecordedBarBuckets.contains(bucket)) return false;
-            switch (bucket) {
-                case AccessoryBarContents.WITH_ACTIONS:
-                    return hasAtLeastOneActionOfType(mModel.get(BAR_ITEMS),
-                            AccessoryAction.MANAGE_PASSWORDS,
-                            AccessoryAction.GENERATE_PASSWORD_AUTOMATIC);
-                case AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS:
-                    return hasAtLeastOneActionOfType(
-                            mModel.get(BAR_ITEMS), AccessoryAction.AUTOFILL_SUGGESTION);
-                case AccessoryBarContents.WITH_TABS:
-                    return mTabSwitcher.hasTabs();
-                case AccessoryBarContents.ANY_CONTENTS: // Intentional fallthrough.
-                case AccessoryBarContents.NO_CONTENTS:
-                    return true; // Logged on first impression.
-            }
-            assert false : "Did not check whether to record an impression bucket " + bucket + ".";
-            return false;
-        }
-    }
-
-    /**
-     * Registers an observer to the given model that records changes for all properties.
-     * @param keyboardAccessoryModel The observable {@link KeyboardAccessoryProperties}.
-     */
-    public static void registerKeyboardAccessoryModelMetricsObserver(
-            PropertyModel keyboardAccessoryModel,
-            KeyboardAccessoryCoordinator.TabSwitchingDelegate tabSwitcher) {
-        AccessoryBarObserver observer =
-                new AccessoryBarObserver(keyboardAccessoryModel, tabSwitcher);
-        keyboardAccessoryModel.addObserver(observer);
-        keyboardAccessoryModel.get(BAR_ITEMS).addObserver(observer);
-    }
-
-    /**
-     * Registers an observer to the given model that records changes for all properties.
-     * @param accessorySheetModel The observable {@link AccessorySheetProperties}.
-     */
-    public static void registerAccessorySheetModelMetricsObserver(
-            PropertyModel accessorySheetModel) {
-        accessorySheetModel.addObserver((source, propertyKey) -> {
-            if (propertyKey == AccessorySheetProperties.VISIBLE) {
-                if (accessorySheetModel.get(AccessorySheetProperties.VISIBLE)) {
-                    int activeTab =
-                            accessorySheetModel.get(AccessorySheetProperties.ACTIVE_TAB_INDEX);
-                    if (activeTab >= 0
-                            && activeTab < accessorySheetModel.get(AccessorySheetProperties.TABS)
-                                                   .size()) {
-                        recordSheetTrigger(accessorySheetModel.get(AccessorySheetProperties.TABS)
-                                                   .get(activeTab)
-                                                   .getRecordingType(),
-                                MANUAL_OPEN);
-                    }
-                } else {
-                    recordSheetTrigger(AccessoryTabType.ALL, AccessorySheetTrigger.ANY_CLOSE);
-                }
-                return;
-            }
-            if (propertyKey == AccessorySheetProperties.ACTIVE_TAB_INDEX
-                    || propertyKey == AccessorySheetProperties.HEIGHT
-                    || propertyKey == AccessorySheetProperties.TOP_SHADOW_VISIBLE
-                    || propertyKey == AccessorySheetProperties.PAGE_CHANGE_LISTENER) {
-                return;
-            }
-            assert false : "Every property update needs to be handled explicitly!";
-        });
-    }
-
-    /**
-     * Gets the complete name of a histogram for the given tab type.
-     * @param baseHistogram the base histogram.
-     * @param tabType The tab type that determines the histogram's suffix.
-     * @return The complete name of the histogram.
-     */
-    @VisibleForTesting
-    public static String getHistogramForType(String baseHistogram, @AccessoryTabType int tabType) {
-        switch (tabType) {
-            case AccessoryTabType.ALL:
-                return baseHistogram;
-            case AccessoryTabType.PASSWORDS:
-                return baseHistogram + "." + UMA_KEYBOARD_ACCESSORY_SHEET_TYPE_SUFFIX_PASSWORDS;
-        }
-        assert false : "Undefined histogram for tab type " + tabType + " !";
-        return "";
-    }
-
-    /**
-     * Records why an accessory sheet was toggled.
-     * @param tabType The tab that was selected to trigger the sheet.
-     * @param bucket The {@link AccessorySheetTrigger} to record..
-     */
-    public static void recordSheetTrigger(
-            @AccessoryTabType int tabType, @AccessorySheetTrigger int bucket) {
-        // TODO(crbug.com/926372): Add metrics capabilities for credit cards.
-        if (tabType == AccessoryTabType.CREDIT_CARDS) return;
-
-        RecordHistogram.recordEnumeratedHistogram(
-                getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED, tabType), bucket,
-                AccessorySheetTrigger.COUNT);
-        if (tabType != AccessoryTabType.ALL) { // Record count for all tab types exactly once!
-            RecordHistogram.recordEnumeratedHistogram(
-                    getHistogramForType(
-                            UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED, AccessoryTabType.ALL),
-                    bucket, AccessorySheetTrigger.COUNT);
-        }
-    }
-
-    public static void recordActionImpression(@AccessoryAction int bucket) {
-        RecordHistogram.recordEnumeratedHistogram(
-                UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION, bucket, AccessoryAction.COUNT);
-    }
-
-    public static void recordActionSelected(@AccessoryAction int bucket) {
-        RecordHistogram.recordEnumeratedHistogram(
-                UMA_KEYBOARD_ACCESSORY_ACTION_SELECTED, bucket, AccessoryAction.COUNT);
-    }
-
-    static void recordSuggestionSelected(
-            @AccessoryTabType int tabType, @AccessorySuggestionType int bucket) {
-        // TODO(crbug.com/926372): Add metrics capabilities for credit cards.
-        if (tabType == AccessoryTabType.CREDIT_CARDS) return;
-
-        RecordHistogram.recordEnumeratedHistogram(
-                getHistogramForType(
-                        UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED, AccessoryTabType.ALL),
-                bucket, AccessorySuggestionType.COUNT);
-        if (tabType != AccessoryTabType.ALL) { // If recorded for all, don't record again.
-            RecordHistogram.recordEnumeratedHistogram(
-                    getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED, tabType),
-                    bucket, AccessorySuggestionType.COUNT);
-        }
-    }
-
-    /**
-     * Records the number of interactive suggestions in the given list.
-     * @param tabType The tab that contained the list.
-     * @param suggestionList The list containing all suggestions.
-     */
-    public static void recordSheetSuggestions(
-            @AccessoryTabType int tabType, ListModel<AccessorySheetDataPiece> suggestionList) {
-        // TODO(crbug.com/926372): Add metrics capabilities for credit cards.
-        if (tabType == AccessoryTabType.CREDIT_CARDS) return;
-
-        int interactiveSuggestions = 0;
-        for (int i = 0; i < suggestionList.size(); ++i) {
-            if (getType(suggestionList.get(i)) == PASSWORD_INFO) {
-                UserInfo info = (UserInfo) suggestionList.get(i).getDataPiece();
-                for (UserInfo.Field field : info.getFields()) {
-                    if (field.isSelectable()) ++interactiveSuggestions;
-                }
-            }
-        }
-        RecordHistogram.recordCount100Histogram(
-                getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS, tabType),
-                interactiveSuggestions);
-        if (tabType != AccessoryTabType.ALL) { // Record count for all tab types exactly once!
-            RecordHistogram.recordCount100Histogram(
-                    getHistogramForType(
-                            UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS, AccessoryTabType.ALL),
-                    interactiveSuggestions);
-        }
-    }
-
-    private static boolean hasAtLeastOneActionOfType(
-            ListModel<BarItem> itemList, @AccessoryAction int... types) {
-        Set<Integer> typeList = new HashSet<>(types.length);
-        for (@AccessoryAction int type : types) typeList.add(type);
-        for (BarItem barItem : itemList) {
-            if (barItem.getAction() == null) continue; // Item irrelevant for recording.
-            if (typeList.contains(barItem.getAction().getActionType())) return true;
-        }
-        return false;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingBridge.java
index c8dec34..88a4193 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingBridge.java
@@ -64,7 +64,7 @@
                         assert mNativeView
                                 != 0
                             : "Controller has been destroyed but the bridge wasn't cleaned up!";
-                        KeyboardAccessoryMetricsRecorder.recordActionSelected(
+                        ManualFillingMetricsRecorder.recordActionSelected(
                                 AccessoryAction.GENERATE_PASSWORD_AUTOMATIC);
                         nativeOnGenerationRequested(mNativeView);
                     })};
@@ -119,8 +119,7 @@
         if (selectable) {
             callback = (field) -> {
                 assert mNativeView != 0 : "Controller was destroyed but the bridge wasn't!";
-                KeyboardAccessoryMetricsRecorder.recordSuggestionSelected(
-                        AccessoryTabType.PASSWORDS,
+                ManualFillingMetricsRecorder.recordSuggestionSelected(AccessoryTabType.PASSWORDS,
                         field.isObfuscated() ? AccessorySuggestionType.PASSWORD
                                              : AccessorySuggestionType.USERNAME);
                 nativeOnFillingTriggered(mNativeView, field.isObfuscated(), field.getDisplayText());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMetricsRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMetricsRecorder.java
new file mode 100644
index 0000000..7b83a1de
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMetricsRecorder.java
@@ -0,0 +1,104 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill.keyboard_accessory;
+
+import org.chromium.base.metrics.RecordHistogram;
+
+/**
+ * This class provides helpers to record metrics related to the keyboard accessory and its sheets.
+ */
+public class ManualFillingMetricsRecorder {
+    public static final String UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION =
+            "KeyboardAccessory.AccessoryActionImpression";
+    public static final String UMA_KEYBOARD_ACCESSORY_ACTION_SELECTED =
+            "KeyboardAccessory.AccessoryActionSelected";
+    public static final String UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED =
+            "KeyboardAccessory.AccessorySheetTriggered";
+    private static final String UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED =
+            "KeyboardAccessory.AccessorySheetSuggestionsSelected";
+    private static final String UMA_KEYBOARD_ACCESSORY_SHEET_TYPE_SUFFIX_PASSWORDS = "Passwords";
+
+    /**
+     * The Recorder itself should be stateless and have no need for an instance.
+     */
+    private ManualFillingMetricsRecorder() {}
+
+    /**
+     * Gets the complete name of a histogram for the given tab type.
+     * @param baseHistogram the base histogram.
+     * @param tabType The tab type that determines the histogram's suffix.
+     * @return The complete name of the histogram.
+     */
+    public static String getHistogramForType(String baseHistogram, @AccessoryTabType int tabType) {
+        switch (tabType) {
+            case AccessoryTabType.ALL:
+                return baseHistogram;
+            case AccessoryTabType.PASSWORDS:
+                return baseHistogram + "." + UMA_KEYBOARD_ACCESSORY_SHEET_TYPE_SUFFIX_PASSWORDS;
+        }
+        assert false : "Undefined histogram for tab type " + tabType + " !";
+        return "";
+    }
+
+    /**
+     * Records why an accessory sheet was toggled.
+     * @param tabType The tab that was selected to trigger the sheet.
+     * @param bucket The {@link AccessorySheetTrigger} to record.
+     */
+    public static void recordSheetTrigger(
+            @AccessoryTabType int tabType, @AccessorySheetTrigger int bucket) {
+        // TODO(crbug.com/926372): Add metrics capabilities for credit cards.
+        if (tabType == AccessoryTabType.CREDIT_CARDS) return;
+
+        RecordHistogram.recordEnumeratedHistogram(
+                getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED, tabType), bucket,
+                AccessorySheetTrigger.COUNT);
+        if (tabType != AccessoryTabType.ALL) { // Record count for all tab types exactly once!
+            RecordHistogram.recordEnumeratedHistogram(
+                    getHistogramForType(
+                            UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED, AccessoryTabType.ALL),
+                    bucket, AccessorySheetTrigger.COUNT);
+        }
+    }
+
+    /**
+     * Records a selected action.
+     * @param bucket An {@link AccessoryAction}.
+     */
+    public static void recordActionSelected(@AccessoryAction int bucket) {
+        RecordHistogram.recordEnumeratedHistogram(
+                UMA_KEYBOARD_ACCESSORY_ACTION_SELECTED, bucket, AccessoryAction.COUNT);
+    }
+
+    /**
+     * Records an impression for a single action.
+     * @param bucket An {@link AccessoryAction} that was just impressed.
+     */
+    public static void recordActionImpression(@AccessoryAction int bucket) {
+        RecordHistogram.recordEnumeratedHistogram(
+                UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION, bucket, AccessoryAction.COUNT);
+    }
+
+    /**
+     * Records a selected suggestions.
+     * @param tabType The sheet to record for. An {@link AccessoryTabType}.
+     * @param bucket An {@link AccessoryAction}.
+     */
+    static void recordSuggestionSelected(
+            @AccessoryTabType int tabType, @AccessorySuggestionType int bucket) {
+        // TODO(crbug.com/926372): Add metrics capabilities for credit cards.
+        if (tabType == AccessoryTabType.CREDIT_CARDS) return;
+
+        RecordHistogram.recordEnumeratedHistogram(
+                getHistogramForType(
+                        UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED, AccessoryTabType.ALL),
+                bucket, AccessorySuggestionType.COUNT);
+        if (tabType != AccessoryTabType.ALL) { // If recorded for all, don't record again.
+            RecordHistogram.recordEnumeratedHistogram(
+                    getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED, tabType),
+                    bucket, AccessorySuggestionType.COUNT);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
index 918f238..539afef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
@@ -13,7 +13,6 @@
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryMetricsRecorder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BarItem;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryViewBinder.BarItemViewHolder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
index e96a903..b5e290e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component;
 
-import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTrigger.MANUAL_CLOSE;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE;
@@ -19,7 +18,8 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryMetricsRecorder;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTrigger;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryCoordinator.TabSwitchingDelegate;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryCoordinator.VisibilityDelegate;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.AutofillBarItem;
@@ -148,7 +148,7 @@
         return new KeyboardAccessoryData.Action(
                 null, // Unused. The AutofillSuggestion has more meaningful labels.
                 AccessoryAction.AUTOFILL_SUGGESTION, result -> {
-                    KeyboardAccessoryMetricsRecorder.recordActionSelected(
+                    ManualFillingMetricsRecorder.recordActionSelected(
                             AccessoryAction.AUTOFILL_SUGGESTION);
                     delegate.suggestionSelected(pos);
                 });
@@ -256,8 +256,8 @@
 
     private void closeSheet() {
         assert mTabSwitcher.getActiveTab() != null;
-        KeyboardAccessoryMetricsRecorder.recordSheetTrigger(
-                mTabSwitcher.getActiveTab().getRecordingType(), MANUAL_CLOSE);
+        ManualFillingMetricsRecorder.recordSheetTrigger(
+                mTabSwitcher.getActiveTab().getRecordingType(), AccessorySheetTrigger.MANUAL_CLOSE);
         mModel.set(KEYBOARD_TOGGLE_VISIBLE, false);
         mVisibilityDelegate.onOpenKeyboard(); // This will close the active tab gently.
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
new file mode 100644
index 0000000..d8ba950
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
@@ -0,0 +1,214 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component;
+
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.VISIBLE;
+
+import android.support.annotation.Nullable;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryBarContents;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BarItem;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData;
+import org.chromium.ui.modelutil.ListModel;
+import org.chromium.ui.modelutil.ListObservable;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyObservable;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class provides helpers to record metrics related to the keyboard accessory bar.
+ * It sets up an observer to observe {@link KeyboardAccessoryProperties}-based models and records
+ * metrics accordingly.
+ */
+class KeyboardAccessoryMetricsRecorder {
+    static final String UMA_KEYBOARD_ACCESSORY_BAR_SHOWN = "KeyboardAccessory.AccessoryBarShown";
+
+    /**
+     * The Recorder itself should be stateless and have no need for an instance.
+     */
+    private KeyboardAccessoryMetricsRecorder() {}
+
+    /**
+     * This observer will react to changes of the {@link KeyboardAccessoryProperties} and store each
+     * impression once per visibility change.
+     */
+    private static class AccessoryBarObserver
+            implements ListObservable.ListObserver<Void>,
+                       PropertyObservable.PropertyObserver<PropertyKey> {
+        private final Set<Integer> mRecordedBarBuckets = new HashSet<>();
+        private final Set<Integer> mRecordedActionImpressions = new HashSet<>();
+        private final PropertyModel mModel;
+        private final KeyboardAccessoryCoordinator.TabSwitchingDelegate mTabSwitcher;
+
+        AccessoryBarObserver(PropertyModel keyboardAccessoryModel,
+                KeyboardAccessoryCoordinator.TabSwitchingDelegate tabSwitcher) {
+            mModel = keyboardAccessoryModel;
+            mTabSwitcher = tabSwitcher;
+        }
+
+        @Override
+        public void onPropertyChanged(
+                PropertyObservable<PropertyKey> source, @Nullable PropertyKey propertyKey) {
+            if (propertyKey == VISIBLE) {
+                if (mModel.get(VISIBLE)) {
+                    recordFirstImpression();
+                    maybeRecordBarBucket(AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS);
+                    maybeRecordBarBucket(AccessoryBarContents.WITH_TABS);
+                    recordGeneralActionTypes();
+                } else {
+                    mRecordedBarBuckets.clear();
+                    mRecordedActionImpressions.clear();
+                }
+                return;
+            }
+            if (propertyKey == KeyboardAccessoryProperties.BOTTOM_OFFSET_PX
+                    || propertyKey == KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE
+                    || propertyKey == KeyboardAccessoryProperties.SHEET_TITLE
+                    || propertyKey == KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK) {
+                return;
+            }
+            assert false : "Every property update needs to be handled explicitly!";
+        }
+
+        /**
+         * If not done yet, this records an impression for the general type of list that was added.
+         * In addition, it records impressions for each new action type that changed in the list.
+         * @param l A list of {@link BarItem}s. Must be equal to the observed models list.
+         * @param first Index of the first element that changed.
+         * @param count Number of elements starting with |first| that were added or changed.
+         */
+        private void recordUnrecordedList(ListObservable l, int first, int count) {
+            assert l == mModel.get(BAR_ITEMS) : "Tried to record metrics for unknown list " + l;
+            // Record any unrecorded type, but not more than once (i.e. one set of suggestion).
+            for (int index = first; index < first + count; ++index) {
+                KeyboardAccessoryData.Action action = mModel.get(BAR_ITEMS).get(index).getAction();
+                if (action == null) continue; // Item is no relevant action.
+                maybeRecordBarBucket(action.getActionType() == AccessoryAction.AUTOFILL_SUGGESTION
+                                ? AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS
+                                : AccessoryBarContents.WITH_ACTIONS);
+                if (mRecordedActionImpressions.add(action.getActionType())) {
+                    ManualFillingMetricsRecorder.recordActionImpression(action.getActionType());
+                }
+            }
+        }
+
+        private void recordGeneralActionTypes() {
+            if (!mModel.get(VISIBLE)) return;
+            // Record any unrecorded type, but not more than once (i.e. one set of suggestion).
+            for (int index = 0; index < mModel.get(BAR_ITEMS).size(); ++index) {
+                KeyboardAccessoryData.Action action = mModel.get(BAR_ITEMS).get(index).getAction();
+                if (action == null) continue; // Item is no relevant action.
+                maybeRecordBarBucket(action.getActionType() == AccessoryAction.AUTOFILL_SUGGESTION
+                                ? AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS
+                                : AccessoryBarContents.WITH_ACTIONS);
+            }
+        }
+
+        /**
+         * Records whether the first impression of the bar contained any contents (which it should).
+         */
+        private void recordFirstImpression() {
+            if (!mRecordedBarBuckets.isEmpty()) return;
+            @AccessoryBarContents
+            int bucketToRecord = AccessoryBarContents.NO_CONTENTS;
+            for (@AccessoryBarContents int bucket = 0; bucket < AccessoryBarContents.COUNT;
+                    ++bucket) {
+                if (shouldRecordAccessoryBarImpression(bucket)) {
+                    bucketToRecord = AccessoryBarContents.ANY_CONTENTS;
+                    break;
+                }
+            }
+            maybeRecordBarBucket(bucketToRecord);
+        }
+
+        @Override
+        public void onItemRangeInserted(ListObservable source, int index, int count) {
+            recordUnrecordedList(source, index, count);
+        }
+
+        @Override
+        public void onItemRangeRemoved(ListObservable source, int index, int count) {}
+
+        @Override
+        public void onItemRangeChanged(
+                ListObservable<Void> source, int index, int count, @Nullable Void payload) {
+            // Remove all actions that were changed, so changes are treated as new recordings.
+            for (int i = index; i < index + count; ++i) {
+                KeyboardAccessoryData.Action action = mModel.get(BAR_ITEMS).get(i).getAction();
+                if (action == null) continue; // Item is no recordable action.
+                mRecordedActionImpressions.remove(action.getActionType());
+            }
+            recordUnrecordedList(source, index, count);
+        }
+
+        /**
+         * Returns an impression for the accessory bar if it hasn't occurred yet.
+         * @param bucket The bucket to record.
+         */
+        private void maybeRecordBarBucket(@AccessoryBarContents int bucket) {
+            if (!shouldRecordAccessoryBarImpression(bucket)) return;
+            mRecordedBarBuckets.add(bucket);
+            RecordHistogram.recordEnumeratedHistogram(
+                    UMA_KEYBOARD_ACCESSORY_BAR_SHOWN, bucket, AccessoryBarContents.COUNT);
+        }
+
+        /**
+         * If a checks whether the given bucket should be recorded (i.e. the property it observes is
+         * not empty, the accessory is visible and it wasn't recorded yet).
+         * @param bucket
+         * @return
+         */
+        private boolean shouldRecordAccessoryBarImpression(int bucket) {
+            if (!mModel.get(VISIBLE)) return false;
+            if (mRecordedBarBuckets.contains(bucket)) return false;
+            switch (bucket) {
+                case AccessoryBarContents.WITH_ACTIONS:
+                    return hasAtLeastOneActionOfType(mModel.get(BAR_ITEMS),
+                            AccessoryAction.MANAGE_PASSWORDS,
+                            AccessoryAction.GENERATE_PASSWORD_AUTOMATIC);
+                case AccessoryBarContents.WITH_AUTOFILL_SUGGESTIONS:
+                    return hasAtLeastOneActionOfType(
+                            mModel.get(BAR_ITEMS), AccessoryAction.AUTOFILL_SUGGESTION);
+                case AccessoryBarContents.WITH_TABS:
+                    return mTabSwitcher.hasTabs();
+                case AccessoryBarContents.ANY_CONTENTS: // Intentional fallthrough.
+                case AccessoryBarContents.NO_CONTENTS:
+                    return true; // Logged on first impression.
+            }
+            assert false : "Did not check whether to record an impression bucket " + bucket + ".";
+            return false;
+        }
+    }
+
+    /**
+     * Registers an observer to the given model that records changes for all properties.
+     * @param keyboardAccessoryModel The observable {@link KeyboardAccessoryProperties}.
+     */
+    static void registerKeyboardAccessoryModelMetricsObserver(PropertyModel keyboardAccessoryModel,
+            KeyboardAccessoryCoordinator.TabSwitchingDelegate tabSwitcher) {
+        AccessoryBarObserver observer =
+                new AccessoryBarObserver(keyboardAccessoryModel, tabSwitcher);
+        keyboardAccessoryModel.addObserver(observer);
+        keyboardAccessoryModel.get(BAR_ITEMS).addObserver(observer);
+    }
+
+    private static boolean hasAtLeastOneActionOfType(
+            ListModel<BarItem> itemList, @AccessoryAction int... types) {
+        Set<Integer> typeList = new HashSet<>(types.length);
+        for (@AccessoryAction int type : types) typeList.add(type);
+        for (BarItem barItem : itemList) {
+            if (barItem.getAction() == null) continue; // Item irrelevant for recording.
+            if (typeList.contains(barItem.getAction().getActionType())) return true;
+        }
+        return false;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java
index 5dd9c70..db19bd1f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java
@@ -20,7 +20,6 @@
 import android.view.View;
 
 import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryMetricsRecorder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData;
 import org.chromium.ui.ViewProvider;
 import org.chromium.ui.modelutil.LazyConstructionPropertyMcp;
@@ -55,7 +54,7 @@
         LazyConstructionPropertyMcp.create(
                 model, VISIBLE, viewProvider, AccessorySheetViewBinder::bind);
 
-        KeyboardAccessoryMetricsRecorder.registerAccessorySheetModelMetricsObserver(model);
+        AccessorySheetMetricsRecorder.registerAccessorySheetModelMetricsObserver(model);
         mMediator = new AccessorySheetMediator(model);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetMetricsRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetMetricsRecorder.java
new file mode 100644
index 0000000..6afc9ee
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetMetricsRecorder.java
@@ -0,0 +1,55 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_component;
+
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTrigger.MANUAL_OPEN;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder.recordSheetTrigger;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_component.AccessorySheetProperties.ACTIVE_TAB_INDEX;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_component.AccessorySheetProperties.TABS;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_component.AccessorySheetProperties.VISIBLE;
+
+import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTrigger;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryTabType;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * This class provides helpers to record general metrics about accessory sheets.
+ * It sets up an observers to observe {@link AccessorySheetProperties}-based models and records
+ * metrics accordingly.
+ */
+class AccessorySheetMetricsRecorder {
+    /**
+     * The Recorder itself should be stateless and have no need for an instance.
+     */
+    private AccessorySheetMetricsRecorder() {}
+
+    /**
+     * Registers an observer to the given model that records changes for all properties.
+     * @param accessorySheetModel The observable {@link AccessorySheetProperties}.
+     */
+    static void registerAccessorySheetModelMetricsObserver(PropertyModel accessorySheetModel) {
+        accessorySheetModel.addObserver((source, propertyKey) -> {
+            if (propertyKey == VISIBLE) {
+                if (accessorySheetModel.get(VISIBLE)) {
+                    int activeTab = accessorySheetModel.get(ACTIVE_TAB_INDEX);
+                    if (activeTab >= 0 && activeTab < accessorySheetModel.get(TABS).size()) {
+                        recordSheetTrigger(
+                                accessorySheetModel.get(TABS).get(activeTab).getRecordingType(),
+                                MANUAL_OPEN);
+                    }
+                } else {
+                    recordSheetTrigger(AccessoryTabType.ALL, AccessorySheetTrigger.ANY_CLOSE);
+                }
+                return;
+            }
+            if (propertyKey == ACTIVE_TAB_INDEX || propertyKey == AccessorySheetProperties.HEIGHT
+                    || propertyKey == AccessorySheetProperties.TOP_SHADOW_VISIBLE
+                    || propertyKey == AccessorySheetProperties.PAGE_CHANGE_LISTENER) {
+                return;
+            }
+            assert false : "Every property update needs to be handled explicitly!";
+        });
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/AccessorySheetTabMetricsRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/AccessorySheetTabMetricsRecorder.java
new file mode 100644
index 0000000..861e720
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/AccessorySheetTabMetricsRecorder.java
@@ -0,0 +1,57 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs;
+
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder.getHistogramForType;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabModel.AccessorySheetDataPiece.Type.PASSWORD_INFO;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabModel.AccessorySheetDataPiece.getType;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryTabType;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.UserInfo;
+import org.chromium.ui.modelutil.ListModel;
+
+/**
+ * This class provides helpers to record metrics related to a specific accessory sheet tab.
+ */
+class AccessorySheetTabMetricsRecorder {
+    static final String UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS =
+            "KeyboardAccessory.AccessorySheetSuggestionCount";
+
+    /**
+     * The Recorder itself should be stateless and have no need for an instance.
+     */
+    private AccessorySheetTabMetricsRecorder() {}
+
+    /**
+     * Records the number of interactive suggestions in the given list.
+     * @param tabType The tab that contained the list.
+     * @param suggestionList The list containing all suggestions.
+     */
+    static void recordSheetSuggestions(@AccessoryTabType int tabType,
+            ListModel<AccessorySheetTabModel.AccessorySheetDataPiece> suggestionList) {
+        // TODO(crbug.com/926372): Add metrics capabilities for credit cards.
+        if (tabType == AccessoryTabType.CREDIT_CARDS) return;
+
+        int interactiveSuggestions = 0;
+        for (int i = 0; i < suggestionList.size(); ++i) {
+            if (getType(suggestionList.get(i)) == PASSWORD_INFO) {
+                UserInfo info = (UserInfo) suggestionList.get(i).getDataPiece();
+                for (UserInfo.Field field : info.getFields()) {
+                    if (field.isSelectable()) ++interactiveSuggestions;
+                }
+            }
+        }
+        RecordHistogram.recordCount100Histogram(
+                getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS, tabType),
+                interactiveSuggestions);
+        if (tabType != AccessoryTabType.ALL) { // Record count for all tab types exactly once!
+            RecordHistogram.recordCount100Histogram(
+                    getHistogramForType(
+                            UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS, AccessoryTabType.ALL),
+                    interactiveSuggestions);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/PasswordAccessorySheetMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/PasswordAccessorySheetMediator.java
index 80b095b..1ee9255a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/PasswordAccessorySheetMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/PasswordAccessorySheetMediator.java
@@ -7,7 +7,7 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryTabType;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryMetricsRecorder;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.AccessorySheetData;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.FooterCommand;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.UserInfo;
@@ -38,8 +38,8 @@
     }
 
     void onTabShown() {
-        KeyboardAccessoryMetricsRecorder.recordActionImpression(AccessoryAction.MANAGE_PASSWORDS);
-        KeyboardAccessoryMetricsRecorder.recordSheetSuggestions(AccessoryTabType.PASSWORDS, mModel);
+        ManualFillingMetricsRecorder.recordActionImpression(AccessoryAction.MANAGE_PASSWORDS);
+        AccessorySheetTabMetricsRecorder.recordSheetSuggestions(AccessoryTabType.PASSWORDS, mModel);
     }
 
     private AccessorySheetDataPiece[] splitIntoDataPieces(AccessorySheetData accessorySheetData) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsTabCreatorManager.java b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsTabCreatorManager.java
index 2888b7e..8ba36c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsTabCreatorManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsTabCreatorManager.java
@@ -52,7 +52,7 @@
                               .setWindow(windowAndroid)
                               .setLaunchType(type)
                               .build();
-            tab.initialize(null, null, new TabDelegateFactory(), true, false);
+            tab.initialize(null, new TabDelegateFactory(), true, false);
             mTabModel.addTab(tab, -1, type);
             return tab;
         }
@@ -65,7 +65,7 @@
                               .setId(id)
                               .setWindow(windowAndroid)
                               .build();
-            tab.initialize(null, null, new TabDelegateFactory(), true, false);
+            tab.initialize(null, new TabDelegateFactory(), true, false);
             mTabModel.addTab(tab, index, TabLaunchType.FROM_RESTORE);
             return tab;
         }
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 35a6458..3d6b1c7 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
@@ -136,6 +136,24 @@
     }
 
     /**
+     * Attach the given Tab's cc layer to this {@link TabContentManager}.
+     * @param tab Tab whose cc layer will be attached.
+     */
+    public void attachTab(Tab tab) {
+        if (mNativeTabContentManager == 0) return;
+        nativeAttachTab(mNativeTabContentManager, tab, tab.getId());
+    }
+
+    /**
+     * Detach the given Tab's cc layer from this {@link TabContentManager}.
+     * @param tab Tab whose cc layer will be detached.
+     */
+    public void detachTab(Tab tab) {
+        if (mNativeTabContentManager == 0) return;
+        nativeDetachTab(mNativeTabContentManager, tab, tab.getId());
+    }
+
+    /**
      * Add a listener to thumbnail changes.
      * @param listener The listener of thumbnail change events.
      */
@@ -310,6 +328,8 @@
     // Class Object Methods
     private native long nativeInit(int defaultCacheSize, int approximationCacheSize,
             int compressionQueueMaxSize, int writeQueueMaxSize, boolean useApproximationThumbnail);
+    private native void nativeAttachTab(long nativeTabContentManager, Tab tab, int tabId);
+    private native void nativeDetachTab(long nativeTabContentManager, Tab tab, int tabId);
     private native boolean nativeHasFullCachedThumbnail(long nativeTabContentManager, int tabId);
     private native void nativeCacheTab(
             long nativeTabContentManager, Object tab, float thumbnailScale);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManagerHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManagerHandler.java
new file mode 100644
index 0000000..47483266
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManagerHandler.java
@@ -0,0 +1,64 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.compositor.layouts.content;
+
+import org.chromium.chrome.browser.fullscreen.FullscreenOptions;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
+
+/**
+ * Helper class attaching Tab's content layer to {@link TabContentManager}.
+ */
+public final class TabContentManagerHandler extends TabModelSelectorTabObserver {
+    private final TabContentManager mTabContentManager;
+
+    // Indicates that thumbnail cache should be removed when tab becomes interactive.
+    // Used when a request is made while a tab is not in interactive state so
+    // the job should be done in a delayed manner.
+    private boolean mShouldRemoveThumbnail;
+
+    // A tab whose thumbnail needs to be removed.
+    private Tab mThumbnailTab;
+
+    public static void create(TabContentManager manager, TabModelSelector selector) {
+        new TabContentManagerHandler(manager, selector);
+    }
+
+    private TabContentManagerHandler(TabContentManager manager, TabModelSelector selector) {
+        super(selector);
+        mTabContentManager = manager;
+    }
+
+    @Override
+    public void onTabRegistered(Tab tab) {
+        // TODO(dtrainor): Remove this and move to a pull model instead of pushing the layer
+        mTabContentManager.attachTab(tab);
+    }
+
+    @Override
+    public void onTabUnregistered(Tab tab) {
+        mTabContentManager.detachTab(tab);
+    }
+
+    @Override
+    public void onInteractabilityChanged(boolean interactable) {
+        if (interactable && mShouldRemoveThumbnail && mThumbnailTab != null) {
+            mTabContentManager.removeTabThumbnail(mThumbnailTab.getId());
+            mShouldRemoveThumbnail = false;
+            mThumbnailTab = null;
+        }
+    }
+
+    @Override
+    public void onEnterFullscreenMode(Tab tab, final FullscreenOptions options) {
+        if (!tab.isUserInteractable()) {
+            mTabContentManager.removeTabThumbnail(tab.getId());
+        } else {
+            mThumbnailTab = tab;
+            mShouldRemoveThumbnail = true;
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/HiddenTabHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/HiddenTabHolder.java
index 92114da0..caaeb7ff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/HiddenTabHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/HiddenTabHolder.java
@@ -117,7 +117,7 @@
                           .setWindow(new WindowAndroid(context))
                           .setLaunchType(TabLaunchType.FROM_SPECULATIVE_BACKGROUND_CREATION)
                           .build();
-        tab.initialize(null, null, CustomTabDelegateFactory.createDummy(), true, false);
+        tab.initialize(null, CustomTabDelegateFactory.createDummy(), true, false);
 
         // Resize the webContent to avoid expensive post load resize when attaching the tab.
         Rect bounds = ExternalPrerenderHandler.estimateContentSize(context, false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
index 5847808..72265a16 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -23,7 +23,6 @@
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
-import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.LaunchSourceType;
@@ -79,7 +78,6 @@
     private final ChromeActivity mActivity;
     private final CustomTabsConnection mConnection;
     private final CustomTabIntentDataProvider mIntentDataProvider;
-    private final Lazy<TabContentManager> mTabContentManager;
     private final TabObserverRegistrar mTabObserverRegistrar;
     private final Lazy<CompositorViewHolder> mCompositorViewHolder;
     private final WarmupManager mWarmupManager;
@@ -107,8 +105,7 @@
     public CustomTabActivityTabController(ChromeActivity activity,
             Lazy<CustomTabDelegateFactory> customTabDelegateFactory,
             CustomTabsConnection connection, CustomTabIntentDataProvider intentDataProvider,
-            Lazy<TabContentManager> tabContentManager, ActivityTabProvider activityTabProvider,
-            TabObserverRegistrar tabObserverRegistrar,
+            ActivityTabProvider activityTabProvider, TabObserverRegistrar tabObserverRegistrar,
             Lazy<CompositorViewHolder> compositorViewHolder,
             ActivityLifecycleDispatcher lifecycleDispatcher, WarmupManager warmupManager,
             CustomTabTabPersistencePolicy persistencePolicy, CustomTabActivityTabFactory tabFactory,
@@ -119,7 +116,6 @@
         mActivity = activity;
         mConnection = connection;
         mIntentDataProvider = intentDataProvider;
-        mTabContentManager = tabContentManager;
         mTabObserverRegistrar = tabObserverRegistrar;
         mCompositorViewHolder = compositorViewHolder;
         mWarmupManager = warmupManager;
@@ -180,7 +176,7 @@
             mTabFactory.initializeTabModels();
             Tab tab = getHiddenTab();
             if (tab == null) {
-                tab = createTab(null);
+                tab = createTab();
                 mTabProvider.setInitialTab(tab, TabCreationMode.EARLY);
             } else {
                 mTabProvider.setInitialTab(tab, TabCreationMode.HIDDEN);
@@ -238,18 +234,12 @@
 
         if (tab == null) {
             // No tab was restored or created early, creating a new tab.
-            tab = createTab(mTabContentManager.get());
+            tab = createTab();
             mode = TabCreationMode.DEFAULT;
         }
 
         assert tab != null;
 
-        if (mode == TabCreationMode.EARLY || mode == TabCreationMode.HIDDEN) {
-            // When the tab is created early, we don't have the TabContentManager connected,
-            // since compositor related controllers were not initialized at that point.
-            tab.attachTabContentManager(mTabContentManager.get());
-        }
-
         if (mode != TabCreationMode.RESTORED) {
             tabModel.addTab(tab, 0, tab.getLaunchType());
         }
@@ -300,7 +290,7 @@
         return tab;
     }
 
-    private Tab createTab(@Nullable TabContentManager tabContentManager) {
+    private Tab createTab() {
         WebContents webContents = takeWebContents();
         Tab tab = mTabFactory.createTab();
         int launchSource = mIntent.getIntExtra(
@@ -312,8 +302,8 @@
             tab.setAppAssociatedWith(mConnection.getClientPackageNameForSession(mSession));
         }
 
-        tab.initialize(webContents, tabContentManager, mCustomTabDelegateFactory.get(),
-                false /*initiallyHidden*/, false /*unfreeze*/);
+        tab.initialize(webContents, mCustomTabDelegateFactory.get(), false /*initiallyHidden*/,
+                false /*unfreeze*/);
 
         if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) {
             tab.enableEmbeddedMediaExperience(true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionMainMenuItem.java b/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionMainMenuItem.java
index 70622b7e..5267ebaf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionMainMenuItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionMainMenuItem.java
@@ -14,7 +14,6 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
@@ -71,10 +70,6 @@
             itemText.setText(
                     getContext().getString(R.string.data_reduction_saved_label, dataSaved));
             itemSummary.setText(getContext().getString(R.string.data_reduction_date_label, date));
-
-            int textColorLink = ApiCompatibilityUtils.getColor(
-                    getContext().getResources(), R.color.default_text_color_link);
-            itemText.setTextColor(textColorLink);
         } else {
             DataReductionProxyUma.dataReductionProxyUIAction(
                     DataReductionProxyUma.ACTION_MAIN_MENU_DISPLAYED_OFF);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionPromoScreen.java b/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionPromoScreen.java
index 344921e2..5fc81d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionPromoScreen.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionPromoScreen.java
@@ -8,6 +8,7 @@
 import android.content.DialogInterface;
 import android.view.View;
 
+import org.chromium.base.CommandLine;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.widget.PromoDialog;
@@ -17,13 +18,15 @@
  * The promo screen encouraging users to enable Data Saver.
  */
 public class DataReductionPromoScreen extends PromoDialog {
+    private static final String FORCE_PROMO_SWITCH = "force-data-reduction-second-run-promo";
+
     private int mState;
 
-    /**
-     * Launch the data reduction promo, if it needs to be displayed.
-     * @return Whether the data reduction promo was displayed.
-     */
-    public static boolean launchDataReductionPromo(Activity parentActivity, boolean isIncognito) {
+    private static boolean shouldLaunchDataReductionPromo(
+            Activity parentActivity, boolean isIncognito) {
+        // This switch is only used for testing so it is ok to override all the other checking.
+        if (CommandLine.getInstance().hasSwitch(FORCE_PROMO_SWITCH)) return true;
+
         // The promo is displayed if Chrome is launched directly (i.e., not with the intent to
         // navigate to and view a URL on startup), the instance is part of the field trial,
         // and the promo has not been displayed before.
@@ -31,6 +34,16 @@
         if (!DataReductionPromoUtils.canShowPromos()) return false;
         if (DataReductionPromoUtils.getDisplayedFreOrSecondRunPromo()) return false;
 
+        return true;
+    }
+
+    /**
+     * Launch the data reduction promo, if it needs to be displayed.
+     * @return Whether the data reduction promo was displayed.
+     */
+    public static boolean launchDataReductionPromo(Activity parentActivity, boolean isIncognito) {
+        if (!shouldLaunchDataReductionPromo(parentActivity, isIncognito)) return false;
+
         DataReductionPromoScreen promoScreen = new DataReductionPromoScreen(parentActivity);
         promoScreen.setOnDismissListener(promoScreen);
         promoScreen.show();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionPromoUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionPromoUtils.java
index bc713e9..b0077a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionPromoUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/datareduction/DataReductionPromoUtils.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.datareduction;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge.AboutVersionStrings;
@@ -65,6 +66,10 @@
      * @return Whether the any data reduction proxy promotion has been displayed.
      */
     public static boolean canShowPromos() {
+        // See http://crbug.com/946357
+        if (LocaleManager.getInstance().isSpecialUser()) {
+            return false;
+        }
         if (!DataReductionProxySettings.getInstance().isDataReductionProxyPromoAllowed()) {
             return false;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
index 1e2a76a..1d203b63 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -125,6 +125,10 @@
     }
 
     protected boolean shouldShowDataReductionPage() {
+        // See http://crbug.com/946357
+        if (LocaleManager.getInstance().isSpecialUser()) {
+            return false;
+        }
         return !DataReductionProxySettings.getInstance().isDataReductionProxyManaged()
                 && DataReductionProxySettings.getInstance().isDataReductionProxyFREPromoAllowed();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionPromoInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionPromoInfoBar.java
index b435cd15..9bfb5b14 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionPromoInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionPromoInfoBar.java
@@ -15,6 +15,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.UrlConstants;
+import org.chromium.chrome.browser.datareduction.DataReductionBrandingResourceProvider;
 import org.chromium.chrome.browser.datareduction.DataReductionPromoUtils;
 import org.chromium.chrome.browser.omaha.VersionNumberGetter;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
@@ -114,7 +115,9 @@
                     BitmapFactory.decodeResource(context.getResources(), R.drawable.infobar_chrome),
                     context.getString(R.string.data_reduction_promo_infobar_title),
                     context.getString(R.string.data_reduction_promo_infobar_text),
-                    context.getString(R.string.data_reduction_promo_infobar_button),
+                    context.getString(
+                            DataReductionBrandingResourceProvider.getDataSaverBrandedString(
+                                    R.string.data_reduction_enable_button)),
                     context.getString(R.string.no_thanks));
 
             return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
index 0f8cfda8..562ee59 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
@@ -15,6 +15,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Callback;
+import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.browser.preferences.SearchEnginePreference;
 import org.chromium.chrome.browser.search_engines.TemplateUrl;
@@ -504,6 +506,15 @@
      * @return Whether the user requires special handling.
      */
     public boolean isSpecialUser() {
+        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.FORCE_ENABLE_SPECIAL_USER)) {
+            return true;
+        }
         return false;
     }
+
+    /**
+     * Record metrics related to user type.
+     */
+    @CalledByNative
+    public void recordUserTypeMetrics() {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/OWNERS
new file mode 100644
index 0000000..d537f02
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/OWNERS
@@ -0,0 +1 @@
+ioanap@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PasswordGenerationAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupAdapter.java
similarity index 85%
rename from chrome/android/java/src/org/chromium/chrome/browser/autofill/PasswordGenerationAdapter.java
rename to chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupAdapter.java
index 93f40aa..f4b8e72 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PasswordGenerationAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupAdapter.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.autofill;
+package org.chromium.chrome.browser.password_manager;
 
 import android.content.Context;
 import android.view.LayoutInflater;
@@ -24,7 +24,7 @@
  * list: (1) the password suggestion and (2) an explanation of the password generation feature. If
  * the passwordDisplayed parameter is false, then the adapter shows only the explanation item.
  */
-public class PasswordGenerationAdapter extends BaseAdapter {
+public class PasswordGenerationPopupAdapter extends BaseAdapter {
     private final Context mContext;
     private final List<Integer> mViewTypes;
     private final String mPassword;
@@ -57,22 +57,23 @@
      * @param anchorWidthInDp The width of the anchor to which the popup is attached. Used to size
      * the explanation view.
      */
-    public PasswordGenerationAdapter(Context context, boolean passwordDisplayed, String password,
-            String suggestionTitle, String explanationText, float anchorWidthInDp) {
+    public PasswordGenerationPopupAdapter(Context context, boolean passwordDisplayed,
+            String password, String suggestionTitle, String explanationText,
+            float anchorWidthInDp) {
         super();
         mContext = context;
         mViewTypes = passwordDisplayed ? Arrays.asList(SUGGESTION, EXPLANATION)
-                : Arrays.asList(EXPLANATION);
+                                       : Arrays.asList(EXPLANATION);
         mPassword = password;
         mSuggestionTitle = suggestionTitle;
         mExplanationText = explanationText;
 
         int horizontalMarginInPx = Math.round(mContext.getResources().getDimension(
                 R.dimen.password_generation_horizontal_margin));
-        int anchorWidthInPx = Math.round(anchorWidthInDp
-                * mContext.getResources().getDisplayMetrics().density);
-        View suggestion = getViewForType(SUGGESTION).findViewById(
-                R.id.password_generation_suggestion);
+        int anchorWidthInPx =
+                Math.round(anchorWidthInDp * mContext.getResources().getDisplayMetrics().density);
+        View suggestion =
+                getViewForType(SUGGESTION).findViewById(R.id.password_generation_suggestion);
         suggestion.setMinimumWidth(anchorWidthInPx - 2 * horizontalMarginInPx);
         suggestion.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
@@ -97,8 +98,8 @@
      * @return The view for this viewType.
      */
     private View getViewForType(int type) {
-        LayoutInflater inflater = (LayoutInflater) mContext
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        LayoutInflater inflater =
+                (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = null;
         switch (type) {
             case SUGGESTION:
@@ -111,11 +112,11 @@
 
             case EXPLANATION:
                 view = inflater.inflate(R.layout.password_generation_popup_explanation, null);
-                TextView explanation = (TextView) view
-                        .findViewById(R.id.password_generation_explanation);
+                TextView explanation =
+                        (TextView) view.findViewById(R.id.password_generation_explanation);
                 explanation.setText(mExplanationText);
-                explanation.setLayoutParams(new LayoutParams(mSuggestionMeasuredWidth,
-                        LayoutParams.WRAP_CONTENT));
+                explanation.setLayoutParams(
+                        new LayoutParams(mSuggestionMeasuredWidth, LayoutParams.WRAP_CONTENT));
                 break;
 
             default:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PasswordGenerationPopupBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupBridge.java
similarity index 90%
rename from chrome/android/java/src/org/chromium/chrome/browser/autofill/PasswordGenerationPopupBridge.java
rename to chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupBridge.java
index 71826887..3e6123b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PasswordGenerationPopupBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationPopupBridge.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.autofill;
+package org.chromium.chrome.browser.password_manager;
 
 import android.content.Context;
 import android.os.Handler;
@@ -11,7 +11,6 @@
 import android.widget.PopupWindow;
 
 import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
 import org.chromium.ui.DropdownPopupWindow;
 import org.chromium.ui.base.WindowAndroid;
@@ -19,7 +18,6 @@
 /**
  * JNI call glue for password generation between native and Java objects.
  */
-@JNINamespace("autofill")
 public class PasswordGenerationPopupBridge
         implements AdapterView.OnItemClickListener, PopupWindow.OnDismissListener {
     private final long mNativePasswordGenerationPopupViewAndroid;
@@ -33,8 +31,8 @@
      * @param windowAndroid The browser window.
      */
     @CalledByNative
-    private static PasswordGenerationPopupBridge create(View anchorView, long nativePopup,
-            WindowAndroid windowAndroid) {
+    private static PasswordGenerationPopupBridge create(
+            View anchorView, long nativePopup, WindowAndroid windowAndroid) {
         return new PasswordGenerationPopupBridge(anchorView, nativePopup, windowAndroid);
     }
 
@@ -44,8 +42,8 @@
      * @param nativePopup The pointer to the native counterpart.
      * @param windowAndroid The browser window.
      */
-    public PasswordGenerationPopupBridge(View anchorView, long nativePopup,
-            WindowAndroid windowAndroid) {
+    public PasswordGenerationPopupBridge(
+            View anchorView, long nativePopup, WindowAndroid windowAndroid) {
         mNativePasswordGenerationPopupViewAndroid = nativePopup;
         mContext = windowAndroid.getActivity().get();
         mAnchorView = anchorView;
@@ -106,7 +104,7 @@
         if (mPopup != null) {
             float anchorWidth = mAnchorView.getLayoutParams().width;
             assert anchorWidth > 0;
-            PasswordGenerationAdapter adapter = new PasswordGenerationAdapter(mContext,
+            PasswordGenerationPopupAdapter adapter = new PasswordGenerationPopupAdapter(mContext,
                     passwordDisplayed, password, suggestionTitle, explanationText, anchorWidth);
             mPopup.setAdapter(adapter);
             mPopup.setRtl(isRtl);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 0f0bc7ac..939759d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -171,7 +171,7 @@
                        .setWindow(getWindowAndroid())
                        .setLaunchType(TabLaunchType.FROM_EXTERNAL_APP)
                        .build();
-        mTab.initialize(WebContentsFactory.createWebContents(false, false), null,
+        mTab.initialize(WebContentsFactory.createWebContents(false, false),
                 new TabDelegateFactory(), false, false);
         mTab.loadUrl(new LoadUrlParams(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL));
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 3b3dbfc..9e55018d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -40,7 +40,6 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.WebContentsFactory;
-import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.content.ContentUtils;
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
@@ -913,8 +912,6 @@
      * new {@link WebContents} will be created for this {@link Tab}.
      * @param webContents       A {@link WebContents} object or {@code null} if one should be
      *                          created.
-     * @param tabContentManager A {@link TabContentManager} instance or {@code null} if the web
-     *                          content will be managed/displayed manually.
      * @param delegateFactory   The {@link TabDelegateFactory} to be used for delegate creation.
      * @param initiallyHidden   Only used if {@code webContents} is {@code null}.  Determines
      *                          whether or not the newly created {@link WebContents} will be hidden
@@ -922,8 +919,8 @@
      * @param unfreeze          Whether there should be an attempt to restore state at the end of
      *                          the initialization.
      */
-    public void initialize(WebContents webContents, TabContentManager tabContentManager,
-            TabDelegateFactory delegateFactory, boolean initiallyHidden, boolean unfreeze) {
+    public void initialize(WebContents webContents, TabDelegateFactory delegateFactory,
+            boolean initiallyHidden, boolean unfreeze) {
         try {
             TraceEvent.begin("Tab.initialize");
 
@@ -935,11 +932,6 @@
             mBrowserControlsVisibilityDelegate =
                     mDelegateFactory.createBrowserControlsVisibilityDelegate(this);
 
-            // Attach the TabContentManager if we have one.  This will bind this Tab's content layer
-            // to this manager.
-            // TODO(dtrainor): Remove this and move to a pull model instead of pushing the layer.
-            attachTabContentManager(tabContentManager);
-
             // If there is a frozen WebContents state or a pending lazy load, don't create a new
             // WebContents.
             if (getFrozenContentsState() != null || getPendingLoadParams() != null) {
@@ -1030,7 +1022,6 @@
         // with an activity, and will crash. crbug.com/657007
         WebContents webContents = getWebContents();
         if (webContents != null) webContents.setTopLevelNativeWindow(null);
-        attachTabContentManager(null);
 
         TabModelSelector tabModelSelector = getTabModelSelector();
         if (tabModelSelector != null) {
@@ -1079,7 +1070,6 @@
         updateWindowAndroid(activity.getWindowAndroid());
 
         // Update for the controllers that need the Compositor from the new Activity.
-        attachTabContentManager(activity.getTabContentManager());
         mFullscreenManager = activity.getFullscreenManager();
         // Update the delegate factory, then recreate and propagate all delegates.
         mDelegateFactory = tabDelegateFactory;
@@ -1130,19 +1120,6 @@
     }
 
     /**
-     * Attach the content layer for this tab to the given {@link TabContentManager}.
-     * @param tabContentManager {@link TabContentManager} to attach to.
-     */
-    public void attachTabContentManager(TabContentManager tabContentManager) {
-        if (mNativeTabAndroid == 0) return;
-        nativeAttachToTabContentManager(mNativeTabAndroid, tabContentManager);
-    }
-
-    void clearThumbnailPlaceholder() {
-        if (mNativeTabAndroid != 0) nativeClearThumbnailPlaceholder(mNativeTabAndroid);
-    }
-
-    /**
      * @return The delegate factory for testing purposes only.
      */
     public TabDelegateFactory getDelegateFactory() {
@@ -2214,9 +2191,6 @@
             long nativeTabAndroid, int constraints, int current, boolean animate);
     private native void nativeLoadOriginalImage(long nativeTabAndroid);
     private native long nativeGetBookmarkId(long nativeTabAndroid, boolean onlyEditable);
-    private native void nativeAttachToTabContentManager(long nativeTabAndroid,
-            TabContentManager tabContentManager);
-    private native void nativeClearThumbnailPlaceholder(long nativeTabAndroid);
     private native boolean nativeHasPrerenderedUrl(long nativeTabAndroid, String url);
     private native void nativeSetWebappManifestScope(long nativeTabAndroid, String scope);
     private native void nativeSetPictureInPictureEnabled(long nativeTabAndroid, boolean enabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFullscreenHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFullscreenHandler.java
index 34e1fc1..ef12863 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFullscreenHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFullscreenHandler.java
@@ -91,9 +91,6 @@
                     SelectionPopupController.fromWebContents(tab.getWebContents());
             controller.destroySelectActionMode();
         }
-
-        // We want to remove any cached thumbnail of the Tab.
-        tab.clearThumbnailPlaceholder();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
index d5a1da6..3d205648d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -12,7 +12,6 @@
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.ServiceTabLauncher;
-import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBuilder;
@@ -38,7 +37,6 @@
 
     private WindowAndroid mNativeWindow;
     private TabModel mTabModel;
-    private TabContentManager mTabContentManager;
     private TabModelOrderController mOrderController;
 
     public ChromeTabCreator(
@@ -137,8 +135,7 @@
                               .setWindow(mNativeWindow)
                               .setLaunchType(type)
                               .build();
-                tab.initialize(
-                        webContents, mTabContentManager, delegateFactory, !openInForeground, false);
+                tab.initialize(webContents, delegateFactory, !openInForeground, false);
                 TabParentIntent.from(tab).set(parentIntent);
                 webContents.resumeLoadingCreatedWebContents();
             } else if (!openInForeground && SysUtils.isLowEndDevice()) {
@@ -151,7 +148,7 @@
                               .setWindow(mNativeWindow)
                               .setLaunchType(type)
                               .build();
-                tab.initialize(null, mTabContentManager, delegateFactory, !openInForeground, false);
+                tab.initialize(null, delegateFactory, !openInForeground, false);
             } else {
                 tab = TabBuilder.createLiveTab(!openInForeground)
                               .setParentId(parentId)
@@ -160,7 +157,7 @@
                               .setLaunchType(type)
                               .build();
 
-                tab.initialize(null, mTabContentManager, delegateFactory, !openInForeground, false);
+                tab.initialize(null, delegateFactory, !openInForeground, false);
                 tab.loadUrl(loadUrlParams);
             }
             TabRedirectHandler.from(tab).updateIntent(intent);
@@ -197,7 +194,7 @@
                           .setWindow(mNativeWindow)
                           .setLaunchType(type)
                           .build();
-        tab.initialize(webContents, mTabContentManager, delegateFactory, !openInForeground, false);
+        tab.initialize(webContents, delegateFactory, !openInForeground, false);
         mTabModel.addTab(tab, position, type);
         return true;
     }
@@ -301,8 +298,7 @@
                           .build();
         boolean selectTab = mOrderController.willOpenInForeground(TabLaunchType.FROM_RESTORE,
                 state.isIncognito());
-        tab.initialize(
-                null, mTabContentManager, createDefaultTabDelegateFactory(), !selectTab, false);
+        tab.initialize(null, createDefaultTabDelegateFactory(), !selectTab, false);
         assert state.isIncognito() == mIncognito;
         mTabModel.addTab(tab, index, TabLaunchType.FROM_RESTORE);
         return tab;
@@ -349,13 +345,10 @@
      * Sets the tab model and tab content manager to use.
      * @param model           The new {@link TabModel} to use.
      * @param orderController The controller for determining the order of tabs.
-     * @param manager         The new {@link TabContentManager} to use.
      */
-    public void setTabModel(
-            TabModel model, TabModelOrderController orderController, TabContentManager manager) {
+    public void setTabModel(TabModel model, TabModelOrderController orderController) {
         mTabModel = model;
         mOrderController = orderController;
-        mTabContentManager = manager;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
index 70868eb..16f3346 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
@@ -135,8 +135,8 @@
                 regularTabCreator, incognitoTabCreator, mUma, mOrderController,
                 mTabContentManager, mTabSaver, this));
         initialize(isIncognitoSelected(), normalModel, incognitoModel);
-        regularTabCreator.setTabModel(normalModel, mOrderController, mTabContentManager);
-        incognitoTabCreator.setTabModel(incognitoModel, mOrderController, mTabContentManager);
+        regularTabCreator.setTabModel(normalModel, mOrderController);
+        incognitoTabCreator.setTabModel(incognitoModel, mOrderController);
         mTabSaver.setTabContentManager(mTabContentManager);
 
         addObserver(new EmptyTabModelSelectorObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserver.java
index 0c60bbd..e0ce5ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserver.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.tabmodel;
 
+import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.tab.Tab;
 
 import java.util.List;
@@ -37,7 +38,8 @@
             mSelectorObserver = new EmptyTabModelSelectorObserver() {
                 @Override
                 public void onNewTabCreated(Tab tab) {
-                    assert false : "onChange should have happened and unregistered this listener.";
+                    throw new IllegalStateException(
+                            "onChange should have happened and unregistered this listener.");
                 }
 
                 @Override
@@ -49,7 +51,10 @@
             };
             mTabModelSelector.addObserver(mSelectorObserver);
         } else {
-            registerModelObservers();
+            // Run this asynchronously so it is done after the tasks in the constructor of
+            // the inherited classes (specifically when used in TabModelSelectoTabObserver)
+            // are completed.
+            ThreadUtils.getUiThreadHandler().postAtFrontOfQueue(() -> registerModelObservers());
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserver.java
index 560a15a..85b390c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserver.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.tabmodel;
 
+import android.util.SparseArray;
+
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 
@@ -16,6 +18,7 @@
 
     private final TabModelSelector mTabModelSelector;
     private final TabModelSelectorTabModelObserver mTabModelObserver;
+    private final SparseArray<Tab> mTabsToClose = new SparseArray<>();
 
     /**
      * Constructs an observer that should be notified of tabs changes for all tabs owned
@@ -35,11 +38,32 @@
             public void didAddTab(Tab tab, @TabLaunchType int type) {
                 // This observer is automatically removed by tab when it is destroyed.
                 tab.addObserver(TabModelSelectorTabObserver.this);
+                onTabRegistered(tab);
+            }
+
+            @Override
+            public void willCloseTab(Tab tab, boolean animate) {
+                mTabsToClose.put(tab.getId(), tab);
+            }
+
+            @Override
+            public void tabClosureUndone(Tab tab) {
+                mTabsToClose.remove(tab.getId());
+            }
+
+            @Override
+            public void didCloseTab(int tabId, boolean incognito) {
+                Tab tab = mTabsToClose.get(tabId);
+                if (tab != null) {
+                    mTabsToClose.remove(tabId);
+                    onTabUnregistered(tab);
+                }
             }
 
             @Override
             public void tabRemoved(Tab tab) {
                 tab.removeObserver(TabModelSelectorTabObserver.this);
+                onTabUnregistered(tab);
             }
 
             @Override
@@ -49,8 +73,9 @@
                     TabModel tabModel = tabModels.get(i);
                     TabList comprehensiveTabList = tabModel.getComprehensiveModel();
                     for (int j = 0; j < comprehensiveTabList.getCount(); j++) {
-                        comprehensiveTabList.getTabAt(j).addObserver(
-                                TabModelSelectorTabObserver.this);
+                        Tab tab = comprehensiveTabList.getTabAt(j);
+                        tab.addObserver(TabModelSelectorTabObserver.this);
+                        onTabRegistered(tab);
                     }
                 }
             }
@@ -58,6 +83,18 @@
     }
 
     /**
+     * Called when a tab is registered to a tab model this selector is managing.
+     * @param tab The registered Tab.
+     */
+    protected void onTabRegistered(Tab tab) {}
+
+    /**
+     * Called when a tab is unregistered from a tab model this selector is managing.
+     * @param tab The unregistered Tab.
+     */
+    protected void onTabUnregistered(Tab tab) {}
+
+    /**
      * Destroys the observer and removes itself as a listener for Tab updates.
      */
     public void destroy() {
@@ -70,7 +107,9 @@
 
             TabList comprehensiveTabList = tabModel.getComprehensiveModel();
             for (int j = 0; j < comprehensiveTabList.getCount(); j++) {
-                comprehensiveTabList.getTabAt(j).removeObserver(this);
+                Tab tab = comprehensiveTabList.getTabAt(j);
+                tab.removeObserver(this);
+                onTabUnregistered(tab);
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index aaa6f484..e362d0aa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -776,7 +776,7 @@
                 shareButtonListener, mAppThemeColorProvider);
 
         mIsBottomToolbarVisible = FeatureUtilities.isBottomToolbarEnabled()
-                && (!FeatureUtilities.isAdaptiveToolbarEnabled(mActivity)
+                && (!FeatureUtilities.isAdaptiveToolbarEnabled()
                         || mActivity.getResources().getConfiguration().orientation
                                 != Configuration.ORIENTATION_LANDSCAPE);
         mBottomControlsCoordinator.setBottomControlsVisible(mIsBottomToolbarVisible);
@@ -1198,8 +1198,8 @@
     public void onOrientationChange() {
         if (mActionModeController != null) mActionModeController.showControlsOnOrientationChange();
 
-        if (mBottomControlsCoordinator != null
-                && FeatureUtilities.isAdaptiveToolbarEnabled(mActivity)) {
+        if (mBottomControlsCoordinator != null && FeatureUtilities.isBottomToolbarEnabled()
+                && FeatureUtilities.isAdaptiveToolbarEnabled()) {
             mIsBottomToolbarVisible = mActivity.getResources().getConfiguration().orientation
                     != Configuration.ORIENTATION_LANDSCAPE;
             mToolbar.onBottomToolbarVisibilityChanged(mIsBottomToolbarVisible);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/EventTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/EventTracker.java
index e4ac159..a7f57f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/EventTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/EventTracker.java
@@ -43,6 +43,7 @@
     public Promise<List<WebsiteEvent>> queryWebsiteEvents(long start, long end) {
         assert start < end;
         return mRootPromise.then((Function<List<WebsiteEvent>, List<WebsiteEvent>>) (result) -> {
+            UsageStatsMetricsReporter.reportMetricsEvent(UsageStatsMetricsEvent.QUERY_EVENTS);
             List<WebsiteEvent> sublist = sublistFromTimeRange(start, end, result);
             List<WebsiteEvent> sublistCopy = new ArrayList<>(sublist.size());
             sublistCopy.addAll(sublist);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
index c1a8382..250cf173 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
@@ -38,8 +38,12 @@
                 // succeeds.
                 List<String> resultCopy = new ArrayList<>(result);
                 if (suspended) {
+                    UsageStatsMetricsReporter.reportMetricsEvent(
+                            UsageStatsMetricsEvent.SUSPEND_SITES);
                     resultCopy.addAll(fqdns);
                 } else {
+                    UsageStatsMetricsReporter.reportMetricsEvent(
+                            UsageStatsMetricsEvent.UNSUSPEND_SITES);
                     resultCopy.removeAll(fqdns);
                 }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/TokenTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/TokenTracker.java
index 9b4ce2f..ec5c493 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/TokenTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/TokenTracker.java
@@ -54,6 +54,8 @@
                 return;
             }
 
+            UsageStatsMetricsReporter.reportMetricsEvent(
+                    UsageStatsMetricsEvent.START_TRACKING_TOKEN);
             String token = mTokenGenerator.nextToken();
             Map<String, String> resultCopy = new HashMap<>(result);
             resultCopy.put(token, fqdn);
@@ -83,6 +85,8 @@
                 return;
             }
 
+            UsageStatsMetricsReporter.reportMetricsEvent(
+                    UsageStatsMetricsEvent.STOP_TRACKING_TOKEN);
             Map<String, String> resultCopy = new HashMap<>(result);
             resultCopy.remove(token);
             mBridge.setTokenMappings(resultCopy, (didSucceed) -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsMetricsEvent.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsMetricsEvent.java
new file mode 100644
index 0000000..efa19ed
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsMetricsEvent.java
@@ -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.
+
+package org.chromium.chrome.browser.usage_stats;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Enumeration of usage stats-related metrics events.
+ */
+@IntDef({
+        UsageStatsMetricsEvent.OPT_IN,
+        UsageStatsMetricsEvent.OPT_OUT,
+        UsageStatsMetricsEvent.START_TRACKING_TOKEN,
+        UsageStatsMetricsEvent.STOP_TRACKING_TOKEN,
+        UsageStatsMetricsEvent.SUSPEND_SITES,
+        UsageStatsMetricsEvent.UNSUSPEND_SITES,
+        UsageStatsMetricsEvent.QUERY_EVENTS,
+        UsageStatsMetricsEvent.CLEAR_ALL_HISTORY,
+        UsageStatsMetricsEvent.CLEAR_HISTORY_RANGE,
+        UsageStatsMetricsEvent.NUM_ENTRIES,
+})
+@Retention(RetentionPolicy.SOURCE)
+public @interface UsageStatsMetricsEvent {
+    int OPT_IN = 0;
+    int OPT_OUT = 1;
+    int START_TRACKING_TOKEN = 2;
+    int STOP_TRACKING_TOKEN = 3;
+    int SUSPEND_SITES = 4;
+    int UNSUSPEND_SITES = 5;
+    int QUERY_EVENTS = 6;
+    int CLEAR_ALL_HISTORY = 7;
+    int CLEAR_HISTORY_RANGE = 8;
+    int NUM_ENTRIES = 9;
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsMetricsReporter.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsMetricsReporter.java
new file mode 100644
index 0000000..c4dc753
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsMetricsReporter.java
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.usage_stats;
+
+import org.chromium.base.metrics.RecordHistogram;
+
+/**
+ * Recorder for usage-stats related metrics events.
+ */
+public class UsageStatsMetricsReporter {
+    public static void reportMetricsEvent(@UsageStatsMetricsEvent int event) {
+        RecordHistogram.recordEnumeratedHistogram(
+                "UsageStats.Events", event, UsageStatsMetricsEvent.NUM_ENTRIES);
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
index b7bb1fd..0be5e80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
@@ -11,6 +11,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.AppHooks;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -74,7 +75,17 @@
     public boolean getOptInState() {
         ThreadUtils.assertOnUiThread();
         PrefServiceBridge prefServiceBridge = PrefServiceBridge.getInstance();
-        return prefServiceBridge.getBoolean(Pref.USAGE_STATS_ENABLED);
+        boolean enabledByPref = prefServiceBridge.getBoolean(Pref.USAGE_STATS_ENABLED);
+        boolean enabledByFeature = ChromeFeatureList.isEnabled(ChromeFeatureList.USAGE_STATS);
+        // If the user has previously opted in, but the feature has been turned off, we need to
+        // treat it as if they opted out; otherwise they'll have no UI affordance for clearing
+        // whatever data Digital Wellbeing has stored.
+        if (enabledByPref && !enabledByFeature) {
+            onAllHistoryDeleted();
+            setOptInState(false);
+        }
+
+        return enabledByPref && enabledByFeature;
     }
 
     /** Sets the user's opt in state. */
@@ -84,9 +95,12 @@
         prefServiceBridge.setBoolean(Pref.USAGE_STATS_ENABLED, state);
 
         if (mOptInState == state) return;
-
         mOptInState = state;
         mClient.notifyOptInStateChange(mOptInState);
+
+        @UsageStatsMetricsEvent
+        int event = state ? UsageStatsMetricsEvent.OPT_IN : UsageStatsMetricsEvent.OPT_OUT;
+        UsageStatsMetricsReporter.reportMetricsEvent(event);
     }
 
     /** Query for all events that occurred in the half-open range [start, end) */
@@ -135,6 +149,7 @@
 
     public void onAllHistoryDeleted() {
         ThreadUtils.assertOnUiThread();
+        UsageStatsMetricsReporter.reportMetricsEvent(UsageStatsMetricsEvent.CLEAR_ALL_HISTORY);
         mClient.notifyAllHistoryCleared();
         mEventTracker.clearAll().except((exception) -> {
             // Retry once; if the subsequent attempt fails, log the failure and move on.
@@ -146,6 +161,7 @@
 
     public void onHistoryDeletedInRange(long startTimeMs, long endTimeMs) {
         ThreadUtils.assertOnUiThread();
+        UsageStatsMetricsReporter.reportMetricsEvent(UsageStatsMetricsEvent.CLEAR_HISTORY_RANGE);
         // endTimeMs could be Long.MAX_VALUE, which doesn't play well when converting into a
         // Timestamp proto. It doesn't make any sense to delete into the future, so we can
         // reasonably cap endTimeMs at now.
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 1482f760..4d73a10b 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
@@ -426,18 +426,16 @@
     }
 
     /**
-     * @param activityContext The context for the containing {@link android.app.Activity}.
      * @return Whether or not the adaptive toolbar is enabled.
      */
-    public static boolean isAdaptiveToolbarEnabled(Context activityContext) {
+    public static boolean isAdaptiveToolbarEnabled() {
         if (sIsAdaptiveToolbarEnabled == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
             sIsAdaptiveToolbarEnabled = prefManager.readBoolean(
                     ChromePreferenceManager.ADAPTIVE_TOOLBAR_ENABLED_KEY, true);
         }
-        return sIsAdaptiveToolbarEnabled && isBottomToolbarEnabled()
-                && !isGridTabSwitcherEnabled(activityContext);
+        return sIsAdaptiveToolbarEnabled;
     }
 
     /**
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 2683b6e..7ab70f7 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1368,7 +1368,7 @@
         Use up to 60 percent less data and speed up the web. Google servers will optimize the pages you visit.
       </message>
       <message name="IDS_DATA_REDUCTION_PROMO_SUMMARY_LITE_MODE" desc="Description for the promo inviting users to enable Lite mode. This informs users that their web traffic will be seen and optimized for speed and data usage, by Google servers (AKA 'Cloud technology')." >
-        In Lite mode, Chrome loads pages faster and uses up to 60 percent less data. Google's cloud technology optimizes the pages you visit.
+        In Lite mode, Chrome loads pages faster and uses up to 60 percent less data. Google's Cloud technology optimizes the pages you visit.
       </message>
       <message name="IDS_DATA_REDUCTION_ENABLE_BUTTON" desc="Button the user presses if they want to enable Data Saver" >
         Turn on Data Saver
@@ -1400,9 +1400,6 @@
       <message name="IDS_DATA_REDUCTION_PROMO_INFOBAR_TEXT" desc="Text to be displayed in the data reduction promo infobar">
         Google servers will optimize the pages you visit.
       </message>
-      <message name="IDS_DATA_REDUCTION_PROMO_INFOBAR_BUTTON" desc="Text to be displayed in the data reduction promo infobar confirm button">
-        Turn on Data Saver
-      </message>
       <message name="IDS_DATA_REDUCTION_MILESTONE_PROMO_TEXT_MB" desc="Text to be displayed in the data reduction promo message that lets the user know they saved a certain amount of data in MB">
         Chrome has saved you <ph name="megabytes">%1$d<ex>100</ex></ph> MB
       </message>
diff --git a/chrome/android/java_templates/ChromeSwitches.java.tmpl b/chrome/android/java_templates/ChromeSwitches.java.tmpl
index 436000a..00ad207 100644
--- a/chrome/android/java_templates/ChromeSwitches.java.tmpl
+++ b/chrome/android/java_templates/ChromeSwitches.java.tmpl
@@ -198,6 +198,9 @@
     public static final String DISABLE_GOOGLE_PLAY_SERVICES_FOR_TESTING =
             "disable-google-play-services-for-testing";
 
+    /** Force enable special user handling. */
+    public static final String FORCE_ENABLE_SPECIAL_USER = "force-enable-special-user";
+
 {NATIVE_STRINGS}
 
     // Prevent instantiation.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AutofillKeyboardAccessoryIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AutofillKeyboardAccessoryIntegrationTest.java
index 6caa4fe..49c552739 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AutofillKeyboardAccessoryIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AutofillKeyboardAccessoryIntegrationTest.java
@@ -110,6 +110,7 @@
         mHelper.clickNodeAndShowKeyboard("NAME_FIRST");
         mHelper.waitForKeyboardAccessoryToBeShown();
 
+        CriteriaHelper.pollUiThread(() -> getFirstSuggestion() != null);
         TestThreadUtils.runOnUiThreadBlocking(() -> getFirstSuggestion().performClick());
         mHelper.waitForKeyboardAccessoryToDisappear();
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java
index 748e7310..a10d1f9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java
@@ -46,8 +46,6 @@
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.AccessorySheetData;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.PropertyProvider;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.components.autofill.AutofillDelegate;
-import org.chromium.components.autofill.AutofillSuggestion;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.WebContents;
@@ -57,7 +55,6 @@
 import org.chromium.content_public.browser.test.util.TestInputMethodManagerWrapper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.net.test.EmbeddedTestServer;
-import org.chromium.ui.DropdownItem;
 import org.chromium.ui.DropdownPopupWindowInterface;
 
 import java.util.concurrent.ExecutionException;
@@ -414,31 +411,4 @@
                             AccessoryAction.GENERATE_PASSWORD_AUTOMATIC, result -> {})});
         });
     }
-
-    public void addAutofillChips() {
-        PropertyProvider<AutofillSuggestion[]> suggestionProvider =
-                new PropertyProvider<>(AccessoryAction.AUTOFILL_SUGGESTION);
-        mActivityTestRule.getActivity()
-                .getManualFillingController()
-                .getKeyboardAccessory()
-                .registerAutofillProvider(suggestionProvider, new AutofillDelegate() {
-                    @Override
-                    public void dismissed() {}
-                    @Override
-                    public void suggestionSelected(int listIndex) {}
-                    @Override
-                    public void deleteSuggestion(int listIndex) {}
-                    @Override
-                    public void accessibilityFocusCleared() {}
-                });
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            suggestionProvider.notifyObservers(new AutofillSuggestion[] {
-                    new AutofillSuggestion("Johnathan", "Smithonian-Jackson", DropdownItem.NO_ICON,
-                            false, 0, false, false, false),
-                    new AutofillSuggestion("Jane Erika", "Donovanova", DropdownItem.NO_ICON, false,
-                            1, false, false, false),
-                    new AutofillSuggestion("Marcus", "McSpartangregor", DropdownItem.NO_ICON, false,
-                            2, false, false, false)});
-        });
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
index d5c59aa..1b926dca 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
@@ -49,6 +49,7 @@
 
     @Test
     @MediumTest
+    @CommandLineFlags.Add({"memlog-in-process=off"})
     public void testModeBrowserDynamic() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
         Assert.assertTrue(shim.runTestForMode("browser", true, "native", true, false, false));
@@ -63,6 +64,7 @@
 
     @Test
     @MediumTest
+    @CommandLineFlags.Add({"memlog-in-process=off"})
     public void testModeBrowserDynamicPseudo() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
         Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false, false));
@@ -101,6 +103,7 @@
 
     @Test
     @MediumTest
+    @CommandLineFlags.Add({"memlog-in-process=off"})
     public void testModeBrowserDynamicPseudoSampleEverything() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
         Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, true));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
index e6f4401..5db9ee6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
@@ -74,7 +74,7 @@
                                     .setWindow(mActivityTestRule.getActivity().getWindowAndroid())
                                     .setLaunchType(TabLaunchType.FROM_LONGPRESS_BACKGROUND)
                                     .build();
-                bgTab.initialize(null, null, new TabDelegateFactory(), true, false);
+                bgTab.initialize(null, new TabDelegateFactory(), true, false);
                 return bgTab;
             }
         });
@@ -119,7 +119,7 @@
                                     .setWindow(mActivityTestRule.getActivity().getWindowAndroid())
                                     .setLaunchType(TabLaunchType.FROM_LONGPRESS_BACKGROUND)
                                     .build();
-                bgTab.initialize(null, null, new TabDelegateFactory(), true, false);
+                bgTab.initialize(null, new TabDelegateFactory(), true, false);
                 bgTab.loadUrl(new LoadUrlParams(mTestUrl));
                 bgTab.show(TabSelectionType.FROM_USER);
                 return bgTab;
@@ -137,7 +137,7 @@
                                     .setWindow(mActivityTestRule.getActivity().getWindowAndroid())
                                     .setLaunchType(TabLaunchType.FROM_LONGPRESS_BACKGROUND)
                                     .build();
-                bgTab.initialize(null, null, new TabDelegateFactory(), true, false);
+                bgTab.initialize(null, new TabDelegateFactory(), true, false);
                 bgTab.loadUrl(new LoadUrlParams(mTestUrl));
                 // Simulate the renderer being killed by the OS.
                 ChromeTabUtils.simulateRendererKilledForTesting(bgTab, false);
@@ -157,7 +157,7 @@
                                     .setWindow(mActivityTestRule.getActivity().getWindowAndroid())
                                     .setLaunchType(TabLaunchType.FROM_LONGPRESS_BACKGROUND)
                                     .build();
-                bgTab.initialize(null, null, new TabDelegateFactory(), true, false);
+                bgTab.initialize(null, new TabDelegateFactory(), true, false);
                 bgTab.show(TabSelectionType.FROM_USER);
                 return bgTab;
             }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserverTest.java
index 960d6bd..c370b3e4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserverTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabModelObserverTest.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserverTestRule.TabModelSelectorTestTabModel;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.List;
 import java.util.concurrent.TimeoutException;
@@ -44,17 +45,17 @@
     }
 
     @Test
-    @UiThreadTest
     @SmallTest
     public void testAlreadyInitializedSelector() throws InterruptedException, TimeoutException {
         final CallbackHelper registrationCompleteCallback = new CallbackHelper();
         TabModelSelectorTabModelObserver observer =
-                new TabModelSelectorTabModelObserver(mSelector) {
-                    @Override
-                    protected void onRegistrationComplete() {
-                        registrationCompleteCallback.notifyCalled();
-                    }
-                };
+                TestThreadUtils.runOnUiThreadBlockingNoException(
+                        () -> new TabModelSelectorTabModelObserver(mSelector) {
+                            @Override
+                            protected void onRegistrationComplete() {
+                                registrationCompleteCallback.notifyCalled();
+                            }
+                        });
         registrationCompleteCallback.waitForCallback(0);
         assertAllModelsHaveObserver(mSelector, observer);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserverTest.java
index ed4e7187..b169326c4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserverTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserverTest.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.tabmodel;
 
-import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.UiThreadTestRule;
 
@@ -14,7 +13,8 @@
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.ObserverList;
+import org.chromium.base.ObserverList.RewindableIterator;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBuilder;
@@ -22,6 +22,10 @@
 import org.chromium.chrome.browser.tab.TabTestUtils;
 import org.chromium.content_public.browser.LoadUrlParams;
 
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
 /**
  * Tests for the TabModelSelectorTabObserver.
  */
@@ -35,59 +39,51 @@
     public final RuleChain mChain = RuleChain.outerRule(mTestRule).around(new UiThreadTestRule());
 
     @Test
-    @UiThreadTest
     @SmallTest
     public void testAddingTab() {
-        TestTabModelSelectorTabObserver observer =
-                new TestTabModelSelectorTabObserver(mTestRule.getSelector());
+        TestTabModelSelectorTabObserver observer = createTabModelSelectorTabObserver();
         Tab tab = createTestTab(false);
-        assertTabDoesNotHaveObserver(tab, observer);
-        mTestRule.getNormalTabModel().addTab(tab, 0, TabLaunchType.FROM_LINK);
+        assertTabDoesNotHaveObserver(tab, observer, /* checkUnregistration= */ false);
+        addTab(mTestRule.getNormalTabModel(), tab);
         assertTabHasObserver(tab, observer);
     }
 
     @Test
-    @UiThreadTest
     @SmallTest
     public void testClosingTab() {
-        TestTabModelSelectorTabObserver observer =
-                new TestTabModelSelectorTabObserver(mTestRule.getSelector());
+        TestTabModelSelectorTabObserver observer = createTabModelSelectorTabObserver();
         Tab tab = createTestTab(false);
-        mTestRule.getNormalTabModel().addTab(tab, 0, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getNormalTabModel(), tab);
         assertTabHasObserver(tab, observer);
-        mTestRule.getNormalTabModel().closeTab(tab);
-        assertTabDoesNotHaveObserver(tab, observer);
+        closeTab(mTestRule.getNormalTabModel(), tab);
+        assertTabDoesNotHaveObserver(tab, observer, true);
     }
 
     @Test
-    @UiThreadTest
     @SmallTest
     public void testRemovingTab() {
-        TestTabModelSelectorTabObserver observer =
-                new TestTabModelSelectorTabObserver(mTestRule.getSelector());
+        TestTabModelSelectorTabObserver observer = createTabModelSelectorTabObserver();
         Tab tab = createTestTab(false);
-        mTestRule.getNormalTabModel().addTab(tab, 0, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getNormalTabModel(), tab);
         assertTabHasObserver(tab, observer);
-        mTestRule.getNormalTabModel().removeTab(tab);
-        assertTabDoesNotHaveObserver(tab, observer);
+        removeTab(mTestRule.getNormalTabModel(), tab);
+        assertTabDoesNotHaveObserver(tab, observer, true);
     }
 
     @Test
-    @UiThreadTest
     @SmallTest
     public void testPreExistingTabs() {
         Tab normalTab1 = createTestTab(false);
-        mTestRule.getNormalTabModel().addTab(normalTab1, 0, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getNormalTabModel(), normalTab1);
         Tab normalTab2 = createTestTab(false);
-        mTestRule.getNormalTabModel().addTab(normalTab2, 1, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getNormalTabModel(), normalTab2);
 
         Tab incognitoTab1 = createTestTab(true);
-        mTestRule.getIncognitoTabModel().addTab(incognitoTab1, 0, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getIncognitoTabModel(), incognitoTab1);
         Tab incognitoTab2 = createTestTab(true);
-        mTestRule.getIncognitoTabModel().addTab(incognitoTab2, 1, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getIncognitoTabModel(), incognitoTab2);
 
-        TestTabModelSelectorTabObserver observer =
-                new TestTabModelSelectorTabObserver(mTestRule.getSelector());
+        TestTabModelSelectorTabObserver observer = createTabModelSelectorTabObserver();
         assertTabHasObserver(normalTab1, observer);
         assertTabHasObserver(normalTab2, observer);
         assertTabHasObserver(incognitoTab1, observer);
@@ -95,26 +91,23 @@
     }
 
     @Test
-    @UiThreadTest
     @SmallTest
     public void testDestroyRemovesObserver() {
         Tab normalTab1 = createTestTab(false);
-        mTestRule.getNormalTabModel().addTab(normalTab1, 0, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getNormalTabModel(), normalTab1);
         Tab incognitoTab1 = createTestTab(true);
-        mTestRule.getIncognitoTabModel().addTab(incognitoTab1, 0, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getIncognitoTabModel(), incognitoTab1);
 
-        TestTabModelSelectorTabObserver observer =
-                new TestTabModelSelectorTabObserver(mTestRule.getSelector());
+        TestTabModelSelectorTabObserver observer = createTabModelSelectorTabObserver();
         assertTabHasObserver(normalTab1, observer);
         assertTabHasObserver(incognitoTab1, observer);
 
         observer.destroy();
-        assertTabDoesNotHaveObserver(normalTab1, observer);
-        assertTabDoesNotHaveObserver(incognitoTab1, observer);
+        assertTabDoesNotHaveObserver(normalTab1, observer, true);
+        assertTabDoesNotHaveObserver(incognitoTab1, observer, true);
     }
 
     @Test
-    @UiThreadTest
     @SmallTest
     public void testObserverAddedBeforeInitialize() {
         TabModelSelectorBase selector = new TabModelSelectorBase() {
@@ -124,54 +117,96 @@
                 return null;
             }
         };
-        TestTabModelSelectorTabObserver observer =
-                new TestTabModelSelectorTabObserver(mTestRule.getSelector());
+        TestTabModelSelectorTabObserver observer = createTabModelSelectorTabObserver();
         selector.initialize(false, mTestRule.getNormalTabModel(), mTestRule.getIncognitoTabModel());
 
         Tab normalTab1 = createTestTab(false);
-        mTestRule.getNormalTabModel().addTab(normalTab1, 0, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getNormalTabModel(), normalTab1);
         assertTabHasObserver(normalTab1, observer);
 
         Tab incognitoTab1 = createTestTab(true);
-        mTestRule.getIncognitoTabModel().addTab(incognitoTab1, 0, TabLaunchType.FROM_LINK);
+        addTab(mTestRule.getIncognitoTabModel(), incognitoTab1);
         assertTabHasObserver(incognitoTab1, observer);
     }
 
+    private TestTabModelSelectorTabObserver createTabModelSelectorTabObserver() {
+        return ThreadUtils.runOnUiThreadBlockingNoException(
+                () -> new TestTabModelSelectorTabObserver(mTestRule.getSelector()));
+    }
+
     private Tab createTestTab(boolean incognito) {
-        Tab testTab = new TabBuilder()
-                              .setIncognito(incognito)
-                              .setWindow(mTestRule.getWindowAndroid())
-                              .build();
-        testTab.initializeNative();
-        return testTab;
+        return ThreadUtils.runOnUiThreadBlockingNoException(() -> {
+            Tab testTab = new TabBuilder()
+                                  .setIncognito(incognito)
+                                  .setWindow(mTestRule.getWindowAndroid())
+                                  .build();
+            testTab.initializeNative();
+            return testTab;
+        });
+    }
+
+    private static void addTab(TabModel tabModel, Tab tab) {
+        ThreadUtils.runOnUiThreadBlocking(() -> tabModel.addTab(tab, 0, TabLaunchType.FROM_LINK));
+    }
+
+    private static void closeTab(TabModel tabModel, Tab tab) {
+        try {
+            ThreadUtils.runOnUiThreadBlocking(() -> tabModel.closeTab(tab));
+        } catch (ExecutionException e) {
+            throw new RuntimeException("Error occurred waiting for runnable", e);
+        }
+    }
+
+    private static void removeTab(TabModel tabModel, Tab tab) {
+        ThreadUtils.runOnUiThreadBlocking(() -> tabModel.removeTab(tab));
     }
 
     private static class TestTabModelSelectorTabObserver extends TabModelSelectorTabObserver {
+        public final Set<Tab> mRegisteredTabs = new HashSet<>();
+        public final Set<Tab> mUnregisteredTabs = new HashSet<>();
+
         public TestTabModelSelectorTabObserver(TabModelSelectorBase selector) {
             super(selector);
         }
+
+        @Override
+        protected void onTabRegistered(Tab tab) {
+            mRegisteredTabs.add(tab);
+        }
+
+        @Override
+        protected void onTabUnregistered(Tab tab) {
+            mUnregisteredTabs.add(tab);
+        }
+
+        private boolean isRegisteredTab(Tab tab) {
+            return mRegisteredTabs.contains(tab);
+        }
+
+        private boolean isUnregisteredTab(Tab tab) {
+            return mUnregisteredTabs.contains(tab);
+        }
     }
 
-    private void assertTabHasObserver(Tab tab, TabObserver observer) {
-        ObserverList.RewindableIterator<TabObserver> tabObservers =
-                TabTestUtils.getTabObservers(tab);
-        tabObservers.rewind();
-        boolean containsObserver = false;
-        while (tabObservers.hasNext()) {
-            if (tabObservers.next().equals(observer)) {
-                containsObserver = true;
-                break;
-            }
-        }
-        Assert.assertTrue(containsObserver);
+    private void assertTabHasObserver(Tab tab, TestTabModelSelectorTabObserver observer) {
+        Assert.assertTrue(tabHasObserver(tab, observer));
+        Assert.assertTrue(observer.isRegisteredTab(tab));
     }
 
-    private void assertTabDoesNotHaveObserver(Tab tab, TabObserver observer) {
-        ObserverList.RewindableIterator<TabObserver> tabObservers =
-                TabTestUtils.getTabObservers(tab);
-        tabObservers.rewind();
-        while (tabObservers.hasNext()) {
-            Assert.assertNotEquals(tabObservers.next(), observer);
-        }
+    private void assertTabDoesNotHaveObserver(
+            Tab tab, TestTabModelSelectorTabObserver observer, boolean checkUnregistration) {
+        Assert.assertFalse(tabHasObserver(tab, observer));
+        if (!checkUnregistration) return;
+        Assert.assertTrue(observer.isUnregisteredTab(tab));
+    }
+
+    private static boolean tabHasObserver(Tab tab, TestTabModelSelectorTabObserver observer) {
+        return ThreadUtils.runOnUiThreadBlockingNoException(() -> {
+            RewindableIterator<TabObserver> tabObservers = TabTestUtils.getTabObservers(tab);
+            tabObservers.rewind();
+            boolean found = false;
+            while (tabObservers.hasNext()) found |= observer.equals(tabObservers.next());
+            return found;
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java
index 1aa41ed..9d81db0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java
@@ -12,6 +12,7 @@
 import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE;
 
 import android.graphics.PointF;
+import android.os.SystemClock;
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
@@ -21,17 +22,22 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.vr.keyboard.TextEditAction;
 import org.chromium.chrome.browser.vr.mock.MockBrowserKeyboardInterface;
 import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityVrTestRule;
 import org.chromium.chrome.browser.vr.util.NativeUiUtils;
+import org.chromium.chrome.browser.vr.util.RenderTestUtils;
 import org.chromium.chrome.browser.vr.util.VrBrowserTransitionUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.RenderTestRule;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 
+import java.io.IOException;
+import java.util.HashMap;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -46,6 +52,10 @@
     @Rule
     public ChromeTabbedActivityVrTestRule mVrTestRule = new ChromeTabbedActivityVrTestRule();
 
+    @Rule
+    public RenderTestRule mRenderTestRule =
+            new RenderTestRule("components/test/data/vr_browser_video/render_tests");
+
     private VrBrowserTestFramework mVrBrowserTestFramework;
 
     @Before
@@ -419,4 +429,48 @@
                 "Keyboard did not hide from app button press", POLL_TIMEOUT_SHORT_MS,
                 POLL_CHECK_INTERVAL_SHORT_MS);
     }
+
+    /**
+     * Tests that video controls look correct in the VR browser and properly hide when the
+     * controller is pointed outside of the content quad.
+     */
+    @Test
+    @MediumTest
+    @Feature({"Browser", "RenderTest"})
+    public void testFullscreenVideoControls()
+            throws InterruptedException, TimeoutException, IOException {
+        VrBrowserTransitionUtils.forceEnterVrBrowserOrFail(POLL_TIMEOUT_LONG_MS);
+        NativeUiUtils.enableMockedInput();
+        mVrBrowserTestFramework.loadUrlAndAwaitInitialization(
+                VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_video_controls"),
+                PAGE_LOAD_TIMEOUT_S);
+
+        // Click the fullscreen button. We use a separate button instead of the controls' fullscreen
+        // button since that's more stable.
+        DOMUtils.clickNode(mVrBrowserTestFramework.getCurrentWebContents(), "fullscreen_button",
+                false /* goThroughRootAndroidView */);
+        mVrBrowserTestFramework.pollJavaScriptBooleanOrFail(
+                "document.getElementById('video_element').readyState === 4", POLL_TIMEOUT_LONG_MS);
+        // The readyState === 4 check only checks that the video can be played through without any
+        // buffering. Wait a bit after that to make sure that the video is actually fully loaded,
+        // and that the loading animation has stopped.
+        SystemClock.sleep(1000);
+
+        NativeUiUtils.waitForUiQuiescence();
+
+        HashMap<String, String> suffixToIds = new HashMap<String, String>();
+        suffixToIds.put(
+                NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_UI, "fullscreen_video_paused_browser_ui");
+        suffixToIds.put(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_CONTENT,
+                "fullscreen_video_paused_browser_content");
+        RenderTestUtils.dumpAndCompare(suffixToIds, null /* bounds */, mRenderTestRule);
+
+        // Start the video and hover outside of the content quad to make sure that the controls
+        // auto-hide.
+        NativeUiUtils.clickContentNode("video_element", new PointF(), 1, mVrBrowserTestFramework);
+        NativeUiUtils.hoverElement(UserFriendlyElementName.CONTENT_QUAD, new PointF(1.0f, 0.0f));
+        SystemClock.sleep(2000);
+        RenderTestUtils.dumpAndCompare(NativeUiUtils.FRAME_BUFFER_SUFFIX_BROWSER_CONTENT,
+                "fullscreen_video_playing_not_hovered_browser_content", mRenderTestRule);
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
index 73865c7..d125cc74 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
@@ -35,7 +35,7 @@
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryBarContents;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryTabType;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryMetricsRecorder;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.AutofillBarItem;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BarItem;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData;
@@ -499,7 +499,7 @@
                                        new Action("One", GENERATE_PASSWORD_AUTOMATIC, null)),
                         new BarItem(BarItem.Type.ACTION_BUTTON,
                                 new Action("Two", GENERATE_PASSWORD_AUTOMATIC, null))});
-        assertThat(getActionImpressionCount(GENERATE_PASSWORD_AUTOMATIC), is(1));
+        assertThat(getGenerationImpressionCount(), is(1));
         assertThat(getShownMetricsCount(AccessoryBarContents.WITH_ACTIONS), is(1));
 
         // Adding another action leaves bar impressions unchanged but affects the actions bucket.
@@ -509,12 +509,13 @@
                         new BarItem(BarItem.Type.ACTION_BUTTON,
                                 new Action("Dos", GENERATE_PASSWORD_AUTOMATIC, null))});
         assertThat(getShownMetricsCount(AccessoryBarContents.WITH_ACTIONS), is(1));
-        assertThat(getActionImpressionCount(GENERATE_PASSWORD_AUTOMATIC), is(2));
+        assertThat(getGenerationImpressionCount(), is(2));
     }
 
-    private int getActionImpressionCount(@AccessoryAction int bucket) {
+    private int getGenerationImpressionCount() {
         return RecordHistogram.getHistogramValueCountForTesting(
-                KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION, bucket);
+                ManualFillingMetricsRecorder.UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION,
+                AccessoryAction.GENERATE_PASSWORD_AUTOMATIC);
     }
 
     private int getShownMetricsCount(@AccessoryBarContents int bucket) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetControllerTest.java
index 96c5d69..c895aba5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_component/AccessorySheetControllerTest.java
@@ -34,7 +34,7 @@
 import org.chromium.base.task.test.CustomShadowAsyncTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTrigger;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryMetricsRecorder;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.Tab;
 import org.chromium.ui.modelutil.ListObservable;
 import org.chromium.ui.modelutil.PropertyKey;
@@ -246,7 +246,7 @@
     @Test
     public void testRecordsSheetClosure() {
         assertThat(RecordHistogram.getHistogramTotalCountForTesting(
-                           KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED),
+                           ManualFillingMetricsRecorder.UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED),
                 is(0));
 
         // Although sheets must be opened manually as of now, don't assume that every opened sheet
@@ -263,6 +263,6 @@
 
     private int getTriggerMetricsCount(@AccessorySheetTrigger int bucket) {
         return RecordHistogram.getHistogramValueCountForTesting(
-                KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED, bucket);
+                ManualFillingMetricsRecorder.UMA_KEYBOARD_ACCESSORY_SHEET_TRIGGERED, bucket);
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java
index 10cac64..ded87ad 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java
@@ -13,6 +13,9 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder.UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingMetricsRecorder.getHistogramForType;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabMetricsRecorder.UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabModel.AccessorySheetDataPiece.Type.FOOTER_COMMAND;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabModel.AccessorySheetDataPiece.Type.PASSWORD_INFO;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.sheet_tabs.AccessorySheetTabModel.AccessorySheetDataPiece.Type.TITLE;
@@ -36,7 +39,6 @@
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryTabType;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.FallbackSheetType;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryMetricsRecorder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.AccessorySheetData;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.data.KeyboardAccessoryData.FooterCommand;
@@ -184,9 +186,8 @@
     public void testRecordsSuggestionsImpressionsWhenShown() {
         final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>();
         mCoordinator.registerDataProvider(testProvider);
-        assertThat(
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS),
+        assertThat(RecordHistogram.getHistogramTotalCountForTesting(
+                           UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS),
                 is(0));
         assertThat(getSuggestionsImpressions(AccessoryTabType.PASSWORDS, 0), is(0));
         assertThat(getSuggestionsImpressions(AccessoryTabType.ALL, 0), is(0));
@@ -224,15 +225,12 @@
 
     private int getActionImpressions(@AccessoryAction int bucket) {
         return RecordHistogram.getHistogramValueCountForTesting(
-                KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION, bucket);
+                UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION, bucket);
     }
 
     private int getSuggestionsImpressions(@AccessoryTabType int type, int sample) {
         return RecordHistogram.getHistogramValueCountForTesting(
-                KeyboardAccessoryMetricsRecorder.getHistogramForType(
-                        KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS,
-                        type),
-                sample);
+                getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS, type), sample);
     }
 
     private void setAutofillFeature(boolean enabled) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
index c18d59b..42d957c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
@@ -105,8 +105,9 @@
 
         doNothing().when(activityTabProvider).addObserverAndTrigger(
                 activityTabObserverCaptor.capture());
-        doNothing().when(tabFromFactory).initialize(webContentsCaptor.capture(), any(), any(),
-                anyBoolean(), anyBoolean());
+        doNothing()
+                .when(tabFromFactory)
+                .initialize(webContentsCaptor.capture(), any(), anyBoolean(), anyBoolean());
     }
 
     @Override
@@ -117,11 +118,13 @@
 
     public CustomTabActivityTabController createTabController() {
         return new CustomTabActivityTabController(activity,
-                () -> customTabDelegateFactory, connection, intentDataProvider,
-                () -> tabContentManager, activityTabProvider,
-                tabObserverRegistrar, () -> compositorViewHolder, lifecycleDispatcher,
-                warmupManager, tabPersistencePolicy, tabFactory, () -> customTabObserver,
-                webContentsFactory, navigationEventObserver, tabProvider);
+                ()
+                        -> customTabDelegateFactory,
+                connection, intentDataProvider, activityTabProvider, tabObserverRegistrar,
+                ()
+                        -> compositorViewHolder,
+                lifecycleDispatcher, warmupManager, tabPersistencePolicy, tabFactory,
+                () -> customTabObserver, webContentsFactory, navigationEventObserver, tabProvider);
     }
 
     public CustomTabActivityNavigationController createNavigationController() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
index c2887fbe..9eb48f4 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
@@ -102,13 +102,6 @@
     }
 
     @Test
-    public void attachesTabContentManager_IfCreatedTabEarly() {
-        env.warmUp();
-        env.reachNativeInit(mTabController);
-        verify(env.tabFromFactory).attachTabContentManager(env.tabContentManager);
-    }
-
-    @Test
     public void addsEarlyCreatedTab_ToTabModel() {
         env.warmUp();
         env.reachNativeInit(mTabController);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java
index 0543e3b6..5b0eaee 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java
@@ -11,6 +11,7 @@
 import static org.mockito.Mockito.verify;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -22,6 +23,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.Promise;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.test.support.DisableHistogramsRule;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -32,8 +34,8 @@
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
 public class EventTrackerTest {
-    private EventTracker mEventTracker;
-
+    @Rule
+    public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
     @Mock
     private UsageStatsBridge mBridge;
     @Captor
@@ -45,6 +47,8 @@
     @Captor
     private ArgumentCaptor<Callback<Boolean>> mDeleteCallbackCaptor;
 
+    private EventTracker mEventTracker;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 563000c7..004659c8 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3912,10 +3912,10 @@
 
         <!-- Begin of Sync Promo strings for Desktop Identity Consistency. -->
         <message name="IDS_EXTENSION_INSTALLED_DICE_PROMO_SIGNIN_MESSAGE" desc="Text of the sync promo displayed at the bottom of the extension installed bubble asking the user to sign in and enable sync.">
-          To get all your extensions on all your devices, sign in and turn on sync.
+          To get your extensions on all your computers, sign in and turn on sync
         </message>
         <message name="IDS_EXTENSION_INSTALLED_DICE_PROMO_SYNC_MESSAGE" desc="Text of the sync promo displayed at the bottom of the extension installed bubble asking the user to enable sync.">
-          To get all your extensions on all your devices, turn on sync.
+          To get your extensions on all your computers, turn on sync
         </message>
         <!-- End of Sync Promo strings for Desktop Identity Consistency. -->
       </if>
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_INSTALLED_DICE_PROMO_SYNC_MESSAGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_INSTALLED_DICE_PROMO_SYNC_MESSAGE.png.sha1
new file mode 100644
index 0000000..db30428
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSION_INSTALLED_DICE_PROMO_SYNC_MESSAGE.png.sha1
@@ -0,0 +1 @@
+351879bf6e69a05c20c8ea9e8c37719305bd547c
\ No newline at end of file
diff --git a/chrome/app_shim/app_shim_controller.mm b/chrome/app_shim/app_shim_controller.mm
index ce6c9d250..05b8c1a 100644
--- a/chrome/app_shim/app_shim_controller.mm
+++ b/chrome/app_shim/app_shim_controller.mm
@@ -12,9 +12,9 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/mach_logging.h"
-#include "base/md5.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app_shim/app_shim_delegate.h"
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 2de956d..8a28ab4 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2723,7 +2723,7 @@
       "//services/identity/public/cpp",
       "//services/proxy_resolver:lib",
       "//third_party/android_opengl/etc1",
-      "//third_party/android_tools:cpu_features",
+      "//third_party/android_sdk:cpu_features",
       "//third_party/libaddressinput:util",
       "//third_party/libphonenumber",
       "//third_party/smhasher:murmurhash2",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 0cfc9b7..5918c2e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -725,35 +725,66 @@
          nullptr}};
 #endif  // OS_ANDROID
 
-const FeatureEntry::Choice kEnableOutOfProcessHeapProfilingChoices[] = {
+const FeatureEntry::Choice kMemlogModeChoices[] = {
     {flags_ui::kGenericExperimentChoiceDisabled, "", ""},
-    {flag_descriptions::kEnableOutOfProcessHeapProfilingModeMinimal,
-     heap_profiling::kMemlog, heap_profiling::kMemlogModeMinimal},
-    {flag_descriptions::kEnableOutOfProcessHeapProfilingModeAll,
-     heap_profiling::kMemlog, heap_profiling::kMemlogModeAll},
-    {flag_descriptions::kEnableOutOfProcessHeapProfilingModeBrowser,
-     heap_profiling::kMemlog, heap_profiling::kMemlogModeBrowser},
-    {flag_descriptions::kEnableOutOfProcessHeapProfilingModeGpu,
-     heap_profiling::kMemlog, heap_profiling::kMemlogModeGpu},
-    {flag_descriptions::kEnableOutOfProcessHeapProfilingModeAllRenderers,
-     heap_profiling::kMemlog, heap_profiling::kMemlogModeAllRenderers},
-    {flag_descriptions::kEnableOutOfProcessHeapProfilingModeManual,
-     heap_profiling::kMemlog, heap_profiling::kMemlogModeManual},
+    {flag_descriptions::kMemlogModeMinimal, heap_profiling::kMemlogMode,
+     heap_profiling::kMemlogModeMinimal},
+    {flag_descriptions::kMemlogModeAll, heap_profiling::kMemlogMode,
+     heap_profiling::kMemlogModeAll},
+    {flag_descriptions::kMemlogModeBrowser, heap_profiling::kMemlogMode,
+     heap_profiling::kMemlogModeBrowser},
+    {flag_descriptions::kMemlogModeGpu, heap_profiling::kMemlogMode,
+     heap_profiling::kMemlogModeGpu},
+    {flag_descriptions::kMemlogModeAllRenderers, heap_profiling::kMemlogMode,
+     heap_profiling::kMemlogModeAllRenderers},
+    {flag_descriptions::kMemlogModeRendererSampling,
+     heap_profiling::kMemlogMode, heap_profiling::kMemlogModeRendererSampling},
 };
 
-const FeatureEntry::Choice kOOPHPStackModeChoices[] = {
-    {flags_ui::kGenericExperimentChoiceDisabled, "", ""},
-    {flag_descriptions::kOOPHPStackModeNative, heap_profiling::kMemlogStackMode,
-     heap_profiling::kMemlogStackModeNative},
-    {flag_descriptions::kOOPHPStackModeNativeWithThreadNames,
+const FeatureEntry::Choice kMemlogStackModeChoices[] = {
+    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
+    {flag_descriptions::kMemlogStackModeNative,
+     heap_profiling::kMemlogStackMode, heap_profiling::kMemlogStackModeNative},
+    {flag_descriptions::kMemlogStackModeNativeWithThreadNames,
      heap_profiling::kMemlogStackMode,
      heap_profiling::kMemlogStackModeNativeWithThreadNames},
-    {flag_descriptions::kOOPHPStackModePseudo, heap_profiling::kMemlogStackMode,
-     heap_profiling::kMemlogStackModePseudo},
-    {flag_descriptions::kOOPHPStackModeMixed, heap_profiling::kMemlogStackMode,
+    {flag_descriptions::kMemlogStackModePseudo,
+     heap_profiling::kMemlogStackMode, heap_profiling::kMemlogStackModePseudo},
+    {flag_descriptions::kMemlogStackModeMixed, heap_profiling::kMemlogStackMode,
      heap_profiling::kMemlogStackModeMixed},
 };
 
+const FeatureEntry::Choice kMemlogInProcessChoices[] = {
+    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
+    {flag_descriptions::kMemlogInProcessDisabled,
+     heap_profiling::kMemlogInProcess,
+     heap_profiling::kMemlogInProcessDisabled},
+    {flag_descriptions::kMemlogInProcessEnabled,
+     heap_profiling::kMemlogInProcess, heap_profiling::kMemlogInProcessEnabled},
+};
+
+const FeatureEntry::Choice kMemlogSamplingRateChoices[] = {
+    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
+    {flag_descriptions::kMemlogSamplingRate10KB,
+     heap_profiling::kMemlogSamplingRate,
+     heap_profiling::kMemlogSamplingRate10KB},
+    {flag_descriptions::kMemlogSamplingRate50KB,
+     heap_profiling::kMemlogSamplingRate,
+     heap_profiling::kMemlogSamplingRate50KB},
+    {flag_descriptions::kMemlogSamplingRate100KB,
+     heap_profiling::kMemlogSamplingRate,
+     heap_profiling::kMemlogSamplingRate100KB},
+    {flag_descriptions::kMemlogSamplingRate500KB,
+     heap_profiling::kMemlogSamplingRate,
+     heap_profiling::kMemlogSamplingRate500KB},
+    {flag_descriptions::kMemlogSamplingRate1MB,
+     heap_profiling::kMemlogSamplingRate,
+     heap_profiling::kMemlogSamplingRate1MB},
+    {flag_descriptions::kMemlogSamplingRate5MB,
+     heap_profiling::kMemlogSamplingRate,
+     heap_profiling::kMemlogSamplingRate5MB},
+};
+
 const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches3[] = {
     {OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "3"}};
 const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches4[] = {
@@ -1699,6 +1730,9 @@
      flag_descriptions::kStrictSiteIsolationDescription, kOsAndroid,
      SINGLE_VALUE_TYPE(switches::kSitePerProcess)},
 #endif
+    {"isolate-origins", flag_descriptions::kIsolateOriginsName,
+     flag_descriptions::kIsolateOriginsDescription, kOsAll,
+     ORIGIN_LIST_VALUE_TYPE(switches::kIsolateOrigins, "")},
     {"site-isolation-trial-opt-out",
      flag_descriptions::kSiteIsolationOptOutName,
      flag_descriptions::kSiteIsolationOptOutDescription, kOsAll,
@@ -2101,11 +2135,6 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(ntp_snippets::kArticleSuggestionsFeature,
                                     kRemoteSuggestionsFeatureVariations,
                                     "NTPArticleSuggestions")},
-    {"enable-ntp-asset-download-suggestions",
-     flag_descriptions::kEnableNtpAssetDownloadSuggestionsName,
-     flag_descriptions::kEnableNtpAssetDownloadSuggestionsDescription,
-     kOsAndroid,
-     FEATURE_VALUE_TYPE(features::kAssetDownloadSuggestionsFeature)},
     {"enable-ntp-offline-page-download-suggestions",
      flag_descriptions::kEnableNtpOfflinePageDownloadSuggestionsName,
      flag_descriptions::kEnableNtpOfflinePageDownloadSuggestionsDescription,
@@ -2635,23 +2664,21 @@
      flag_descriptions::kSamplingHeapProfilerDescription, kOsAll,
      SINGLE_VALUE_TYPE(switches::kSamplingHeapProfiler)},
 
-    {"memlog", flag_descriptions::kEnableOutOfProcessHeapProfilingName,
-     flag_descriptions::kEnableOutOfProcessHeapProfilingDescription, kOsAll,
-     MULTI_VALUE_TYPE(kEnableOutOfProcessHeapProfilingChoices)},
+    {"memlog", flag_descriptions::kMemlogName,
+     flag_descriptions::kMemlogDescription, kOsAll,
+     MULTI_VALUE_TYPE(kMemlogModeChoices)},
 
-    {"memlog-in-process",
-     flag_descriptions::kOutOfProcessHeapProfilingInProcess,
-     flag_descriptions::kOutOfProcessHeapProfilingInProcessDescription, kOsAll,
-     SINGLE_VALUE_TYPE(heap_profiling::kMemlogInProcess)},
+    {"memlog-in-process", flag_descriptions::kMemlogInProcessName,
+     flag_descriptions::kMemlogInProcessDescription, kOsAll,
+     MULTI_VALUE_TYPE(kMemlogInProcessChoices)},
 
-    {"memlog-sampling-rate",
-     flag_descriptions::kOutOfProcessHeapProfilingSamplingRate,
-     flag_descriptions::kOutOfProcessHeapProfilingSamplingRateDescription,
-     kOsAll, SINGLE_VALUE_TYPE(heap_profiling::kMemlogSamplingRate)},
+    {"memlog-sampling-rate", flag_descriptions::kMemlogSamplingRateName,
+     flag_descriptions::kMemlogSamplingRateDescription, kOsAll,
+     MULTI_VALUE_TYPE(kMemlogSamplingRateChoices)},
 
-    {"memlog-stack-mode", flag_descriptions::kOOPHPStackModeName,
-     flag_descriptions::kOOPHPStackModeDescription, kOsAll,
-     MULTI_VALUE_TYPE(kOOPHPStackModeChoices)},
+    {"memlog-stack-mode", flag_descriptions::kMemlogStackModeName,
+     flag_descriptions::kMemlogStackModeDescription, kOsAll,
+     MULTI_VALUE_TYPE(kMemlogStackModeChoices)},
 
     {"omnibox-ui-hide-steady-state-url-scheme",
      flag_descriptions::kOmniboxUIHideSteadyStateUrlSchemeName,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index e3d91949..6905966 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -169,6 +169,7 @@
     &kTabSwitcherOnReturn,
     &kTrustedWebActivity,
     &kTrustedWebActivityPostMessage,
+    &kUsageStatsFeature,
     &kVideoPersistence,
     &kVrBrowsingFeedback,
     &network::features::kNetworkService,
@@ -486,6 +487,9 @@
 const base::Feature kTrustedWebActivityPostMessage{
     "TrustedWebActivityPostMessage", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kUsageStatsFeature{"UsageStats",
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
+
 const base::Feature kUserMediaScreenCapturing{
     "UserMediaScreenCapturing", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index ca38c3e..6b2a619 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -99,6 +99,7 @@
 extern const base::Feature kTabSwitcherOnReturn;
 extern const base::Feature kTrustedWebActivity;
 extern const base::Feature kTrustedWebActivityPostMessage;
+extern const base::Feature kUsageStatsFeature;
 extern const base::Feature kUserMediaScreenCapturing;
 extern const base::Feature kVideoPersistence;
 extern const base::Feature kVrBrowsingFeedback;
diff --git a/chrome/browser/android/compositor/tab_content_manager.cc b/chrome/browser/android/compositor/tab_content_manager.cc
index 9bc082f..c2a97c27 100644
--- a/chrome/browser/android/compositor/tab_content_manager.cc
+++ b/chrome/browser/android/compositor/tab_content_manager.cc
@@ -169,8 +169,12 @@
   return static_layer;
 }
 
-void TabContentManager::AttachLiveLayer(int tab_id,
-                                        scoped_refptr<cc::Layer> layer) {
+void TabContentManager::AttachTab(JNIEnv* env,
+                                  const JavaParamRef<jobject>& obj,
+                                  const JavaParamRef<jobject>& jtab,
+                                  jint tab_id) {
+  TabAndroid* tab = TabAndroid::GetNativeTab(env, jtab);
+  scoped_refptr<cc::Layer> layer = tab->GetContentLayer();
   if (!layer.get())
     return;
 
@@ -179,14 +183,18 @@
     live_layer_list_[tab_id] = layer;
 }
 
-void TabContentManager::DetachLiveLayer(int tab_id,
-                                        scoped_refptr<cc::Layer> layer) {
+void TabContentManager::DetachTab(JNIEnv* env,
+                                  const JavaParamRef<jobject>& obj,
+                                  const JavaParamRef<jobject>& jtab,
+                                  jint tab_id) {
   scoped_refptr<cc::Layer> current_layer = live_layer_list_[tab_id];
   if (!current_layer.get()) {
     // Empty cached layer should not exist but it is ok if it happens.
     return;
   }
 
+  TabAndroid* tab = TabAndroid::GetNativeTab(env, jtab);
+  scoped_refptr<cc::Layer> layer = tab->GetContentLayer();
   // We need to remove if we're getting a detach for our current layer or we're
   // getting a detach with NULL and we have a current layer, which means remove
   //  all layers.
diff --git a/chrome/browser/android/compositor/tab_content_manager.h b/chrome/browser/android/compositor/tab_content_manager.h
index 95db6be..f2154891 100644
--- a/chrome/browser/android/compositor/tab_content_manager.h
+++ b/chrome/browser/android/compositor/tab_content_manager.h
@@ -60,17 +60,22 @@
   // Get the static thumbnail from the cache, or the NTP.
   scoped_refptr<ThumbnailLayer> GetOrCreateStaticLayer(int tab_id,
                                                        bool force_disk_read);
+  // JNI methods.
 
   // Should be called when a tab gets a new live layer that should be served
   // by the cache to the CompositorView.
-  void AttachLiveLayer(int tab_id, scoped_refptr<cc::Layer> layer);
+  void AttachTab(JNIEnv* env,
+                 const base::android::JavaParamRef<jobject>& obj,
+                 const base::android::JavaParamRef<jobject>& jtab,
+                 jint tab_id);
 
   // Should be called when a tab removes a live layer because it should no
   // longer be served by the CompositorView.  If |layer| is NULL, will
   // make sure all live layers are detached.
-  void DetachLiveLayer(int tab_id, scoped_refptr<cc::Layer> layer);
-
-  // JNI methods.
+  void DetachTab(JNIEnv* env,
+                 const base::android::JavaParamRef<jobject>& obj,
+                 const base::android::JavaParamRef<jobject>& jtab,
+                 jint tab_id);
   jboolean HasFullCachedThumbnail(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/locale/locale_manager.cc b/chrome/browser/android/locale/locale_manager.cc
index ec93c3c..89f1af3 100644
--- a/chrome/browser/android/locale/locale_manager.cc
+++ b/chrome/browser/android/locale/locale_manager.cc
@@ -27,3 +27,11 @@
   return base::android::ConvertJavaStringToUTF8(
       env, Java_LocaleManager_getMailRUReferralId(env, jlocale_manager));
 }
+
+// static
+void LocaleManager::RecordUserTypeMetrics() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jobject> jlocale_manager =
+      Java_LocaleManager_getInstance(env);
+  return Java_LocaleManager_recordUserTypeMetrics(env, jlocale_manager);
+}
diff --git a/chrome/browser/android/locale/locale_manager.h b/chrome/browser/android/locale/locale_manager.h
index 34cff2e1..6cff5188 100644
--- a/chrome/browser/android/locale/locale_manager.h
+++ b/chrome/browser/android/locale/locale_manager.h
@@ -15,6 +15,7 @@
  public:
   static std::string GetYandexReferralID();
   static std::string GetMailRUReferralID();
+  static void RecordUserTypeMetrics();
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(LocaleManager);
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 7d29af0..c922cbd 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -627,28 +627,6 @@
   web_contents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
 }
 
-void TabAndroid::AttachToTabContentManager(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jobject>& jtab_content_manager) {
-  android::TabContentManager* tab_content_manager =
-      android::TabContentManager::FromJavaObject(jtab_content_manager);
-  if (tab_content_manager == tab_content_manager_)
-    return;
-
-  if (tab_content_manager_)
-    tab_content_manager_->DetachLiveLayer(GetAndroidId(), GetContentLayer());
-  tab_content_manager_ = tab_content_manager;
-  if (tab_content_manager_)
-    tab_content_manager_->AttachLiveLayer(GetAndroidId(), GetContentLayer());
-}
-
-void TabAndroid::ClearThumbnailPlaceholder(JNIEnv* env,
-                                           const JavaParamRef<jobject>& obj) {
-  if (tab_content_manager_)
-    tab_content_manager_->NativeRemoveTabThumbnail(GetAndroidId());
-}
-
 bool TabAndroid::AreRendererInputEventsIgnored(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj) {
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index 896cd3073..6d26843 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -194,16 +194,6 @@
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jobject>& delegate);
 
-  // TODO(dtrainor): Remove this, pull content_layer() on demand.
-  void AttachToTabContentManager(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jobject>& jtab_content_manager);
-
-  void ClearThumbnailPlaceholder(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-
   bool HasPrerenderedUrl(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj,
                          const base::android::JavaParamRef<jstring>& url);
diff --git a/chrome/browser/apps/app_service/app_icon_source.cc b/chrome/browser/apps/app_service/app_icon_source.cc
index 90cb9b3..0a16d96 100644
--- a/chrome/browser/apps/app_service/app_icon_source.cc
+++ b/chrome/browser/apps/app_service/app_icon_source.cc
@@ -51,17 +51,6 @@
 
 AppIconSource::~AppIconSource() = default;
 
-bool AppIconSource::AllowCaching() const {
-  // Should not be cached as caching is performed by proxy.
-  return false;
-}
-
-std::string AppIconSource::GetMimeType(const std::string&) const {
-  // We need to explicitly return a mime type, otherwise if the user tries to
-  // drag the image they get no extension.
-  return "image/png";
-}
-
 std::string AppIconSource::GetSource() const {
   return chrome::kChromeUIAppIconHost;
 }
@@ -105,4 +94,20 @@
       allow_placeholder_icon, base::BindOnce(&RunCallback, callback));
 }
 
+std::string AppIconSource::GetMimeType(const std::string&) const {
+  // We need to explicitly return a mime type, otherwise if the user tries to
+  // drag the image they get no extension.
+  return "image/png";
+}
+
+bool AppIconSource::AllowCaching() const {
+  // Should not be cached as caching is performed by proxy.
+  return false;
+}
+
+bool AppIconSource::ShouldReplaceExistingSource() const {
+  // The source doesn't maintain its own state so there's no need to replace it.
+  return false;
+}
+
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/app_icon_source.h b/chrome/browser/apps/app_service/app_icon_source.h
index 41e3ae5..9d2a9573 100644
--- a/chrome/browser/apps/app_service/app_icon_source.h
+++ b/chrome/browser/apps/app_service/app_icon_source.h
@@ -15,8 +15,8 @@
 // AppIconSource serves app icons through the AppServiceProxy.
 // Icons can be retrieved for any installed app.
 //
-// To request an icon a call must first be made to chrome://apps
-// as the URLDataSource is first initialised in that page's handler.
+// To request an icon the AppIconSource must have been initialized via
+// content::URLDataSource::Add().
 //
 // The format for requesting an icon is as follows:
 //   chrome://app-icon/<app_id>/<icon_size>
@@ -35,13 +35,14 @@
   ~AppIconSource() override;
 
   // content::URLDataSource implementation.
-  bool AllowCaching() const override;
-  std::string GetMimeType(const std::string&) const override;
   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;
+  bool AllowCaching() const override;
+  bool ShouldReplaceExistingSource() const override;
 
  private:
   Profile* profile_;
diff --git a/chrome/browser/apps/app_shim/app_shim_host_manager_mac.mm b/chrome/browser/apps/app_shim/app_shim_host_manager_mac.mm
index 9627ee5..e3129934 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_manager_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_host_manager_mac.mm
@@ -9,8 +9,8 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/path_service.h"
 #include "base/task/post_task.h"
 #include "base/threading/scoped_blocking_call.h"
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
index 6d83230..ccf9324 100644
--- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
+++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
@@ -13,11 +13,11 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/macros.h"
-#include "base/sha1.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h"
diff --git a/chrome/browser/browsing_data/browsing_data_appcache_helper.cc b/chrome/browser/browsing_data/browsing_data_appcache_helper.cc
index 2b7869e8..6be57b42 100644
--- a/chrome/browser/browsing_data/browsing_data_appcache_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_appcache_helper.cc
@@ -46,7 +46,13 @@
     int64_t total_size = 0;
     for (const auto& info : origin_info.second) {
       last_modified = std::max(last_modified, info.last_update_time);
-      total_size += info.size;
+      // The sizes only cover the on-disk response sizes. They do not include
+      // the padding sizes added by the Quota system to cross-origin resources.
+      //
+      // We count the actual disk usage because this number is only reported in
+      // UI (not in any API accessible to the site). This decision may need to
+      // be revisited if users are confused by the Quota system's decisions.
+      total_size += info.response_sizes;
     }
     result.emplace_back(origin, total_size, last_modified);
   }
diff --git a/chrome/browser/browsing_data/canonical_cookie_hash.cc b/chrome/browser/browsing_data/canonical_cookie_hash.cc
index 7cb590e..1ee21c9 100644
--- a/chrome/browser/browsing_data/canonical_cookie_hash.cc
+++ b/chrome/browser/browsing_data/canonical_cookie_hash.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/browsing_data/canonical_cookie_hash.h"
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 
 namespace canonical_cookie {
 
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc
index caef03e5..c1ae2fe9 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.cc
+++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -9,10 +9,10 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/hash/sha1.h"
 #include "base/i18n/timezone.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "base/sha1.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
index 0bc6b77..f182ce4 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
@@ -12,6 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h"
+#include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h"
 #include "chrome/browser/chromeos/file_manager/app_id.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/file_manager/path_util.h"
@@ -124,6 +125,22 @@
   NOTREACHED();
 }
 
+base::FilePath GetInitialFilePath(const mojom::SelectFilesRequestPtr& request) {
+  const mojom::DocumentPathPtr& document_path = request->initial_document_path;
+  if (!document_path)
+    return base::FilePath();
+
+  if (document_path->path.empty()) {
+    LOG(ERROR) << "path should at least contain root Document ID.";
+    return base::FilePath();
+  }
+
+  const std::string& root_document_id = document_path->path[0];
+  // TODO(niwa): Convert non-root document IDs to the relative path and append.
+  return arc::GetDocumentsProviderMountPath(document_path->authority,
+                                            root_document_id);
+}
+
 void BuildFileTypeInfo(const mojom::SelectFilesRequestPtr& request,
                        ui::SelectFileDialog::FileTypeInfo* file_type_info) {
   file_type_info->allowed_paths = ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
@@ -168,11 +185,12 @@
   ui::SelectFileDialog::Type dialog_type = GetDialogType(request);
   ui::SelectFileDialog::FileTypeInfo file_type_info;
   BuildFileTypeInfo(request, &file_type_info);
+  base::FilePath default_path = GetInitialFilePath(request);
 
   select_file_dialog_->SelectFile(
       dialog_type,
       /*title=*/base::string16(),
-      /*default_path=*/base::FilePath(), &file_type_info,
+      /*default_path=*/default_path, &file_type_info,
       /*file_type_index=*/0,
       /*default_extension=*/base::FilePath::StringType(),
       /*owning_window=*/nullptr,
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 258feabf..34a1533 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
@@ -39,6 +39,11 @@
   return true;
 }
 
+MATCHER_P(FilePathMatcher, expected, "") {
+  EXPECT_EQ(expected.value(), arg.value());
+  return true;
+}
+
 MATCHER_P(FileSelectorElementsMatcher, expected, "") {
   EXPECT_EQ(expected->directory_elements.size(),
             arg->directory_elements.size());
@@ -221,6 +226,26 @@
   arc_select_files_handler_->SelectFiles(request, callback.Get());
 }
 
+TEST_F(ArcSelectFilesHandlerTest, SelectFiles_InitialDocumentPath) {
+  SelectFilesRequestPtr request = SelectFilesRequest::New();
+  request->action_type = SelectFilesActionType::OPEN_DOCUMENT;
+  request->initial_document_path = arc::mojom::DocumentPath::New();
+  request->initial_document_path->authority = "testing.provider";
+  request->initial_document_path->path = {"doc:root", "doc:file1"};
+
+  // "doc:file1" is expected to be ignored.
+  base::FilePath expected_file_path = base::FilePath(
+      "/special/arc-documents-provider/testing.provider/doc:root");
+
+  EXPECT_CALL(
+      *mock_dialog_,
+      SelectFileImpl(_, _, FilePathMatcher(expected_file_path), _, _, _, _, _))
+      .Times(1);
+
+  base::MockCallback<SelectFilesCallback> callback;
+  arc_select_files_handler_->SelectFiles(request, callback.Get());
+}
+
 TEST_F(ArcSelectFilesHandlerTest, FileSelected_CallbackCalled) {
   SelectFilesRequestPtr request = SelectFilesRequest::New();
   request->action_type = SelectFilesActionType::OPEN_DOCUMENT;
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
index ce2583e..f2eb3603 100644
--- a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
+++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
@@ -7,9 +7,9 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/hash/sha1.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/sha1.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/arc/extensions/fake_arc_support.h"
diff --git a/chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.cc b/chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.cc
index cd65db9..647f68863 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.cc
@@ -10,15 +10,17 @@
 constexpr base::TimeDelta ArcGraphicsJankDetector::kPauseDetectionThreshold;
 
 ArcGraphicsJankDetector::ArcGraphicsJankDetector(const JankCallback& callback)
-    : callback_(callback),
-      stage_(Stage::kWarmUp),
-      last_sample_time_(base::Time::Now()),
-      warm_up_sample_cnt_(kWarmUpSamples) {}
+    : callback_(callback) {
+  Reset();
+}
 
 ArcGraphicsJankDetector::~ArcGraphicsJankDetector() = default;
 
-void ArcGraphicsJankDetector::OnSample() {
-  OnSample(base::Time::Now());
+void ArcGraphicsJankDetector::Reset() {
+  stage_ = Stage::kWarmUp;
+  last_sample_time_ = base::Time::Now();
+  warm_up_sample_cnt_ = kWarmUpSamples;
+  period_fixed_ = false;
 }
 
 void ArcGraphicsJankDetector::SetPeriodFixed(const base::TimeDelta& period) {
@@ -27,6 +29,10 @@
   stage_ = Stage::kActive;
 }
 
+void ArcGraphicsJankDetector::OnSample() {
+  OnSample(base::Time::Now());
+}
+
 void ArcGraphicsJankDetector::OnSample(const base::Time& timestamp) {
   const base::TimeDelta delta = timestamp - last_sample_time_;
   last_sample_time_ = timestamp;
diff --git a/chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.h b/chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.h
index 4fb09fa..e40dd819 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.h
+++ b/chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.h
@@ -58,6 +58,11 @@
   explicit ArcGraphicsJankDetector(const JankCallback& callback);
   ~ArcGraphicsJankDetector();
 
+  // Resets detector to its initial state, stage is set to |Stage::kWarmUp| with
+  // the initial number of warm up samples. Fixed period is discarded if it was
+  // set.
+  void Reset();
+
   // Sets the expected refresh rate. This disables |Stage::kWarmUp| and
   // |Stage::kRateDetection| stages and keeps detector in |Stage::kActive|
   // stage.
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 85f649d..953d792 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.cc
@@ -856,9 +856,9 @@
     out_events->buffer_events().emplace_back(std::move(events));
   }
 
-  const base::Value* const jank_entries =
+  const base::Value* const global_events =
       dictionary->FindKeyOfType(kKeyGlobalEvents, base::Value::Type::LIST);
-  if (!LoadEvents(jank_entries, &out_events->global_events()))
+  if (!LoadEvents(global_events, &out_events->global_events()))
     return false;
 
   return true;
@@ -964,6 +964,7 @@
              BufferEventType::kBufferFillJank);
     AddJanks(&it.second, BufferEventType::kExoSurfaceAttach,
              BufferEventType::kExoJank);
+    SortBufferEventsByTimestamp(&it.second.global_events());
   }
 
   GetChromeTopLevelEvents(common_model, &chrome_top_level_);
@@ -1072,14 +1073,18 @@
 
 bool ArcTracingGraphicsModel::LoadFromJson(const std::string& json_data) {
   Reset();
-
   const std::unique_ptr<base::DictionaryValue> root =
       base::DictionaryValue::From(base::JSONReader::ReadDeprecated(json_data));
   if (!root)
     return false;
+  return LoadFromValue(*root);
+}
+
+bool ArcTracingGraphicsModel::LoadFromValue(const base::DictionaryValue& root) {
+  Reset();
 
   const base::Value* view_list =
-      root->FindKeyOfType(kKeyViews, base::Value::Type::LIST);
+      root.FindKeyOfType(kKeyViews, base::Value::Type::LIST);
   if (!view_list || view_list->GetList().empty())
     return false;
 
@@ -1100,13 +1105,13 @@
       return false;
   }
 
-  if (!LoadEventsContainer(root->FindKey(kKeyAndroid), &android_top_level_))
+  if (!LoadEventsContainer(root.FindKey(kKeyAndroid), &android_top_level_))
     return false;
 
-  if (!LoadEventsContainer(root->FindKey(kKeyChrome), &chrome_top_level_))
+  if (!LoadEventsContainer(root.FindKey(kKeyChrome), &chrome_top_level_))
     return false;
 
-  const base::Value* duration = root->FindKey(kKeyDuration);
+  const base::Value* duration = root.FindKey(kKeyDuration);
   if (!duration || (!duration->is_double() && !duration->is_int()))
     return false;
 
diff --git a/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h b/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h
index 6deefa8..f8f6324 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h
@@ -140,6 +140,8 @@
   std::string SerializeToJson() const;
   // Loads the model from Json string.
   bool LoadFromJson(const std::string& json_data);
+  // Loads the model from |base::DictionaryValue|.
+  bool LoadFromValue(const base::DictionaryValue& root);
 
   uint64_t duration() const { return duration_; }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path.cc b/chrome/browser/chromeos/crostini/crostini_share_path.cc
index edfe05c..32af7e1b 100644
--- a/chrome/browser/chromeos/crostini/crostini_share_path.cc
+++ b/chrome/browser/chromeos/crostini/crostini_share_path.cc
@@ -277,7 +277,7 @@
   if (persist) {
     RegisterPersistedPath(path);
   }
-  RegisterSharedPath(path, vm_name);
+  RegisterSharedPath(vm_name, path);
 
   request.mutable_shared_path()->set_path(relative_path.value());
   request.mutable_shared_path()->set_writable(true);
@@ -392,7 +392,7 @@
 
   CallSeneschalUnsharePath(vm_name, path, std::move(callback));
   for (Observer& observer : observers_) {
-    observer.OnUnshare(path, vm_name);
+    observer.OnUnshare(vm_name, path);
   }
 }
 
@@ -421,7 +421,7 @@
     }
     migrated_paths.AppendString(path.value());
     result.emplace_back(path);
-    RegisterSharedPath(path, kCrostiniDefaultVmName);
+    RegisterSharedPath(kCrostiniDefaultVmName, path);
   }
 
   // If any paths were modified during migration, update prefs.
@@ -519,8 +519,8 @@
                                            base::Unretained(this)));
 }
 
-void CrostiniSharePath::RegisterSharedPath(const base::FilePath& path,
-                                           const std::string& vm_name) {
+void CrostiniSharePath::RegisterSharedPath(const std::string& vm_name,
+                                           const base::FilePath& path) {
   // Paths may be called to be shared multiple times for the same or different
   // vm.  If path is already registered, add vm_name to list of VMs shared with
   // and return.
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path.h b/chrome/browser/chromeos/crostini/crostini_share_path.h
index 68fd05bd..34f648c1 100644
--- a/chrome/browser/chromeos/crostini/crostini_share_path.h
+++ b/chrome/browser/chromeos/crostini/crostini_share_path.h
@@ -50,8 +50,8 @@
                                    std::string failure_reason)>;
   class Observer {
    public:
-    virtual void OnUnshare(const base::FilePath& path,
-                           const std::string& vm_name) = 0;
+    virtual void OnUnshare(const std::string& vm_name,
+                           const base::FilePath& path) = 0;
   };
 
   static CrostiniSharePath* GetForProfile(Profile* profile);
@@ -113,8 +113,8 @@
   // detect when the path has been deleted.  If the path is deleted, we unshare
   // the path, and remove it from prefs if it was persisted.
   // Visible for testing.
-  void RegisterSharedPath(const base::FilePath& path,
-                          const std::string& vm_name);
+  void RegisterSharedPath(const std::string& vm_name,
+                          const base::FilePath& path);
 
   // Runs on UI Thread to handle when a path is deleted.
   // Visible for testing.
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc b/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
index 2e91484..2fcc58af 100644
--- a/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
@@ -203,8 +203,8 @@
     base::ListValue* shared_paths = update.Get();
     shared_paths->Append(std::make_unique<base::Value>(shared_path_.value()));
     volume_downloads_ = file_manager::Volume::CreateForDownloads(root_);
-    crostini_share_path_->RegisterSharedPath(shared_path_,
-                                             kCrostiniDefaultVmName);
+    crostini_share_path_->RegisterSharedPath(kCrostiniDefaultVmName,
+                                             shared_path_);
   }
 
   void SetUp() override {
diff --git a/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.cc b/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.cc
index dbb61c3..99873d4 100644
--- a/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.cc
+++ b/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.cc
@@ -8,8 +8,8 @@
 #include <stdint.h>
 #include <string>
 
+#include "base/hash/md5.h"
 #include "base/linux_util.h"
-#include "base/md5.h"
 #include "base/no_destructor.h"
 #include "base/system/sys_info.h"
 #include "base/version.h"
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index bc95073d..3f649ee2 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -13,9 +13,9 @@
 #include "base/bind_helpers.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index 5da9bbc..74c06e9 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -1107,8 +1107,8 @@
   event.entries.emplace_back(std::move(entry));
 }
 
-void EventRouter::OnUnshare(const base::FilePath& path,
-                            const std::string& vm_name) {
+void EventRouter::OnUnshare(const std::string& vm_name,
+                            const base::FilePath& path) {
   if (vm_name != crostini::kCrostiniDefaultVmName) {
     return;
   }
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h
index 504c43d..029b253 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.h
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -152,8 +152,8 @@
   void OnFileSystemMountFailed() override;
 
   // crostini::CrostiniSharePath::Observer overrides
-  void OnUnshare(const base::FilePath& path,
-                 const std::string& vm_name) override;
+  void OnUnshare(const std::string& vm_name,
+                 const base::FilePath& path) override;
 
   // Returns a weak pointer for the event router.
   base::WeakPtr<EventRouter> GetWeakPtr();
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.h b/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.h
index e0d080a..0e37e4e 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_stream_md5_digester.h
@@ -8,8 +8,8 @@
 #include <memory>
 
 #include "base/callback.h"
+#include "base/hash/md5.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/io_buffer.h"
 
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index a943060a..50de989 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -571,7 +571,7 @@
         TestCase("dirCreateWithKeyboard").EnableMyFilesVolume(),
         TestCase("dirCreateWithoutChangingCurrent").EnableMyFilesVolume(),
         TestCase("dirCreateWithoutChangingCurrent"),
-#if defined(ADDRESS_SANITIZER) || defined(DEBUG)
+#if !(defined(ADDRESS_SANITIZER) || defined(DEBUG))
         // Zip tests times out too often on ASAN and DEBUG.
         ZipCase("dirContextMenuZip"),
 #endif
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index 0963fa9..b8d178c 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -15,7 +15,7 @@
 #include "ash/public/cpp/ash_features.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/location.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen.cc b/chrome/browser/chromeos/login/screens/welcome_screen.cc
index 2309386..0d9d64ba 100644
--- a/chrome/browser/chromeos/login/screens/welcome_screen.cc
+++ b/chrome/browser/chromeos/login/screens/welcome_screen.cc
@@ -60,8 +60,6 @@
     view_->Bind(this);
 
   input_method::InputMethodManager::Get()->AddObserver(this);
-  InitializeTimezoneObserver();
-  OnSystemTimezoneChanged();
   UpdateLanguageList();
 }
 
@@ -78,7 +76,6 @@
 void WelcomeScreen::OnViewDestroyed(WelcomeView* view) {
   if (view_ == view) {
     view_ = nullptr;
-    timezone_subscription_.reset();
   }
 }
 
@@ -181,9 +178,6 @@
     SetApplicationLocale(startup_manifest->initial_locale_default());
   }
 
-  if (!timezone_subscription_)
-    InitializeTimezoneObserver();
-
   // Automatically continue if we are using hands-off enrollment.
   if (WizardController::UsingHandsOffEnrollment()) {
     OnUserAction(kUserActionContinueButtonClicked);
@@ -193,7 +187,6 @@
 }
 
 void WelcomeScreen::Hide() {
-  timezone_subscription_.reset();
   if (view_)
     view_->Hide();
 }
@@ -222,12 +215,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WelcomeScreen, private:
 
-void WelcomeScreen::InitializeTimezoneObserver() {
-  timezone_subscription_ = CrosSettings::Get()->AddSettingsObserver(
-      kSystemTimezone, base::Bind(&WelcomeScreen::OnSystemTimezoneChanged,
-                                  base::Unretained(this)));
-}
-
 void WelcomeScreen::OnContinueButtonPressed() {
   if (view_) {
     view_->StopDemoModeDetection();
@@ -279,14 +266,6 @@
     observer.OnLanguageListReloaded();
 }
 
-void WelcomeScreen::OnSystemTimezoneChanged() {
-  if (view_) {
-    std::string current_timezone_id;
-    CrosSettings::Get()->GetString(kSystemTimezone, &current_timezone_id);
-    view_->SetTimezoneId(current_timezone_id);
-  }
-}
-
 void WelcomeScreen::ConnectToLocaleUpdateController() {
   content::ServiceManagerConnection* connection =
       content::ServiceManagerConnection::GetForProcess();
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen.h b/chrome/browser/chromeos/login/screens/welcome_screen.h
index 6eba275..d682b57 100644
--- a/chrome/browser/chromeos/login/screens/welcome_screen.h
+++ b/chrome/browser/chromeos/login/screens/welcome_screen.h
@@ -15,7 +15,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 
 namespace chromeos {
@@ -86,9 +85,6 @@
                           Profile* profile,
                           bool show_message) override;
 
-  // Subscribe to timezone changes.
-  void InitializeTimezoneObserver();
-
   // Called when continue button is pressed.
   void OnContinueButtonPressed();
 
@@ -117,8 +113,6 @@
   void NotifyLocaleChange();
   void OnLocaleChangeResult(ash::mojom::LocaleNotificationResult result);
 
-  std::unique_ptr<CrosSettings::ObserverSubscription> timezone_subscription_;
-
   WelcomeView* view_ = nullptr;
   base::RepeatingClosure exit_callback_;
 
diff --git a/chrome/browser/chromeos/login/screens/welcome_view.h b/chrome/browser/chromeos/login/screens/welcome_view.h
index 0d97861..c4731dd3 100644
--- a/chrome/browser/chromeos/login/screens/welcome_view.h
+++ b/chrome/browser/chromeos/login/screens/welcome_view.h
@@ -41,9 +41,6 @@
 
   // Change the current input method.
   virtual void SetInputMethodId(const std::string& input_method_id) = 0;
-
-  // Change the current timezone.
-  virtual void SetTimezoneId(const std::string& timezone_id) = 0;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/enterprise_printers_provider.cc b/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
index 7f6015d..0b930ca 100644
--- a/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
+++ b/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
@@ -8,8 +8,8 @@
 #include <vector>
 
 #include "base/feature_list.h"
+#include "base/hash/md5.h"
 #include "base/json/json_reader.h"
-#include "base/md5.h"
 #include "chrome/browser/chromeos/printing/bulk_printers_calculator.h"
 #include "chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h"
 #include "chrome/browser/chromeos/printing/calculators_policies_binder.h"
diff --git a/chrome/browser/chromeos/printing/printer_configurer.cc b/chrome/browser/chromeos/printing/printer_configurer.cc
index c178e6d..6babedc6 100644
--- a/chrome/browser/chromeos/printing/printer_configurer.cc
+++ b/chrome/browser/chromeos/printing/printer_configurer.cc
@@ -15,8 +15,8 @@
 #include "base/callback.h"
 #include "base/containers/flat_map.h"
 #include "base/feature_list.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
diff --git a/chrome/browser/chromeos/printing/usb_printer_util.cc b/chrome/browser/chromeos/printing/usb_printer_util.cc
index e4e7fd2f..374e79f6 100644
--- a/chrome/browser/chromeos/printing/usb_printer_util.cc
+++ b/chrome/browser/chromeos/printing/usb_printer_util.cc
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/big_endian.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc b/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
index 650db39..fec48e6 100644
--- a/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
+++ b/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
@@ -9,7 +9,7 @@
 #include <utility>
 #include <vector>
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/observer_list_threadsafe.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
diff --git a/chrome/browser/component_updater/metadata_table_chromeos.cc b/chrome/browser/component_updater/metadata_table_chromeos.cc
index 8bd3fd2..229759c 100644
--- a/chrome/browser/component_updater/metadata_table_chromeos.cc
+++ b/chrome/browser/component_updater/metadata_table_chromeos.cc
@@ -9,8 +9,8 @@
 #include <utility>
 #include <vector>
 
+#include "base/hash/sha1.h"
 #include "base/memory/ptr_util.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "components/component_updater/component_updater_paths.h"
diff --git a/chrome/browser/conflicts/inspection_results_cache_win.cc b/chrome/browser/conflicts/inspection_results_cache_win.cc
index 312d331..10bd9de 100644
--- a/chrome/browser/conflicts/inspection_results_cache_win.cc
+++ b/chrome/browser/conflicts/inspection_results_cache_win.cc
@@ -10,7 +10,7 @@
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/pickle.h"
 
 namespace {
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc b/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
index 097b4676..5a2c874 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
@@ -12,11 +12,11 @@
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/sha1.h"
 #include "base/i18n/case_conversion.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
-#include "base/sha1.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task_runner_util.h"
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win.h b/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
index 1698cdbe..e3b27d2 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
@@ -10,8 +10,8 @@
 #include "base/callback.h"
 #include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
+#include "base/hash/md5.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc b/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
index 43ddc29..c46ebe9 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
@@ -15,11 +15,11 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
+#include "base/hash/sha1.h"
 #include "base/i18n/case_conversion.h"
 #include "base/logging.h"
 #include "base/optional.h"
 #include "base/path_service.h"
-#include "base/sha1.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
diff --git a/chrome/browser/conflicts/module_blacklist_cache_util_win.cc b/chrome/browser/conflicts/module_blacklist_cache_util_win.cc
index f0a0dc3..97aa28e 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_util_win.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_util_win.cc
@@ -16,8 +16,8 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/stl_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/conflicts/module_list_filter_win.h"
diff --git a/chrome/browser/conflicts/module_blacklist_cache_util_win_unittest.cc b/chrome/browser/conflicts/module_blacklist_cache_util_win_unittest.cc
index 813f7a5..75161a6 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_util_win_unittest.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_util_win_unittest.cc
@@ -13,9 +13,9 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/stl_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/conflicts/module_list_filter_win.h"
diff --git a/chrome/browser/conflicts/module_list_filter_win.cc b/chrome/browser/conflicts/module_list_filter_win.cc
index 184e35b3..0de10c3 100644
--- a/chrome/browser/conflicts/module_list_filter_win.cc
+++ b/chrome/browser/conflicts/module_list_filter_win.cc
@@ -8,9 +8,9 @@
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/sha1.h"
 #include "base/i18n/case_conversion.h"
 #include "base/logging.h"
-#include "base/sha1.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/conflicts/module_info_win.h"
 
diff --git a/chrome/browser/conflicts/module_list_filter_win_unittest.cc b/chrome/browser/conflicts/module_list_filter_win_unittest.cc
index 797278a..6706a87 100644
--- a/chrome/browser/conflicts/module_list_filter_win_unittest.cc
+++ b/chrome/browser/conflicts/module_list_filter_win_unittest.cc
@@ -10,9 +10,9 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/hash/sha1.h"
 #include "base/i18n/case_conversion.h"
 #include "base/optional.h"
-#include "base/sha1.h"
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
index 7c3aed79..66f1cf5 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
@@ -253,6 +253,10 @@
   std::string body = GetBody();
   EXPECT_THAT(body, HasSubstr(kSessionKey));
   EXPECT_THAT(body, HasSubstr("pid="));
+  EXPECT_THAT(body, HasSubstr("s="));
+  EXPECT_THAT(body, HasSubstr("c="));
+  EXPECT_THAT(body, HasSubstr("b="));
+  EXPECT_THAT(body, HasSubstr("p="));
 }
 
 // Gets the response body for an XHR to |url| (as seen by the renderer).
@@ -303,6 +307,10 @@
 
   EXPECT_THAT(result, HasSubstr(kSessionKey));
   EXPECT_THAT(result, Not(HasSubstr("pid=")));
+  EXPECT_THAT(result, HasSubstr("s="));
+  EXPECT_THAT(result, HasSubstr("c="));
+  EXPECT_THAT(result, HasSubstr("b="));
+  EXPECT_THAT(result, HasSubstr("p="));
 }
 
 IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, ChromeProxyEctHeaderSet) {
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
index f9969bfe..d28c399 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
@@ -14,7 +14,7 @@
 #include <utility>
 
 #include "base/feature_list.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/supports_user_data.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index c4dc024..7497a31 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -10,9 +10,9 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/sequenced_task_runner_handle.h"
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.h b/chrome/browser/extensions/api/image_writer_private/operation.h
index ba12212..cfc95222 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation.h
+++ b/chrome/browser/extensions/api/image_writer_private/operation.h
@@ -12,7 +12,7 @@
 #include "base/callback.h"
 #include "base/files/file.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index 31154214..1aa88fcd 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -383,8 +383,8 @@
       "handwritinggesture",
       base::FeatureList::IsEnabled(features::kHandwritingGesture)));
   features->AppendString(GenerateFeatureFlag(
-      "fstinputlogic", base::GetFieldTrialParamByFeatureAsBool(
-                           chromeos::features::kImeInputLogic, "fst", false)));
+      "fstinputlogic",
+      base::FeatureList::IsEnabled(chromeos::features::kImeInputLogicFst)));
 
   results->Set("features", std::move(features));
 
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 5ab5e14..ab4b26e 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
@@ -48,6 +48,7 @@
 #include "extensions/browser/api/web_request/web_request_api_constants.h"
 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
 #include "extensions/common/api/web_request.h"
+#include "extensions/common/constants.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/features/feature.h"
 #include "google_apis/gaia/gaia_urls.h"
@@ -65,6 +66,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest-message.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h"
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/login/login_state/scoped_test_public_session_login_state.h"
@@ -106,6 +108,8 @@
 
 static void EventHandledOnIOThread(
     void* profile,
+    int worker_thread_id,
+    int64_t service_worker_version_id,
     const std::string& extension_id,
     const std::string& event_name,
     const std::string& sub_event_name,
@@ -113,7 +117,8 @@
     ExtensionWebRequestEventRouter::EventResponse* response) {
   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
       profile, extension_id, event_name, sub_event_name, request_id,
-      0 /* render_process_id */, 0 /* web_view_instance_id */, response);
+      0 /* render_process_id */, 0 /* web_view_instance_id */, worker_thread_id,
+      service_worker_version_id, response);
 }
 
 // Returns whether |warnings| contains an extension for |extension_id|.
@@ -295,10 +300,12 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension1_id, extension1_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, ExtraInfoSpec::BLOCKING, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension2_id, extension2_id, events::FOR_TEST, kEventName,
       kEventName + "/2", filter, ExtraInfoSpec::BLOCKING, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   net::URLRequestJobFactoryImpl job_factory;
@@ -323,7 +330,8 @@
         extension1_id, base::Time::FromDoubleT(1));
     response->new_url = not_chosen_redirect_url;
     ipc_sender_.PushTask(base::BindRepeating(
-        &EventHandledOnIOThread, &profile_, extension1_id, kEventName,
+        &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+        blink::mojom::kInvalidServiceWorkerVersionId, extension1_id, kEventName,
         kEventName + "/1", request->identifier(), response));
 
     // Extension2 response. Arrives second, and chosen because of install_time.
@@ -331,21 +339,24 @@
         extension2_id, base::Time::FromDoubleT(2));
     response->new_url = redirect_url;
     ipc_sender_.PushTask(base::BindRepeating(
-        &EventHandledOnIOThread, &profile_, extension2_id, kEventName,
+        &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+        blink::mojom::kInvalidServiceWorkerVersionId, extension2_id, kEventName,
         kEventName + "/2", request->identifier(), response));
 
     // Extension2 response to the redirected URL. Arrives first, and chosen.
     response = new ExtensionWebRequestEventRouter::EventResponse(
         extension2_id, base::Time::FromDoubleT(2));
     ipc_sender_.PushTask(base::BindRepeating(
-        &EventHandledOnIOThread, &profile_, extension2_id, kEventName,
+        &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+        blink::mojom::kInvalidServiceWorkerVersionId, extension2_id, kEventName,
         kEventName + "/2", request->identifier(), response));
 
     // Extension1 response to the redirected URL. Arrives second, and ignored.
     response = new ExtensionWebRequestEventRouter::EventResponse(
         extension1_id, base::Time::FromDoubleT(1));
     ipc_sender_.PushTask(base::BindRepeating(
-        &EventHandledOnIOThread, &profile_, extension1_id, kEventName,
+        &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+        blink::mojom::kInvalidServiceWorkerVersionId, extension1_id, kEventName,
         kEventName + "/1", request->identifier(), response));
 
     request->Start();
@@ -369,7 +380,8 @@
         extension2_id, base::Time::FromDoubleT(2));
     response->new_url = redirect_url;
     ipc_sender_.PushTask(base::BindRepeating(
-        &EventHandledOnIOThread, &profile_, extension2_id, kEventName,
+        &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+        blink::mojom::kInvalidServiceWorkerVersionId, extension2_id, kEventName,
         kEventName + "/2", request2->identifier(), response));
 
     // Extension1 response. Arrives second, but ignored due to install_time.
@@ -377,21 +389,24 @@
         extension1_id, base::Time::FromDoubleT(1));
     response->new_url = not_chosen_redirect_url;
     ipc_sender_.PushTask(base::BindRepeating(
-        &EventHandledOnIOThread, &profile_, extension1_id, kEventName,
+        &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+        blink::mojom::kInvalidServiceWorkerVersionId, extension1_id, kEventName,
         kEventName + "/1", request2->identifier(), response));
 
     // Extension2 response to the redirected URL. Arrives first, and chosen.
     response = new ExtensionWebRequestEventRouter::EventResponse(
         extension2_id, base::Time::FromDoubleT(2));
     ipc_sender_.PushTask(base::BindRepeating(
-        &EventHandledOnIOThread, &profile_, extension2_id, kEventName,
+        &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+        blink::mojom::kInvalidServiceWorkerVersionId, extension2_id, kEventName,
         kEventName + "/2", request2->identifier(), response));
 
     // Extension1 response to the redirected URL. Arrives second, and ignored.
     response = new ExtensionWebRequestEventRouter::EventResponse(
         extension1_id, base::Time::FromDoubleT(1));
     ipc_sender_.PushTask(base::BindRepeating(
-        &EventHandledOnIOThread, &profile_, extension1_id, kEventName,
+        &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+        blink::mojom::kInvalidServiceWorkerVersionId, extension1_id, kEventName,
         kEventName + "/1", request2->identifier(), response));
 
     request2->Start();
@@ -405,9 +420,11 @@
   }
 
   ExtensionWebRequestEventRouter::EventListener::ID id1(
-      &profile_, extension1_id, kEventName + "/1", 0, 0);
+      &profile_, extension1_id, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id2(
-      &profile_, extension2_id, kEventName + "/2", 0, 0);
+      &profile_, extension2_id, kEventName + "/2", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id2,
@@ -425,10 +442,12 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension1_id, extension1_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, ExtraInfoSpec::BLOCKING, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension2_id, extension2_id, events::FOR_TEST, kEventName,
       kEventName + "/2", filter, ExtraInfoSpec::BLOCKING, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   GURL request_url("about:blank");
@@ -446,7 +465,8 @@
       extension1_id, base::Time::FromDoubleT(1));
   response->cancel = true;
   ipc_sender_.PushTask(base::BindRepeating(
-      &EventHandledOnIOThread, &profile_, extension1_id, kEventName,
+      &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId, extension1_id, kEventName,
       kEventName + "/1", request->identifier(), response));
 
   // Extension2 response. Arrives second, but has higher precedence
@@ -455,7 +475,8 @@
       extension2_id, base::Time::FromDoubleT(2));
   response->new_url = redirect_url;
   ipc_sender_.PushTask(base::BindRepeating(
-      &EventHandledOnIOThread, &profile_, extension2_id, kEventName,
+      &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId, extension2_id, kEventName,
       kEventName + "/2", request->identifier(), response));
 
   request->Start();
@@ -469,9 +490,11 @@
   EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
 
   ExtensionWebRequestEventRouter::EventListener::ID id1(
-      &profile_, extension1_id, kEventName + "/1", 0, 0);
+      &profile_, extension1_id, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id2(
-      &profile_, extension2_id, kEventName + "/2", 0, 0);
+      &profile_, extension2_id, kEventName + "/2", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id2,
@@ -494,10 +517,13 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, ExtraInfoSpec::BLOCKING, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, events::FOR_TEST, kEventName2,
-      kEventName2 + "/1", filter, 0, 0, 0, ipc_sender_factory.GetWeakPtr());
+      kEventName2 + "/1", filter, 0, 0, 0, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId,
+      ipc_sender_factory.GetWeakPtr());
 
   GURL request_url("about:blank");
   std::unique_ptr<net::URLRequest> request = CreateRequest(request_url);
@@ -511,7 +537,8 @@
   GURL redirect_url("about:redirected");
   response->new_url = redirect_url;
   ipc_sender_.PushTask(base::BindRepeating(
-      &EventHandledOnIOThread, &profile_, extension_id, kEventName,
+      &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId, extension_id, kEventName,
       kEventName + "/1", request->identifier(), response));
 
   base::RunLoop run_loop;
@@ -534,9 +561,11 @@
   EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
 
   ExtensionWebRequestEventRouter::EventListener::ID id1(
-      &profile_, extension_id, kEventName + "/1", 0, 0);
+      &profile_, extension_id, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id2(
-      &profile_, extension_id, kEventName2 + "/1", 0, 0);
+      &profile_, extension_id, kEventName2 + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id2,
@@ -707,6 +736,7 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, extra_info_spec_body, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2);
@@ -715,7 +745,8 @@
   base::RunLoop().RunUntilIdle();
 
   ExtensionWebRequestEventRouter::EventListener::ID id1(
-      &profile_, extension_id, kEventName + "/1", 0, 0);
+      &profile_, extension_id, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
 
@@ -726,6 +757,7 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, extra_info_spec_empty, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2);
@@ -737,6 +769,7 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, extra_info_spec_body, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   // Part 3.
@@ -797,24 +830,28 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id1, extension_id1, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, extra_info_spec_body, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   // Extension 1 without requestBody spec.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id1, extension_id1, events::FOR_TEST, kEventName,
       kEventName + "/2", filter, extra_info_spec_empty, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   // Extension 2, without requestBody spec.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id2, extension_id2, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, extra_info_spec_empty, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   // Extension 2, with requestBody spec.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id2, extension_id2, events::FOR_TEST, kEventName,
       kEventName + "/2", filter, extra_info_spec_body, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   // Only one request is sent, but more than one event will be triggered.
@@ -828,13 +865,17 @@
 
   // Clean-up
   ExtensionWebRequestEventRouter::EventListener::ID id1(
-      &profile_, extension_id1, kEventName + "/1", 0, 0);
+      &profile_, extension_id1, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id2(
-      &profile_, extension_id1, kEventName + "/2", 0, 0);
+      &profile_, extension_id1, kEventName + "/2", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id3(
-      &profile_, extension_id2, kEventName + "/1", 0, 0);
+      &profile_, extension_id2, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id4(
-      &profile_, extension_id2, kEventName + "/2", 0, 0);
+      &profile_, extension_id2, kEventName + "/2", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id2,
@@ -884,10 +925,12 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id1, extension_id1, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, extra_info_spec_body, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id2, extension_id2, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, extra_info_spec_body, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   // Only one request is sent, but more than one event will be triggered.
@@ -901,9 +944,11 @@
 
   // Clean-up
   ExtensionWebRequestEventRouter::EventListener::ID id1(
-      &profile_, extension_id1, kEventName + "/1", 0, 0);
+      &profile_, extension_id1, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id2(
-      &profile_, extension_id2, kEventName + "/1", 0, 0);
+      &profile_, extension_id2, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id2,
@@ -947,6 +992,7 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, extra_info_spec, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   // The request URL can be arbitrary but must have an HTTP or HTTPS scheme.
@@ -963,7 +1009,8 @@
   base::RunLoop().RunUntilIdle();
 
   ExtensionWebRequestEventRouter::EventListener::ID id1(
-      &profile_, extension_id, kEventName + "/1", 0, 0);
+      &profile_, extension_id, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
 
@@ -998,18 +1045,23 @@
   // Add two non-webview listeners.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
-      filter, 0, 1 /* render_process_id */, 0, ipc_sender_factory.GetWeakPtr());
+      filter, 0, 1 /* render_process_id */, 0, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId,
+      ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
-      filter, 0, 2 /* render_process_id */, 0, ipc_sender_factory.GetWeakPtr());
+      filter, 0, 2 /* render_process_id */, 0, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId,
+      ipc_sender_factory.GetWeakPtr());
   EXPECT_EQ(
       2u,
       ExtensionWebRequestEventRouter::GetInstance()->GetListenerCountForTesting(
           &profile_, kEventName));
 
   // Now remove the events without passing an explicit process ID.
-  ExtensionWebRequestEventRouter::EventListener::ID id1(&profile_, ext_id,
-                                                        kSubEventName, 0, 0);
+  ExtensionWebRequestEventRouter::EventListener::ID id1(
+      &profile_, ext_id, kSubEventName, 0, 0, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
   EXPECT_EQ(
@@ -1036,9 +1088,11 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension_id, extension_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, ExtraInfoSpec::BLOCKING, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
-  ExtensionWebRequestEventRouter::EventListener::ID id(&profile_, extension_id,
-                                                       kEventName + "/1", 0, 0);
+  ExtensionWebRequestEventRouter::EventListener::ID id(
+      &profile_, extension_id, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener* listener =
       ExtensionWebRequestEventRouter::GetInstance()->FindEventListener(id);
   ASSERT_NE(nullptr, listener);
@@ -1069,7 +1123,8 @@
   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
       &profile_, extension_id, kEventName, kEventName + "/1",
       request->identifier(), 0 /* render_process_id */,
-      0 /* web_view_instance_id */, response);
+      0 /* web_view_instance_id */, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId, response);
   {
     base::RunLoop run_loop;
     run_loop.RunUntilIdle();
@@ -1164,17 +1219,20 @@
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension1_id, extension1_id, events::FOR_TEST, kEventName,
       kEventName + "/1", filter, ExtraInfoSpec::BLOCKING, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension2_id, extension2_id, events::FOR_TEST, kEventName,
       kEventName + "/2", filter, ExtraInfoSpec::BLOCKING, 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   // Install one extension that observes the final headers.
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension3_id, extension3_id, events::FOR_TEST,
       keys::kOnSendHeadersEvent, std::string(keys::kOnSendHeadersEvent) + "/3",
-      filter, ExtraInfoSpec::REQUEST_HEADERS, 0, 0,
+      filter, ExtraInfoSpec::REQUEST_HEADERS, 0, 0, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId,
       ipc_sender_factory.GetWeakPtr());
 
   GURL request_url("http://doesnotexist/does_not_exist.html");
@@ -1216,7 +1274,8 @@
     if (i+1 == test.modification_size ||
         mod.extension_id != test.modification[i+1].extension_id) {
       ipc_sender_.PushTask(base::BindRepeating(
-          &EventHandledOnIOThread, &profile_,
+          &EventHandledOnIOThread, &profile_, extensions::kMainThreadId,
+          blink::mojom::kInvalidServiceWorkerVersionId,
           mod.extension_id == 1 ? extension1_id : extension2_id, kEventName,
           kEventName + (mod.extension_id == 1 ? "/1" : "/2"),
           request->identifier(), response));
@@ -1292,12 +1351,15 @@
   }
   EXPECT_EQ(1, num_headers_observed);
   ExtensionWebRequestEventRouter::EventListener::ID id1(
-      &profile_, extension1_id, kEventName + "/1", 0, 0);
+      &profile_, extension1_id, kEventName + "/1", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id2(
-      &profile_, extension2_id, kEventName + "/2", 0, 0);
+      &profile_, extension2_id, kEventName + "/2", 0, 0,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::EventListener::ID id3(
       &profile_, extension3_id, std::string(keys::kOnSendHeadersEvent) + "/3",
-      0, 0);
+      0, 0, extensions::kMainThreadId,
+      blink::mojom::kInvalidServiceWorkerVersionId);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id1,
                                                                      false);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(id2,
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index e26c3be6..78119d4 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -1563,6 +1563,17 @@
   web_socket.reset();
 }
 
+// Tests that a clean close from the server is not reported as an error when
+// there is a race between OnDropChannel and SendFrame.
+// Regression test for https://crbug.com/937790.
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebSocketCleanClose) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(StartWebSocketServer(net::GetWebSocketTestDataDirectory()));
+  ASSERT_TRUE(
+      RunExtensionSubtest("webrequest", "test_websocket_clean_close.html"))
+      << message_;
+}
+
 // Test behavior when intercepting requests from a browser-initiated url fetch.
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
                        WebRequestURLLoaderInterception) {
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
index 284f941..8efee87 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 1070508f..6bac64b 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -656,14 +656,16 @@
   AddComponentFromDir(
       base::FilePath(extension_misc::kGoogleSpeechSynthesisExtensionPath),
       extension_misc::kGoogleSpeechSynthesisExtensionId,
-      base::BindRepeating(&ComponentLoader::EnableFileSystemInGuestMode,
+      base::BindRepeating(&ComponentLoader::FinishLoadSpeechSynthesisExtension,
                           weak_factory_.GetWeakPtr(),
                           extension_misc::kGoogleSpeechSynthesisExtensionId));
 
   AddComponentFromDir(
       base::FilePath(extension_misc::kEspeakSpeechSynthesisExtensionPath),
       extension_misc::kEspeakSpeechSynthesisExtensionId,
-      base::RepeatingClosure());
+      base::BindRepeating(&ComponentLoader::FinishLoadSpeechSynthesisExtension,
+                          weak_factory_.GetWeakPtr(),
+                          extension_misc::kEspeakSpeechSynthesisExtensionId));
 }
 
 void ComponentLoader::EnableFileSystemInGuestMode(const std::string& id) {
@@ -709,6 +711,16 @@
   if (!done_cb.is_null())
     done_cb.Run();
 }
+
+void ComponentLoader::FinishLoadSpeechSynthesisExtension(
+    const char* extension_id) {
+  EnableFileSystemInGuestMode(extension_id);
+
+  // TODO(https://crbug.com/947305): mitigation for extension not awake after
+  // load.
+  extensions::ProcessManager::Get(profile_)->WakeEventPage(extension_id,
+                                                           base::DoNothing());
+}
 #endif
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index 332f7ec..3f8b640 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -210,7 +210,10 @@
       const base::Optional<std::string>& description_string,
       const base::Closure& done_cb,
       std::unique_ptr<base::DictionaryValue> manifest);
-#endif  // defined(OS_CHROMEOS)
+
+  // Finishes loading an extension tts engine.
+  void FinishLoadSpeechSynthesisExtension(const char* extension_id);
+#endif
 
   PrefService* profile_prefs_;
   PrefService* local_state_;
diff --git a/chrome/browser/extensions/extension_bindings_apitest.cc b/chrome/browser/extensions/extension_bindings_apitest.cc
index 2724af86..26e77d4 100644
--- a/chrome/browser/extensions/extension_bindings_apitest.cc
+++ b/chrome/browser/extensions/extension_bindings_apitest.cc
@@ -440,6 +440,60 @@
   EXPECT_TRUE(RunExtensionTest("bindings/invalidate_context")) << message_;
 }
 
+// Tests that we don't crash if the extension invalidates the context in a
+// callback with a runtime.lastError present. Regression test for
+// https://crbug.com/944014.
+IN_PROC_BROWSER_TEST_F(ExtensionBindingsApiTest,
+                       InvalidateContextInCallbackWithLastError) {
+  TestExtensionDir dir;
+  dir.WriteManifest(
+      R"({
+           "name": "Invalidate Context in onDisconnect",
+           "version": "0.1",
+           "manifest_version": 2,
+           "background": {"scripts": ["background.js"]}
+         })");
+
+  constexpr char kFrameHtml[] =
+      R"(<html>
+           <body></body>
+           <script src="frame.js"></script>
+         </html>)";
+  constexpr char kFrameJs[] =
+      R"(chrome.tabs.executeScript({code: ''}, () => {
+           // We expect a last error to be present, since we don't have access
+           // to the tab.
+           chrome.test.assertTrue(!!chrome.runtime.lastError);
+           // Remove the frame from the DOM. This causes blink to remove the
+           // associated script contexts.
+           parent.document.body.removeChild(
+               parent.document.body.querySelector('iframe'));
+         });)";
+  constexpr char kBackgroundJs[] =
+      R"(let frame = document.createElement('iframe');
+         frame.src = 'frame.html';
+         let observer = new MutationObserver((mutationList) => {
+           for (let mutation of mutationList) {
+             if (mutation.removedNodes.length == 0)
+               continue;
+             chrome.test.assertEq(1, mutation.removedNodes.length);
+             chrome.test.assertEq('IFRAME', mutation.removedNodes[0].tagName);
+             chrome.test.notifyPass();
+             break;
+           }
+         });
+         observer.observe(document.body, {childList: true});
+         document.body.appendChild(frame);)";
+  dir.WriteFile(FILE_PATH_LITERAL("frame.html"), kFrameHtml);
+  dir.WriteFile(FILE_PATH_LITERAL("frame.js"), kFrameJs);
+  dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+
+  ResultCatcher catcher;
+  const Extension* extension = LoadExtension(dir.UnpackedPath());
+  ASSERT_TRUE(extension);
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
 // TODO(devlin): Can this be combined with
 // ExtensionBindingsApiTest.UseAPIsAfterContextRemoval?
 IN_PROC_BROWSER_TEST_F(ExtensionBindingsApiTest, UseAppAPIAfterFrameRemoval) {
diff --git a/chrome/browser/extensions/extension_keybinding_registry.cc b/chrome/browser/extensions/extension_keybinding_registry.cc
index 4bf5a29..940eec2 100644
--- a/chrome/browser/extensions/extension_keybinding_registry.cc
+++ b/chrome/browser/extensions/extension_keybinding_registry.cc
@@ -19,6 +19,10 @@
 #include "extensions/common/extension_set.h"
 #include "extensions/common/manifest_constants.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/ash/media_client.h"
+#endif
+
 namespace {
 
 const char kOnCommandEventName[] = "commands.onCommand";
@@ -95,14 +99,19 @@
 
   // If we're no longer listening to any media keys, tell the browser that
   // it can start handling media keys.
-  if (any_media_keys_removed &&
-      content::MediaKeysListenerManager::IsMediaKeysListenerManagerEnabled() &&
-      !IsListeningToAnyMediaKeys()) {
-    content::MediaKeysListenerManager* media_keys_listener_manager =
-        content::MediaKeysListenerManager::GetInstance();
-    DCHECK(media_keys_listener_manager);
+  if (any_media_keys_removed && !IsListeningToAnyMediaKeys()) {
+    if (content::MediaKeysListenerManager::
+            IsMediaKeysListenerManagerEnabled()) {
+      content::MediaKeysListenerManager* media_keys_listener_manager =
+          content::MediaKeysListenerManager::GetInstance();
+      DCHECK(media_keys_listener_manager);
 
-    media_keys_listener_manager->EnableInternalMediaKeyHandling();
+      media_keys_listener_manager->EnableInternalMediaKeyHandling();
+    } else {
+#if defined(OS_CHROMEOS)
+      MediaClient::Get()->DisableCustomMediaKeyHandler(browser_context_, this);
+#endif
+    }
   }
 }
 
@@ -184,6 +193,10 @@
       DCHECK(media_keys_listener_manager);
 
       media_keys_listener_manager->DisableInternalMediaKeyHandling();
+    } else {
+#if defined(OS_CHROMEOS)
+      MediaClient::Get()->EnableCustomMediaKeyHandler(browser_context_, this);
+#endif
     }
   }
 }
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index aab9e688..dd0d7cc 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -117,7 +117,7 @@
 
   void SetUpOnMainThread() override {
     ExtensionApiTest::SetUpOnMainThread();
-    host_resolver()->AddRule("a.com", "127.0.0.1");
+    host_resolver()->AddRule("*", "127.0.0.1");
   }
 
  protected:
@@ -337,6 +337,13 @@
       << message_;
 }
 
+// Tests chrome.storage APIs.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequest) {
+  ASSERT_TRUE(
+      RunExtensionTest("service_worker/worker_based_background/web_request"))
+      << message_;
+}
+
 // Listens for |message| from extension Service Worker early so that tests can
 // wait for the message on startup (and not miss it).
 class ServiceWorkerWithEarlyMessageListenerTest
diff --git a/chrome/browser/extensions/system_display/display_info_provider_win.cc b/chrome/browser/extensions/system_display/display_info_provider_win.cc
index 065fef7..e71556d 100644
--- a/chrome/browser/extensions/system_display/display_info_provider_win.cc
+++ b/chrome/browser/extensions/system_display/display_info_provider_win.cc
@@ -7,7 +7,7 @@
 #include <stddef.h>
 #include <windows.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/win_util.h"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 8c54108..15581c9 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1416,11 +1416,6 @@
     "expiry_milestone": 76
   },
   {
-    "name": "enable-ntp-asset-download-suggestions",
-    "owners": [ "fgorski" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "enable-ntp-button",
     "owners": [ "twellington" ],
     "expiry_milestone": 78
@@ -1635,7 +1630,7 @@
   {
     "name": "enable-site-isolation-for-password-sites",
     "owners": [ "site-isolation-dev", "alexmos", "lukasza" ],
-    "expiry_milestone": 77
+    "expiry_milestone": 79
   },
   {
     "name": "enable-site-per-process",
@@ -2196,6 +2191,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "isolate-origins",
+    "owners": [ "site-isolation-dev", "alexmos", "creis", "lukasza" ],
+    "expiry_milestone": 79
+  },
+  {
     "name": "language-settings",
     // "owners": [ "your-team" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 95b3bef..904bdb9 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -780,63 +780,64 @@
     "If enabled, event targeting uses the new viz-assisted hit-testing logic, "
     "with hit-test data computed from the CompositorFrame.";
 
-const char kEnableOutOfProcessHeapProfilingName[] =
-    "Chrome heap profiling start mode.";
-const char kEnableOutOfProcessHeapProfilingDescription[] =
-    "Starts heap profiling service that records sampled memory allocation "
-    "profile having each sample attributed with a callstack. "
-    "The sampling resolution is controlled with --memlog-sampling flag. "
-    "Recorded heap dumps can be obtained at chrome://tracing "
-    "[category:memory-infra] and chrome://memory-internals. This setting "
-    "controls which processes are profiled. As long as this setting is not "
-    "disabled, users can start profiling any given process in "
-    "chrome://memory-internals.";
-const char kEnableOutOfProcessHeapProfilingModeMinimal[] = "Browser and GPU";
-const char kEnableOutOfProcessHeapProfilingModeAll[] = "All processes";
-const char kEnableOutOfProcessHeapProfilingModeAllRenderers[] = "All renderers";
-const char kEnableOutOfProcessHeapProfilingModeBrowser[] = "Only browser";
-const char kEnableOutOfProcessHeapProfilingModeGpu[] = "Only GPU.";
-const char kEnableOutOfProcessHeapProfilingModeManual[] =
-    "None by default. Visit chrome://memory-internals to choose which "
-    "processes to profile.";
-const char kEnableOutOfProcessHeapProfilingModeRendererSampling[] =
-    "Profile a random sampling of renderer processes, ensuring only one is "
-    "ever profiled at a time.";
-
 const char kCompositorThreadedScrollbarScrollingName[] =
     "Enable compositor threaded scrollbar scrolling";
 const char kCompositorThreadedScrollbarScrollingDescription[] =
     "Enables pointer-based scrollbar scrolling on the compositor thread "
     "instead of the main thread";
 
-const char kOutOfProcessHeapProfilingInProcess[] =
-    "Run the heap profiling service in the browser process.";
-const char kOutOfProcessHeapProfilingInProcessDescription[] =
-    "Makes profiling service (if enabled) to be executed within the browser "
-    "process. By default the service is run in a dedicated utility process.";
+const char kMemlogName[] = "Chrome heap profiler start mode.";
+const char kMemlogDescription[] =
+    "Starts heap profiling service that records sampled memory allocation "
+    "profile having each sample attributed with a callstack. "
+    "The sampling resolution is controlled with --memlog-sampling-rate flag. "
+    "Recorded heap dumps can be obtained at chrome://tracing "
+    "[category:memory-infra] and chrome://memory-internals. This setting "
+    "controls which processes will be profiled since their start. To profile "
+    "any given process at a later time use chrome://memory-internals page.";
+const char kMemlogModeMinimal[] = "Browser and GPU";
+const char kMemlogModeAll[] = "All processes";
+const char kMemlogModeAllRenderers[] = "All renderers";
+const char kMemlogModeRendererSampling[] = "Single renderer";
+const char kMemlogModeBrowser[] = "Browser only";
+const char kMemlogModeGpu[] = "GPU only";
 
-const char kOutOfProcessHeapProfilingSamplingRate[] =
-    "Sampling interval in bytes for memlog allocations.";
-const char kOutOfProcessHeapProfilingSamplingRateDescription[] =
-    "Use a poisson process to sample allocations. Defaults to a sampling rate "
-    "of 100KB. This results in low noise for large and/or frequent allocations "
+const char kMemlogInProcessName[] = "Heap profiling service process type.";
+const char kMemlogInProcessDescription[] =
+    "Controls if the heap profiling service runs within the browser process "
+    "(default) or in a dedicated utility process.";
+const char kMemlogInProcessEnabled[] = "In browser process";
+const char kMemlogInProcessDisabled[] = "As separate process";
+
+const char kMemlogSamplingRateName[] =
+    "Heap profiling sampling interval (in bytes).";
+const char kMemlogSamplingRateDescription[] =
+    "Heap profiling service uses Poisson process to sample allocations. "
+    "Default value for the interval between samples is 100000 (100KB). "
+    "This results in low noise for large and/or frequent allocations "
     "[size * frequency >> 100KB]. This means that aggregate numbers [e.g. "
     "total size of malloc-ed objects] and large and/or frequent allocations "
-    "can be trusted with high fidelity.";
+    "can be trusted with high fidelity. "
+    "Lower intervals produce higher samples resolution, but come at a cost of "
+    "higher performance overhead.";
+const char kMemlogSamplingRate10KB[] = "10KB";
+const char kMemlogSamplingRate50KB[] = "50KB";
+const char kMemlogSamplingRate100KB[] = "100KB";
+const char kMemlogSamplingRate500KB[] = "500KB";
+const char kMemlogSamplingRate1MB[] = "1MB";
+const char kMemlogSamplingRate5MB[] = "5MB";
 
-const char kOOPHPStackModeName[] =
-    "The type of stack to record for memlog heap dumps";
-const char kOOPHPStackModeDescription[] =
-    "By default, memlog heap dumps record native stacks, which requires a "
-    "post-processing step to symbolize. Requires a custom build with frame "
-    "pointers to work on Android. Native with thread names will add the thread "
-    "name as the first frame of each native stack. It's also possible to "
-    "record a pseudo stack using trace events as identifiers. It's also "
-    "possible to do a mix of both.";
-const char kOOPHPStackModeMixed[] = "Mixed";
-const char kOOPHPStackModeNative[] = "Native";
-const char kOOPHPStackModeNativeWithThreadNames[] = "Native with thread names";
-const char kOOPHPStackModePseudo[] = "Trace events";
+const char kMemlogStackModeName[] = "Heap profiling stack traces type.";
+const char kMemlogStackModeDescription[] =
+    "By default heap profiling service records native stacks. "
+    "A post-processing step is required to symbolize the stacks. "
+    "'Native with thread names' adds the thread name as the first frame of "
+    "each native stack. It's also possible to record a pseudo stack using "
+    "trace events as identifiers. It's also possible to do a mix of both.";
+const char kMemlogStackModeMixed[] = "Mixed";
+const char kMemlogStackModeNative[] = "Native";
+const char kMemlogStackModeNativeWithThreadNames[] = "Native with thread names";
+const char kMemlogStackModePseudo[] = "Trace events";
 
 const char kEnablePixelCanvasRecordingName[] = "Enable pixel canvas recording";
 const char kEnablePixelCanvasRecordingDescription[] =
@@ -1787,6 +1788,11 @@
 const char kSimplifyHttpsIndicatorDescription[] =
     "Change the UI treatment for HTTPS pages.";
 
+const char kIsolateOriginsName[] = "Isolate additional origins";
+const char kIsolateOriginsDescription[] =
+    "Requires dedicated processes for an additional set of origins, "
+    "specified as a comma-separated list.";
+
 const char kSiteIsolationOptOutName[] = "Disable site isolation";
 const char kSiteIsolationOptOutDescription[] =
     "Disables site isolation "
@@ -2333,13 +2339,6 @@
     "Enables a revamped context menu when a link, image, or video is long "
     "pressed within Chrome.";
 
-const char kEnableNtpAssetDownloadSuggestionsName[] =
-    "Show asset downloads on the New Tab page";
-const char kEnableNtpAssetDownloadSuggestionsDescription[] =
-    "If enabled, the list of content suggestions on the New Tab page will "
-    "contain assets (e.g. books, pictures, audio) that the user downloaded for "
-    "later use.";
-
 const char kEnableNtpOfflinePageDownloadSuggestionsName[] =
     "Show offline page downloads on the New Tab page";
 const char kEnableNtpOfflinePageDownloadSuggestionsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 52f7270..097156e 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -469,26 +469,36 @@
 extern const char kVizHitTestDrawQuadName[];
 extern const char kVizHitTestDrawQuadDescription[];
 
-extern const char kEnableOutOfProcessHeapProfilingName[];
-extern const char kEnableOutOfProcessHeapProfilingDescription[];
-extern const char kEnableOutOfProcessHeapProfilingModeMinimal[];
-extern const char kEnableOutOfProcessHeapProfilingModeAll[];
-extern const char kEnableOutOfProcessHeapProfilingModeAllRenderers[];
-extern const char kEnableOutOfProcessHeapProfilingModeBrowser[];
-extern const char kEnableOutOfProcessHeapProfilingModeGpu[];
-extern const char kEnableOutOfProcessHeapProfilingModeManual[];
-extern const char kEnableOutOfProcessHeapProfilingModeRendererSampling[];
-extern const char kOutOfProcessHeapProfilingInProcess[];
-extern const char kOutOfProcessHeapProfilingInProcessDescription[];
-extern const char kOutOfProcessHeapProfilingSamplingRate[];
-extern const char kOutOfProcessHeapProfilingSamplingRateDescription[];
+extern const char kMemlogName[];
+extern const char kMemlogDescription[];
+extern const char kMemlogModeMinimal[];
+extern const char kMemlogModeAll[];
+extern const char kMemlogModeAllRenderers[];
+extern const char kMemlogModeBrowser[];
+extern const char kMemlogModeGpu[];
+extern const char kMemlogModeManual[];
+extern const char kMemlogModeRendererSampling[];
 
-extern const char kOOPHPStackModeName[];
-extern const char kOOPHPStackModeDescription[];
-extern const char kOOPHPStackModeMixed[];
-extern const char kOOPHPStackModeNative[];
-extern const char kOOPHPStackModeNativeWithThreadNames[];
-extern const char kOOPHPStackModePseudo[];
+extern const char kMemlogInProcessName[];
+extern const char kMemlogInProcessDescription[];
+extern const char kMemlogInProcessDisabled[];
+extern const char kMemlogInProcessEnabled[];
+
+extern const char kMemlogSamplingRateName[];
+extern const char kMemlogSamplingRateDescription[];
+extern const char kMemlogSamplingRate10KB[];
+extern const char kMemlogSamplingRate50KB[];
+extern const char kMemlogSamplingRate100KB[];
+extern const char kMemlogSamplingRate500KB[];
+extern const char kMemlogSamplingRate1MB[];
+extern const char kMemlogSamplingRate5MB[];
+
+extern const char kMemlogStackModeName[];
+extern const char kMemlogStackModeDescription[];
+extern const char kMemlogStackModeMixed[];
+extern const char kMemlogStackModeNative[];
+extern const char kMemlogStackModeNativeWithThreadNames[];
+extern const char kMemlogStackModePseudo[];
 
 extern const char kEnableNewDownloadBackendName[];
 extern const char kEnableNewDownloadBackendDescription[];
@@ -1063,6 +1073,9 @@
 extern const char kSimplifyHttpsIndicatorName[];
 extern const char kSimplifyHttpsIndicatorDescription[];
 
+extern const char kIsolateOriginsName[];
+extern const char kIsolateOriginsDescription[];
+
 extern const char kSiteIsolationOptOutName[];
 extern const char kSiteIsolationOptOutDescription[];
 extern const char kSiteIsolationOptOutChoiceDefault[];
@@ -1388,9 +1401,6 @@
 extern const char kEnableRevampedContextMenuName[];
 extern const char kEnableRevampedContextMenuDescription[];
 
-extern const char kEnableNtpAssetDownloadSuggestionsName[];
-extern const char kEnableNtpAssetDownloadSuggestionsDescription[];
-
 extern const char kEnableNtpOfflinePageDownloadSuggestionsName[];
 extern const char kEnableNtpOfflinePageDownloadSuggestionsDescription[];
 
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index e1e0db8..175c994c 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -300,7 +300,7 @@
           GetInfoBarService(), nullptr,
           std::make_unique<PluginMetadata>(
               "test-plugin", base::ASCIIToUTF16("Test Plugin"), true, GURL(),
-              GURL(), base::ASCIIToUTF16("Test"), std::string()));
+              GURL(), base::ASCIIToUTF16("Test"), std::string(), false));
       break;
 
     case IBD::RELOAD_PLUGIN_INFOBAR_DELEGATE:
diff --git a/chrome/browser/media/capture_access_handler_base.cc b/chrome/browser/media/capture_access_handler_base.cc
index f678b6e..96969286 100644
--- a/chrome/browser/media/capture_access_handler_base.cc
+++ b/chrome/browser/media/capture_access_handler_base.cc
@@ -13,7 +13,7 @@
 #include "extensions/common/extension.h"
 
 #if defined(OS_CHROMEOS)
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #endif  // defined(OS_CHROMEOS)
 
 using content::BrowserThread;
diff --git a/chrome/browser/media/router/discovery/discovery_network_monitor.cc b/chrome/browser/media/router/discovery/discovery_network_monitor.cc
index 1e173ef..31e149c 100644
--- a/chrome/browser/media/router/discovery/discovery_network_monitor.cc
+++ b/chrome/browser/media/router/discovery/discovery_network_monitor.cc
@@ -7,10 +7,10 @@
 #include <memory>
 #include <unordered_set>
 
+#include "base/hash/sha1.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/task/task_traits.h"
diff --git a/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc b/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc
index bd83eaa7..4724a80a 100644
--- a/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc
+++ b/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc
@@ -7,9 +7,9 @@
 #include <string>
 
 #include "base/base64url.h"
+#include "base/hash/sha1.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
-#include "base/sha1.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
 #include "components/cast_channel/cast_socket.h"
diff --git a/chrome/browser/media/router/providers/dial/dial_internal_message_util.cc b/chrome/browser/media/router/providers/dial/dial_internal_message_util.cc
index 004b4ea..94149e0 100644
--- a/chrome/browser/media/router/providers/dial/dial_internal_message_util.cc
+++ b/chrome/browser/media/router/providers/dial/dial_internal_message_util.cc
@@ -7,9 +7,9 @@
 #include <array>
 
 #include "base/base64url.h"
+#include "base/hash/sha1.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/media/router/providers/dial/dial_activity_manager.h"
 #include "chrome/browser/media/router/route_message_util.h"
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
index 2338d6d..b060eb3 100644
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/media/webrtc/native_desktop_media_list.h"
 
 #include "base/bind.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
diff --git a/chrome/browser/media/webrtc/tab_desktop_media_list.cc b/chrome/browser/media/webrtc/tab_desktop_media_list.cc
index 56f37e0..806a766f 100644
--- a/chrome/browser/media/webrtc/tab_desktop_media_list.cc
+++ b/chrome/browser/media/webrtc/tab_desktop_media_list.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/metrics/android_metrics_provider.cc b/chrome/browser/metrics/android_metrics_provider.cc
index b1916e2..619bd76 100644
--- a/chrome/browser/metrics/android_metrics_provider.cc
+++ b/chrome/browser/metrics/android_metrics_provider.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/system/sys_info.h"
 #include "chrome/browser/android/feature_utilities.h"
+#include "chrome/browser/android/locale/locale_manager.h"
 
 namespace {
 
@@ -55,4 +56,5 @@
       "Android.MultiWindowMode.Active",
       chrome::android::GetIsInMultiWindowModeValue());
   EmitAppNotificationStatusHistogram();
+  LocaleManager::RecordUserTypeMetrics();
 }
diff --git a/chrome/browser/metrics/chrome_metrics_service_accessor.h b/chrome/browser/metrics/chrome_metrics_service_accessor.h
index a3f2f59..b6a06a99 100644
--- a/chrome/browser/metrics/chrome_metrics_service_accessor.h
+++ b/chrome/browser/metrics/chrome_metrics_service_accessor.h
@@ -117,6 +117,7 @@
   friend bool nux::IsNuxOnboardingEnabled(Profile* profile);
 
   // Testing related friends.
+  friend class ForceFieldTrialsBrowserTest;
   friend class MetricsReportingStateTest;
   friend class metrics::UkmConsentParamBrowserTest;
   FRIEND_TEST_ALL_PREFIXES(ChromeMetricsServiceAccessorTest,
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.cc b/chrome/browser/metrics/chromeos_metrics_provider.cc
index 979919b..deb0b07 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider.cc
+++ b/chrome/browser/metrics/chromeos_metrics_provider.cc
@@ -11,6 +11,7 @@
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -27,7 +28,9 @@
 #include "components/metrics/metrics_service.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
+#include "components/user_manager/user_type.h"
 #include "components/variations/service/variations_field_trial_creator.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -257,6 +260,7 @@
     }
   }
   arc::UpdateEnabledStateByUserTypeUMA();
+  UpdateUserTypeUMA();
 }
 
 void ChromeOSMetricsProvider::WriteBluetoothProto(
@@ -348,3 +352,16 @@
   full_hardware_class_ = full_hardware_class;
   callback.Run();
 }
+
+void ChromeOSMetricsProvider::UpdateUserTypeUMA() {
+  if (user_manager::UserManager::IsInitialized()) {
+    const user_manager::User* primary_user =
+        user_manager::UserManager::Get()->GetPrimaryUser();
+    if (primary_user) {
+      user_manager::UserType user_type = primary_user->GetType();
+      return base::UmaHistogramEnumeration(
+          "UMA.PrimaryUserType", user_type,
+          user_manager::UserType::NUM_USER_TYPES);
+    }
+  }
+}
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.h b/chrome/browser/metrics/chromeos_metrics_provider.h
index c814c7a..3477c7304 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider.h
+++ b/chrome/browser/metrics/chromeos_metrics_provider.h
@@ -91,6 +91,9 @@
   // Writes info about paired Bluetooth devices on this system.
   void WriteBluetoothProto(metrics::SystemProfileProto* system_profile_proto);
 
+  // Called from the ProvideCurrentSessionData(...) to record UserType.
+  void UpdateUserTypeUMA();
+
   // For collecting systemwide performance data via the UMA channel.
   std::unique_ptr<metrics::ProfileProvider> profile_provider_;
 
diff --git a/chrome/browser/metrics/variations/force_field_trials_browsertest.cc b/chrome/browser/metrics/variations/force_field_trials_browsertest.cc
new file mode 100644
index 0000000..eccae3f
--- /dev/null
+++ b/chrome/browser/metrics/variations/force_field_trials_browsertest.cc
@@ -0,0 +1,174 @@
+// 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 <string>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/system/sys_info.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/in_process_browser_test.h"
+
+namespace {
+
+const char kEnabledGroupName[] = "Enabled";
+const char kDisabledGroupName[] = "Disabled";
+
+// Create 20 ONE_TIME_RANDOMIZED test trials to make sure they persist their
+// state correctly between runs. We use 20 trials instead of just a couple so
+// that if there's a failure, it likely won't be too flaky since the chance
+// of all 20 randomly getting the same state is very low.
+const int kNumTestTrials = 20;
+
+}  // namespace
+
+// This test verifies the functionality of the --force-fieldtrials flag.
+// It spans multiple browser launches (using the PRE_ construct) and checks
+// that forcing two trials affects only those trials, but not other ones. For
+// the other trials, it checks that they get the same state between sessions
+// as they are ONE_TIME_RANDOMIZED.
+class ForceFieldTrialsBrowserTest : public InProcessBrowserTest,
+                                    public testing::WithParamInterface<bool> {
+ public:
+  ForceFieldTrialsBrowserTest() : metrics_consent_(GetParam()) {}
+  ~ForceFieldTrialsBrowserTest() override = default;
+
+  std::string GetTestTrialName(int trial_number) {
+    return base::StringPrintf("_TestTrial_%d", trial_number);
+  }
+
+  // Creates a 50/50 trial with ONE_TIME_RANDOMIZED consistency.
+  void CreateFiftyPercentTrial(const std::string& trial_name) {
+    auto* trial = base::FieldTrialList::FactoryGetFieldTrial(
+        trial_name, 100, "Default", base::FieldTrialList::kNoExpirationYear, 1,
+        1, base::FieldTrial::ONE_TIME_RANDOMIZED, nullptr);
+    trial->AppendGroup(kEnabledGroupName, 50);
+    trial->AppendGroup(kDisabledGroupName, 50);
+  }
+
+  base::FilePath GetTestFilePath(int trial_number) {
+    base::FilePath user_data_dir;
+    EXPECT_TRUE(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
+    std::string file_name =
+        "ForceFieldTrialsBrowserTest" + GetTestTrialName(trial_number);
+    return user_data_dir.AppendASCII(file_name);
+  }
+
+  // InProcessBrowserTest:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Force the first trial to "Enabled" and the second to "Disabled".
+    command_line->AppendSwitchASCII(
+        switches::kForceFieldTrials,
+        GetTestTrialName(1) + "/Enabled/" + GetTestTrialName(2) + "/Disabled");
+  }
+
+  void SetUp() override {
+    // Make metrics reporting work same as in Chrome branded builds, for test
+    // consistency between Chromium and Chrome builds.
+    ChromeMetricsServiceAccessor::SetForceIsMetricsReportingEnabledPrefLookup(
+        true);
+    // Based on GetParam(), either enable or disable metrics reporting.
+    ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
+        &metrics_consent_);
+    InProcessBrowserTest::SetUp();
+  }
+
+ private:
+  bool metrics_consent_;
+
+  DISALLOW_COPY_AND_ASSIGN(ForceFieldTrialsBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_P(ForceFieldTrialsBrowserTest, PRE_PRE_ForceTrials) {
+  // Empty test to bypass first-run provisional client id logic in
+  // metrics_state_manager.cc before running the other two tests.
+}
+
+// The "PRE_" prefix makes this test run before the corresponding named test.
+// This allows us to do a test spanning two Chrome launches and check the
+// consistency of behavior between them.
+IN_PROC_BROWSER_TEST_P(ForceFieldTrialsBrowserTest, PRE_ForceTrials) {
+  // Create twenty one-time randomized field trials. Note: Loop is 1-indexed so
+  // that we get trial names from "_TestTrial_1" to "_TestTrial_20".
+  for (int i = 1; i <= kNumTestTrials; i++)
+    CreateFiftyPercentTrial(GetTestTrialName(i));
+
+  // The first two trials has been forced via SetUpCommandLine() above.
+  EXPECT_EQ(kEnabledGroupName,
+            base::FieldTrialList::FindFullName(GetTestTrialName(1)));
+  EXPECT_EQ(kDisabledGroupName,
+            base::FieldTrialList::FindFullName(GetTestTrialName(2)));
+
+  // Save the other trials' group names to separate files, so we can check them
+  // in the ForceTrials test below.
+  for (int i = 3; i <= kNumTestTrials; i++) {
+    const std::string trial_group =
+        base::FieldTrialList::FindFullName(GetTestTrialName(i));
+    EXPECT_TRUE(trial_group == kEnabledGroupName ||
+                trial_group == kDisabledGroupName);
+
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    int bytes_to_write = base::checked_cast<int>(trial_group.length());
+    int bytes_written = base::WriteFile(GetTestFilePath(i), trial_group.c_str(),
+                                        bytes_to_write);
+    ASSERT_EQ(bytes_to_write, bytes_written);
+  }
+}
+
+IN_PROC_BROWSER_TEST_P(ForceFieldTrialsBrowserTest, ForceTrials) {
+#if defined(OS_CHROMEOS)
+  // TODO(asvitkine): This test fails on Linux Chrome OS bots. Since it passes
+  // on proper Chrome OS bots, and Linux Chrome OS is not an end user
+  // configuration, disable there for now. Would be good to understand the
+  // problem at some point, though. crbug.com/947132
+  if (!base::SysInfo::IsRunningOnChromeOS())
+    return;
+#endif  // defined(OS_CHROMEOS)
+
+  // Create twenty one-time randomized field trials. Note: Loop is 1-indexed so
+  // that we get trial names from "_TestTrial_1" to "_TestTrial_20". Since they
+  // are one-time randomized and there was a PRE_ test that created them earlier
+  // they should get the same groups as before.
+  for (int i = 1; i <= kNumTestTrials; i++)
+    CreateFiftyPercentTrial(GetTestTrialName(i));
+
+  // The first two trials has been forced via SetUpCommandLine() above.
+  EXPECT_EQ(kEnabledGroupName,
+            base::FieldTrialList::FindFullName(GetTestTrialName(1)));
+  EXPECT_EQ(kDisabledGroupName,
+            base::FieldTrialList::FindFullName(GetTestTrialName(2)));
+
+  // Check that the other trials have expected state.
+  for (int i = 3; i <= kNumTestTrials; i++) {
+    const std::string trial_group =
+        base::FieldTrialList::FindFullName(GetTestTrialName(i));
+    EXPECT_TRUE(trial_group == kEnabledGroupName ||
+                trial_group == kDisabledGroupName);
+
+    // Read the trial group name that was saved by PRE_ForceTrials from the
+    // corresponding test file.
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    char data[256];
+    int bytes_read = ReadFile(GetTestFilePath(i), data, sizeof(data));
+    ASSERT_NE(-1, bytes_read);
+
+    // Verify that the trial has the same group as last run and was unaffected
+    // by the --force-fieldtrials= switch.
+    EXPECT_EQ(std::string(data, bytes_read), trial_group)
+        << GetTestTrialName(i);
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(ForceFieldTrialsBrowserTests,
+                         ForceFieldTrialsBrowserTest,
+                         testing::Bool());
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc
index 9fa1e8c2..a9ec427 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -14,7 +14,7 @@
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/feature_list.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/sequenced_task_runner.h"
diff --git a/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc b/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
index 2c58b6a..4fb47be 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
@@ -13,7 +13,7 @@
 #include <wrl/client.h>
 #include <wrl/implements.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/chrome/browser/notifications/scheduler/notification_entry.cc b/chrome/browser/notifications/scheduler/notification_entry.cc
index e5405b73..461c693 100644
--- a/chrome/browser/notifications/scheduler/notification_entry.cc
+++ b/chrome/browser/notifications/scheduler/notification_entry.cc
@@ -8,7 +8,9 @@
 
 namespace notifications {
 
-NotificationEntry::NotificationEntry(const std::string& guid) : guid(guid) {}
+NotificationEntry::NotificationEntry(SchedulerClientType type,
+                                     const std::string& guid)
+    : type(type), guid(guid) {}
 
 NotificationEntry::~NotificationEntry() = default;
 
diff --git a/chrome/browser/notifications/scheduler/notification_entry.h b/chrome/browser/notifications/scheduler/notification_entry.h
index 335d29c1..eadfdb5f 100644
--- a/chrome/browser/notifications/scheduler/notification_entry.h
+++ b/chrome/browser/notifications/scheduler/notification_entry.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "chrome/browser/notifications/scheduler/notification_data.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_types.h"
 #include "chrome/browser/notifications/scheduler/schedule_params.h"
 
 namespace notifications {
@@ -15,9 +16,12 @@
 // Represents the in-memory counterpart of scheduled notification database
 // record.
 struct NotificationEntry {
-  explicit NotificationEntry(const std::string& guid);
+  NotificationEntry(SchedulerClientType type, const std::string& guid);
   ~NotificationEntry();
 
+  // The type of the notification.
+  SchedulerClientType type;
+
   // The unique id of the notification database entry.
   std::string guid;
 
diff --git a/chrome/browser/ntp_snippets/dependent_features.cc b/chrome/browser/ntp_snippets/dependent_features.cc
index 29c885a6..571d5ffb 100644
--- a/chrome/browser/ntp_snippets/dependent_features.cc
+++ b/chrome/browser/ntp_snippets/dependent_features.cc
@@ -21,9 +21,7 @@
 }
 
 bool AreAssetDownloadsEnabled() {
-  return !IsSimplifiedNtpEnabled() &&
-         base::FeatureList::IsEnabled(
-             features::kAssetDownloadSuggestionsFeature);
+  return !IsSimplifiedNtpEnabled();
 }
 
 bool AreOfflinePageDownloadsEnabled() {
diff --git a/chrome/browser/ntp_snippets/download_suggestions_provider.cc b/chrome/browser/ntp_snippets/download_suggestions_provider.cc
index 70be668c..cc35fea5 100644
--- a/chrome/browser/ntp_snippets/download_suggestions_provider.cc
+++ b/chrome/browser/ntp_snippets/download_suggestions_provider.cc
@@ -45,35 +45,12 @@
 const char kAssetDownloadsPrefix = 'D';
 const char kOfflinePageDownloadsPrefix = 'O';
 
-// NOTE: You must set variation param values for both features (one of them may
-// be disabled in future).
-const char kMaxSuggestionsCountParamName[] = "downloads_max_count";
-const char kMaxDownloadAgeHoursParamName[] = "downloads_max_age_hours";
-
-const base::Feature& GetEnabledDownloadsFeature() {
-  bool assets_enabled =
-      base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature);
-  DCHECK(assets_enabled ||
-         base::FeatureList::IsEnabled(
-             features::kOfflinePageDownloadSuggestionsFeature));
-  return assets_enabled ? features::kAssetDownloadSuggestionsFeature
-                        : features::kOfflinePageDownloadSuggestionsFeature;
-}
-
 int GetMaxSuggestionsCount() {
-  // One cannot get a variation param from a disabled feature, so the enabled
-  // one is taken.
-  return variations::GetVariationParamByFeatureAsInt(
-      GetEnabledDownloadsFeature(), kMaxSuggestionsCountParamName,
-      kDefaultMaxSuggestionsCount);
+  return kDefaultMaxSuggestionsCount;
 }
 
 int GetMaxDownloadAgeHours() {
-  // One cannot get a variation param from a disabled feature, so the enabled
-  // one is taken.
-  return variations::GetVariationParamByFeatureAsInt(
-      GetEnabledDownloadsFeature(), kMaxDownloadAgeHoursParamName,
-      kDefaultMaxDownloadAgeHours);
+  return kDefaultMaxDownloadAgeHours;
 }
 
 base::Time GetOfflinePagePublishedTime(const OfflinePageItem& item) {
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
index c3d40f6f..29c6367 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h"
 
 #include <algorithm>
+#include <limits>
 #include <string>
 #include <utility>
 
@@ -688,9 +689,11 @@
         ad_frame_data.visibility() != visibility)
       continue;
 
+    int frame_area = ad_frame_data.frame_size().GetCheckedArea().ValueOrDefault(
+        std::numeric_limits<int>::max());
     ADS_HISTOGRAM("FrameCounts.AdFrames.PerFrame.SqrtNumberOfPixels",
                   UMA_HISTOGRAM_COUNTS_10000, visibility,
-                  std::sqrt(ad_frame_data.frame_size().GetArea()));
+                  std::sqrt(frame_area));
     ADS_HISTOGRAM("FrameCounts.AdFrames.PerFrame.SmallestDimension",
                   UMA_HISTOGRAM_COUNTS_10000, visibility,
                   std::min(ad_frame_data.frame_size().width(),
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
index 45c4f5c..59c964f 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h"
 
 #include <algorithm>
+#include <limits>
 #include <string>
 
 #include "chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h"
@@ -163,7 +164,9 @@
 
 void FrameData::UpdateFrameVisibility() {
   visibility_ =
-      !is_display_none_ && frame_size_.GetArea() >= kMinimumVisibleFrameArea
+      !is_display_none_ &&
+              frame_size_.GetCheckedArea().ValueOrDefault(
+                  std::numeric_limits<int>::max()) >= kMinimumVisibleFrameArea
           ? FrameVisibility::kVisible
           : FrameVisibility::kNonVisible;
 }
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 073f009..d49789ac 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -11,7 +11,7 @@
 #include "base/bind.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
diff --git a/chrome/browser/plugins/plugin_finder.cc b/chrome/browser/plugins/plugin_finder.cc
index 427c192..75d783a8 100644
--- a/chrome/browser/plugins/plugin_finder.cc
+++ b/chrome/browser/plugins/plugin_finder.cc
@@ -100,10 +100,12 @@
   DCHECK(success);
   std::string language_str;
   plugin_dict->GetString("lang", &language_str);
+  bool plugin_is_deprecated = false;
+  plugin_dict->GetBoolean("plugin_is_deprecated", &plugin_is_deprecated);
 
   std::unique_ptr<PluginMetadata> plugin = std::make_unique<PluginMetadata>(
       identifier, name, display_url, GURL(url), GURL(help_url),
-      group_name_matcher, language_str);
+      group_name_matcher, language_str, plugin_is_deprecated);
   const base::ListValue* versions = NULL;
   if (plugin_dict->GetList("versions", &versions)) {
     for (auto it = versions->begin(); it != versions->end(); ++it) {
@@ -283,11 +285,11 @@
   }
 
   // The plugin metadata was not found, create a dummy one holding
-  // the name, identifier and group name only.
+  // the name, identifier and group name only. Dummy plugin is not deprecated.
   std::string identifier = GetIdentifier(plugin);
   std::unique_ptr<PluginMetadata> metadata = std::make_unique<PluginMetadata>(
       identifier, GetGroupName(plugin), false, GURL(), GURL(), plugin.name,
-      std::string());
+      std::string(), false /* plugin_is_deprecated */);
   for (size_t i = 0; i < plugin.mime_types.size(); ++i)
     metadata->AddMatchingMimeType(plugin.mime_types[i].mime_type);
 
diff --git a/chrome/browser/plugins/plugin_info_host_impl.cc b/chrome/browser/plugins/plugin_info_host_impl.cc
index 8f9bfa5..daf826e 100644
--- a/chrome/browser/plugins/plugin_info_host_impl.cc
+++ b/chrome/browser/plugins/plugin_info_host_impl.cc
@@ -416,9 +416,12 @@
       output->status = chrome::mojom::PluginStatus::kRestartRequired;
     }
 #endif
+    // Component Updater wouldn't provide a deprecated plugin.
+    bool plugin_is_deprecated = false;
     plugin_metadata = std::make_unique<PluginMetadata>(
         cus_plugin_info->id, cus_plugin_info->name, false, GURL(), GURL(),
-        base::ASCIIToUTF16(cus_plugin_info->id), std::string());
+        base::ASCIIToUTF16(cus_plugin_info->id), std::string(),
+        plugin_is_deprecated);
   }
   GetPluginInfoFinish(params, std::move(output), std::move(callback),
                       std::move(plugin_metadata));
diff --git a/chrome/browser/plugins/plugin_infobar_delegates.cc b/chrome/browser/plugins/plugin_infobar_delegates.cc
index 122a8adf..0b84d2bb8 100644
--- a/chrome/browser/plugins/plugin_infobar_delegates.cc
+++ b/chrome/browser/plugins/plugin_infobar_delegates.cc
@@ -41,7 +41,7 @@
 namespace {
 
 base::string16 GetInfoBarMessage(const PluginMetadata& metadata) {
-  return l10n_util::GetStringFUTF16(metadata.IsPluginDeprecated()
+  return l10n_util::GetStringFUTF16(metadata.plugin_is_deprecated()
                                         ? IDS_PLUGIN_DEPRECATED_PROMPT
                                         : IDS_PLUGIN_OUTDATED_PROMPT,
                                     metadata.name());
@@ -115,7 +115,7 @@
 }
 
 int OutdatedPluginInfoBarDelegate::GetButtons() const {
-  if (plugin_metadata_->IsPluginDeprecated())
+  if (plugin_metadata_->plugin_is_deprecated())
     return BUTTON_CANCEL;
 
   return BUTTON_OK | BUTTON_CANCEL;
diff --git a/chrome/browser/plugins/plugin_metadata.cc b/chrome/browser/plugins/plugin_metadata.cc
index 4324079..0ba33a0 100644
--- a/chrome/browser/plugins/plugin_metadata.cc
+++ b/chrome/browser/plugins/plugin_metadata.cc
@@ -32,15 +32,16 @@
                                const GURL& plugin_url,
                                const GURL& help_url,
                                const base::string16& group_name_matcher,
-                               const std::string& language)
+                               const std::string& language,
+                               bool plugin_is_deprecated)
     : identifier_(identifier),
       name_(name),
       group_name_matcher_(group_name_matcher),
       url_for_display_(url_for_display),
       plugin_url_(plugin_url),
       help_url_(help_url),
-      language_(language) {
-}
+      language_(language),
+      plugin_is_deprecated_(plugin_is_deprecated) {}
 
 PluginMetadata::~PluginMetadata() {
 }
@@ -63,12 +64,6 @@
   return base::ContainsValue(all_mime_types_, mime_type);
 }
 
-bool PluginMetadata::IsPluginDeprecated() const {
-  // TODO(crbug/918427): this is a placeholder behavior; please replace once
-  // the metadata standard for blocking plugins has been finalized.
-  return plugin_url().is_empty();
-}
-
 bool PluginMetadata::MatchesPlugin(const content::WebPluginInfo& plugin) {
   for (size_t i = 0; i < matching_mime_types_.size(); ++i) {
     // To have a match, every one of the |matching_mime_types_|
@@ -105,6 +100,12 @@
 
 PluginMetadata::SecurityStatus PluginMetadata::GetSecurityStatus(
     const content::WebPluginInfo& plugin) const {
+  // Deprecated plugins should be treated as out-of-date by the renderer.
+  // The browser will show an infobar explaining that it is deprecated without
+  // the ability to update.
+  if (plugin_is_deprecated())
+    return SECURITY_STATUS_OUT_OF_DATE;
+
   if (versions_.empty()) {
     // Unknown plugins require authorization.
     return SECURITY_STATUS_REQUIRES_AUTHORIZATION;
@@ -132,13 +133,9 @@
 }
 
 std::unique_ptr<PluginMetadata> PluginMetadata::Clone() const {
-  PluginMetadata* copy = new PluginMetadata(identifier_,
-                                            name_,
-                                            url_for_display_,
-                                            plugin_url_,
-                                            help_url_,
-                                            group_name_matcher_,
-                                            language_);
+  PluginMetadata* copy = new PluginMetadata(
+      identifier_, name_, url_for_display_, plugin_url_, help_url_,
+      group_name_matcher_, language_, plugin_is_deprecated_);
   copy->versions_ = versions_;
   return base::WrapUnique(copy);
 }
diff --git a/chrome/browser/plugins/plugin_metadata.h b/chrome/browser/plugins/plugin_metadata.h
index b93e2ea..4ec966b63 100644
--- a/chrome/browser/plugins/plugin_metadata.h
+++ b/chrome/browser/plugins/plugin_metadata.h
@@ -48,7 +48,8 @@
                  const GURL& plugin_url,
                  const GURL& help_url,
                  const base::string16& group_name_matcher,
-                 const std::string& language);
+                 const std::string& language,
+                 bool plugin_is_deprecated);
   ~PluginMetadata();
 
   // Unique identifier for the plugin.
@@ -70,7 +71,7 @@
   const std::string& language() const { return language_; }
 
   // Returns whether the plugin has been deprecated and cannot be updated.
-  bool IsPluginDeprecated() const;
+  bool plugin_is_deprecated() const { return plugin_is_deprecated_; }
 
   bool HasMimeType(const std::string& mime_type) const;
   void AddMimeType(const std::string& mime_type);
@@ -110,6 +111,7 @@
   std::map<base::Version, SecurityStatus, VersionComparator> versions_;
   std::vector<std::string> all_mime_types_;
   std::vector<std::string> matching_mime_types_;
+  const bool plugin_is_deprecated_;
 
   DISALLOW_COPY_AND_ASSIGN(PluginMetadata);
 };
diff --git a/chrome/browser/plugins/plugin_metadata_unittest.cc b/chrome/browser/plugins/plugin_metadata_unittest.cc
index 25748e7..623b1a19 100644
--- a/chrome/browser/plugins/plugin_metadata_unittest.cc
+++ b/chrome/browser/plugins/plugin_metadata_unittest.cc
@@ -31,13 +31,11 @@
   const PluginMetadata::SecurityStatus kRequiresAuthorization =
       PluginMetadata::SECURITY_STATUS_REQUIRES_AUTHORIZATION;
 
-  PluginMetadata plugin_metadata("claybrick-writer",
-                                 base::ASCIIToUTF16("ClayBrick Writer"),
-                                 true,
-                                 GURL(),
-                                 GURL(),
-                                 base::ASCIIToUTF16("ClayBrick"),
-                                 std::string());
+  PluginMetadata plugin_metadata(
+      "claybrick-writer", base::ASCIIToUTF16("ClayBrick Writer"), true, GURL(),
+      GURL(), base::ASCIIToUTF16("ClayBrick"), std::string(),
+      false /* plugin_is_deprecated */);
+
   EXPECT_EQ(kRequiresAuthorization,
             GetSecurityStatus(&plugin_metadata, "1.2.3"));
 
@@ -45,6 +43,8 @@
   plugin_metadata.AddVersion(base::Version("10"), kOutOfDate);
   plugin_metadata.AddVersion(base::Version("10.2.1"), kUpToDate);
 
+  EXPECT_FALSE(plugin_metadata.plugin_is_deprecated());
+
   // Invalid version.
   EXPECT_EQ(kOutOfDate, GetSecurityStatus(&plugin_metadata, "foo"));
 
@@ -58,3 +58,26 @@
   EXPECT_EQ(kUpToDate, GetSecurityStatus(&plugin_metadata, "10.2.1"));
   EXPECT_EQ(kUpToDate, GetSecurityStatus(&plugin_metadata, "11"));
 }
+
+TEST(PluginMetadataTest, DeprecatedSecurityStatus) {
+  const PluginMetadata::SecurityStatus kOutOfDate =
+      PluginMetadata::SECURITY_STATUS_OUT_OF_DATE;
+
+  PluginMetadata plugin_metadata(
+      "claybrick-writer", base::ASCIIToUTF16("ClayBrick Writer"), true, GURL(),
+      GURL(), base::ASCIIToUTF16("ClayBrick"), std::string(),
+      true /* plugin_is_deprecated */);
+
+  // It doesn't really matter what's in the versions field of a deprecated
+  // plugin. But canonically, we would expect exactly one version:
+  // Version "0" marked "out_of_date".
+  plugin_metadata.AddVersion(base::Version("0"),
+                             PluginMetadata::SECURITY_STATUS_OUT_OF_DATE);
+
+  EXPECT_TRUE(plugin_metadata.plugin_is_deprecated());
+
+  // All versions should be considered out of date for deprecated plugins.
+  EXPECT_EQ(kOutOfDate, GetSecurityStatus(&plugin_metadata, "foo"));
+  EXPECT_EQ(kOutOfDate, GetSecurityStatus(&plugin_metadata, "0"));
+  EXPECT_EQ(kOutOfDate, GetSecurityStatus(&plugin_metadata, "1.2.3"));
+}
diff --git a/chrome/browser/policy/browser_dm_token_storage_linux.cc b/chrome/browser/policy/browser_dm_token_storage_linux.cc
index 427f7b86e..164e195d 100644
--- a/chrome/browser/policy/browser_dm_token_storage_linux.cc
+++ b/chrome/browser/policy/browser_dm_token_storage_linux.cc
@@ -12,10 +12,10 @@
 #include "base/callback.h"
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
 #include "base/path_service.h"
-#include "base/sha1.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/policy/browser_dm_token_storage_mac.mm b/chrome/browser/policy/browser_dm_token_storage_mac.mm
index 5021562..00a19a080 100644
--- a/chrome/browser/policy/browser_dm_token_storage_mac.mm
+++ b/chrome/browser/policy/browser_dm_token_storage_mac.mm
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_cftyperef.h"
@@ -19,7 +20,6 @@
 #include "base/no_destructor.h"
 #include "base/optional.h"
 #include "base/path_service.h"
-#include "base/sha1.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
diff --git a/chrome/browser/policy/browser_dm_token_storage_mac_unittest.cc b/chrome/browser/policy/browser_dm_token_storage_mac_unittest.cc
index 8bc3d4d..a0ec15bc 100644
--- a/chrome/browser/policy/browser_dm_token_storage_mac_unittest.cc
+++ b/chrome/browser/policy/browser_dm_token_storage_mac_unittest.cc
@@ -10,11 +10,11 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
+#include "base/hash/sha1.h"
 #include "base/mac/foundation_util.h"
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/sha1.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
index 53177032..5631ae99 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/location.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index fa34255..07ac09d 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -406,6 +406,12 @@
 const char kVoiceInteractionActivityControlAcceptedDeprecated[] =
     "settings.voice_interaction.activity_control.accepted";
 
+// Deprecated 3/2019.
+const char kCurrentThemeImages[] = "extensions.theme.images";
+const char kCurrentThemeColors[] = "extensions.theme.colors";
+const char kCurrentThemeTints[] = "extensions.theme.tints";
+const char kCurrentThemeDisplayProperties[] = "extensions.theme.properties";
+
 // Register prefs used only for migration (clearing or moving to a new key).
 void RegisterProfilePrefsForMigration(
     user_prefs::PrefRegistrySyncable* registry) {
@@ -437,6 +443,11 @@
 
   registry->RegisterBooleanPref(
       kVoiceInteractionActivityControlAcceptedDeprecated, false);
+
+  registry->RegisterDictionaryPref(kCurrentThemeImages);
+  registry->RegisterDictionaryPref(kCurrentThemeColors);
+  registry->RegisterDictionaryPref(kCurrentThemeTints);
+  registry->RegisterDictionaryPref(kCurrentThemeDisplayProperties);
 }
 
 }  // namespace
@@ -979,4 +990,10 @@
   // Added 3/2019.
   syncer::ClearObsoleteFirstSyncTime(profile_prefs);
   syncer::ClearObsoleteSyncLongPollIntervalSeconds(profile_prefs);
+
+  // Added 3/2019.
+  profile_prefs->ClearPref(kCurrentThemeImages);
+  profile_prefs->ClearPref(kCurrentThemeColors);
+  profile_prefs->ClearPref(kCurrentThemeTints);
+  profile_prefs->ClearPref(kCurrentThemeDisplayProperties);
 }
diff --git a/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc b/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
index 2b9a3e2a..b038a8c 100644
--- a/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
@@ -8,10 +8,10 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
+#include "base/hash/sha1.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
index 23b6b3e..d328244 100644
--- a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
+++ b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
@@ -21,10 +21,10 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/hash/md5.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
diff --git a/chrome/browser/printing/pwg_raster_converter_browsertest.cc b/chrome/browser/printing/pwg_raster_converter_browsertest.cc
index c1e192c..b2e3f2b 100644
--- a/chrome/browser/printing/pwg_raster_converter_browsertest.cc
+++ b/chrome/browser/printing/pwg_raster_converter_browsertest.cc
@@ -6,10 +6,10 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
+#include "base/hash/sha1.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
index 713ae2f..26e8cf5 100644
--- a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
+++ b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
@@ -9,7 +9,7 @@
 
 #include "base/bind.h"
 #include "base/guid.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/cancellation_flag.h"
diff --git a/chrome/browser/profiling_host/memlog_browsertest.cc b/chrome/browser/profiling_host/memlog_browsertest.cc
index 67238e6..074f641 100644
--- a/chrome/browser/profiling_host/memlog_browsertest.cc
+++ b/chrome/browser/profiling_host/memlog_browsertest.cc
@@ -44,43 +44,46 @@
                           public testing::WithParamInterface<TestParam> {
   void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
     InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
-    if (GetParam().start_profiling_with_command_line_flag) {
-      if (GetParam().mode == Mode::kAllRenderers) {
-        command_line->AppendSwitchASCII(
-            heap_profiling::kMemlog, heap_profiling::kMemlogModeAllRenderers);
-      } else if (GetParam().mode == Mode::kAll) {
-        command_line->AppendSwitchASCII(heap_profiling::kMemlog,
-                                        heap_profiling::kMemlogModeAll);
-      } else {
-        NOTREACHED();
-      }
 
-      if (!GetParam().stream_samples)
-        command_line->AppendSwitch(heap_profiling::kMemlogInProcess);
+    if (GetParam().stream_samples) {
+      command_line->AppendSwitchASCII(heap_profiling::kMemlogInProcess,
+                                      heap_profiling::kMemlogInProcessDisabled);
+    }
 
-      if (!GetParam().should_sample) {
-        command_line->AppendSwitchASCII(heap_profiling::kMemlogSamplingRate,
-                                        "1");
-      }
+    if (!GetParam().start_profiling_with_command_line_flag)
+      return;
 
-      if (GetParam().stack_mode == mojom::StackMode::PSEUDO) {
-        command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
-                                        heap_profiling::kMemlogStackModePseudo);
-      } else if (GetParam().stack_mode ==
-                 mojom::StackMode::NATIVE_WITH_THREAD_NAMES) {
-        command_line->AppendSwitchASCII(
-            heap_profiling::kMemlogStackMode,
-            heap_profiling::kMemlogStackModeNativeWithThreadNames);
-      } else if (GetParam().stack_mode ==
-                 mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES) {
-        command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
-                                        heap_profiling::kMemlogStackModeNative);
-      } else if (GetParam().stack_mode == mojom::StackMode::MIXED) {
-        command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
-                                        heap_profiling::kMemlogStackModeMixed);
-      } else {
-        NOTREACHED();
-      }
+    if (GetParam().mode == Mode::kAllRenderers) {
+      command_line->AppendSwitchASCII(heap_profiling::kMemlogMode,
+                                      heap_profiling::kMemlogModeAllRenderers);
+    } else if (GetParam().mode == Mode::kAll) {
+      command_line->AppendSwitchASCII(heap_profiling::kMemlogMode,
+                                      heap_profiling::kMemlogModeAll);
+    } else {
+      NOTREACHED();
+    }
+
+    if (!GetParam().should_sample) {
+      command_line->AppendSwitchASCII(heap_profiling::kMemlogSamplingRate, "1");
+    }
+
+    if (GetParam().stack_mode == mojom::StackMode::PSEUDO) {
+      command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
+                                      heap_profiling::kMemlogStackModePseudo);
+    } else if (GetParam().stack_mode ==
+               mojom::StackMode::NATIVE_WITH_THREAD_NAMES) {
+      command_line->AppendSwitchASCII(
+          heap_profiling::kMemlogStackMode,
+          heap_profiling::kMemlogStackModeNativeWithThreadNames);
+    } else if (GetParam().stack_mode ==
+               mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES) {
+      command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
+                                      heap_profiling::kMemlogStackModeNative);
+    } else if (GetParam().stack_mode == mojom::StackMode::MIXED) {
+      command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
+                                      heap_profiling::kMemlogStackModeMixed);
+    } else {
+      NOTREACHED();
     }
   }
 };
diff --git a/chrome/browser/push_messaging/push_messaging_constants.cc b/chrome/browser/push_messaging/push_messaging_constants.cc
index ec32bc1..bd0d33d6 100644
--- a/chrome/browser/push_messaging/push_messaging_constants.cc
+++ b/chrome/browser/push_messaging/push_messaging_constants.cc
@@ -5,9 +5,6 @@
 #include "chrome/browser/push_messaging/push_messaging_constants.h"
 
 const char kPushMessagingGcmEndpoint[] =
-    "https://android.googleapis.com/gcm/send/";
-
-const char kPushMessagingPushProtocolEndpoint[] =
     "https://fcm.googleapis.com/fcm/send/";
 
 const char kPushMessagingForcedNotificationTag[] =
diff --git a/chrome/browser/push_messaging/push_messaging_constants.h b/chrome/browser/push_messaging/push_messaging_constants.h
index 7830af0..f6c9e4bf 100644
--- a/chrome/browser/push_messaging/push_messaging_constants.h
+++ b/chrome/browser/push_messaging/push_messaging_constants.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_
 
 extern const char kPushMessagingGcmEndpoint[];
-extern const char kPushMessagingPushProtocolEndpoint[];
 
 // The tag of the notification that will be automatically shown if a webapp
 // receives a push message then fails to show a notification.
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc
index 98084fb..9e0edb5 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -418,8 +418,7 @@
 // GetEndpoint method ----------------------------------------------------------
 
 GURL PushMessagingServiceImpl::GetEndpoint(bool standard_protocol) const {
-  return GURL(standard_protocol ? kPushMessagingPushProtocolEndpoint
-                                : kPushMessagingGcmEndpoint);
+  return GURL(kPushMessagingGcmEndpoint);
 }
 
 // Subscribe and GetPermissionStatus methods -----------------------------------
diff --git a/chrome/browser/push_messaging/push_messaging_service_unittest.cc b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
index 7b1f142..1740dafc 100644
--- a/chrome/browser/push_messaging/push_messaging_service_unittest.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
@@ -257,12 +257,3 @@
 
   EXPECT_EQ(p256dh, push_service->NormalizeSenderInfo(p256dh));
 }
-
-TEST_F(PushMessagingServiceTest, DifferentEndpoints) {
-  PushMessagingServiceImpl* push_service = profile()->GetPushMessagingService();
-  ASSERT_TRUE(push_service);
-
-  // Verifies that the service returns different endpoints depending on whether
-  // support for the standard protocol is requested.
-  EXPECT_NE(push_service->GetEndpoint(true), push_service->GetEndpoint(false));
-}
diff --git a/chrome/browser/resource_coordinator/utils.cc b/chrome/browser/resource_coordinator/utils.cc
index 4d4b322..803ca25 100644
--- a/chrome/browser/resource_coordinator/utils.cc
+++ b/chrome/browser/resource_coordinator/utils.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/resource_coordinator/utils.h"
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/numerics/safe_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/resource_coordinator/resource_coordinator_parts.h"
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.html b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.html
index 1a82518..fd8a787 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.html
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.html
@@ -12,24 +12,17 @@
     <script src="chrome://resources/js/util.js"></script>
     <script src="arc_graphics_tracing_ui.js"></script>
     <script src="arc_graphics_tracing.js"></script>
+    <title>ARC graphics tracing</title>
   </head>
-  <title>Graphics buffer</title>
-<body>
-  <div id="arc-graphics-tracing-control">
-    <h4>ARC graphics tracing</h4>
-    <input type="button"
-           id="arc-graphics-tracing-start"
-           value="Start tracing in ">
-    <input type="text"
-           id="arc-graphics-tracing-start-delay"
-           value="3">
-    seconds for
-    <input type="text"
-           id="arc-graphics-tracing-duration"
-           value="2">
-    seconds.
-  </div>
-  <div id='arc-event-bands'></div>
-  <svg id='arc-event-band-tooltip'></svg>
-</body>
+  <body>
+    <div id="arc-graphics-tracing-control">
+      <h3>ARC graphics tracing</h3>
+      Use <b>Ctrl+Shift+G</b> in active Android app to start/stop tracing.
+      <input type="checkbox" id="arc-graphics-tracing-stop-on-jank">
+      Stop on jank. Status: <i id="arc-graphics-tracing-status">Idle</i>
+    </div>
+    <hr>
+    <div id='arc-event-bands'></div>
+    <svg id='arc-event-band-tooltip'></svg>
+  </body>
 </html>
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.js b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.js
index e23e7d4e..54bd0cd9 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.js
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.js
@@ -12,14 +12,17 @@
      * Initializes internal structures.
      */
     initialize: function() {
-      var startDelay = $('arc-graphics-tracing-start-delay');
-      var duration = $('arc-graphics-tracing-duration');
-      $('arc-graphics-tracing-start')
-          .addEventListener('click', function(event) {
-            chrome.send(
-                'startTracing',
-                [Number(startDelay.value), Number(duration.value)]);
-          }, false);
+      var stopOnJank = $('arc-graphics-tracing-stop-on-jank');
+      stopOnJank.addEventListener('click', function(event) {
+        chrome.send('setStopOnJank', [stopOnJank.checked]);
+      }, false);
+      chrome.send('ready');
+      chrome.send('setStopOnJank', [stopOnJank.checked]);
+    },
+
+    setStatus: function(statusText) {
+      var status = $('arc-graphics-tracing-status');
+      status.textContent = statusText;
     },
 
     setModel: function(model) {
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
index 23d6568..3fb41fa 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
@@ -430,7 +430,7 @@
     var globalEvent = this.findGlobalEvent_(eventTimestamp, 200 /* distance */);
     if (globalEvent) {
       // Show the global event info.
-      var attributes = eventAttributes[global_event[0]];
+      var attributes = eventAttributes[globalEvent[0]];
       SVG.addText(
           this.tooltip, horizontalGap, yOffset, 12,
           attributes.name + ' ' + timestempToMsText(globalEvent[1]) + ' ms.');
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
index 44bbe88b..d8710ec0 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -368,7 +368,8 @@
  * @return {boolean}
  */
 AutomationPredicate.structuralContainer = AutomationPredicate.roles([
-  Role.ALERT_DIALOG, Role.CLIENT, Role.DIALOG, Role.ROOT_WEB_AREA,
+  Role.ALERT_DIALOG, Role.CLIENT, Role.DIALOG, Role.LAYOUT_TABLE,
+  Role.LAYOUT_TABLE_CELL, Role.LAYOUT_TABLE_ROW, Role.ROOT_WEB_AREA,
   Role.WEB_VIEW, Role.WINDOW, Role.EMBEDDED_OBJECT, Role.IFRAME,
   Role.IFRAME_PRESENTATIONAL, Role.IGNORED, Role.UNKNOWN
 ]);
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index 20df0b4..952eeb28 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -1786,12 +1786,13 @@
 TEST_F('ChromeVoxBackgroundTest', 'LayoutTable', function() {
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(function() {/*
-    <table><tr><td>start</td></tr></table>
+    <table><tr><td>start</td></tr></table><p>end</p>
   */}, function(root) {
-    mockFeedback.expectSpeech(
-            'start',
-            'row 1 column 1',
-            'Table , 1 by 1')
+    mockFeedback.expectSpeech('start')
+        .call(doCmd('nextObject'))
+        .expectNextSpeechUtteranceIsNot('row 1 column 1')
+        .expectNextSpeechUtteranceIsNot('Table , 1 by 1')
+        .expectSpeech('end')
         .replay();
   });
 });
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index 5cbc184..c2b87c3 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -230,9 +230,6 @@
     msgId: 'role_img',
   },
   inputTime: {msgId: 'input_type_time', inherits: 'abstractContainer'},
-  layoutTable: {inherits: 'table'},
-  layoutTableCell: {msgId: '', inherits: 'cell'},
-  layoutTableRow: {msgId: 'role_row', inherits: 'row'},
   link: {msgId: 'role_link', earconId: 'LINK'},
   list: {msgId: 'role_list'},
   listBox: {msgId: 'role_listbox', earconId: 'LISTBOX'},
@@ -467,13 +464,12 @@
           $if($inPageLinkTarget, @internal_link, $role) $description`,
     },
     list: {
-      enter: `$role @@list_with_items($countChildren(listItem))`,
+      enter: `$role @@list_with_items($setSize)`,
       speak: `$nameFromNode $descendants $role
-          @@list_with_items($countChildren(listItem)) $description $state`
+          @@list_with_items($setSize) $description $state`
     },
     listBox: {
-      enter: `$nameFromNode
-          $role @@list_with_items($countChildren(listBoxOption))
+      enter: `$nameFromNode $role @@list_with_items($setSize)
           $restriction $description`
     },
     listBoxOption: {
@@ -488,29 +484,23 @@
     menu: {
       enter: `$name $role `,
       speak: `$name $node(activeDescendant)
-          $role @@list_with_items(
-              $countChildren(menuItem, menuItemCheckBox, menuItemRadio))
-          $description $state $restriction`
+          $role @@list_with_items($setSize) $description $state $restriction`
     },
     menuItem: {
       speak: `$name $role $if($hasPopup, @has_submenu)
-          @describe_index($if($posInSet, $posInSet, $indexInParent(menuItem, menuItemCheckBox, menuItemRadio)),
-              $if($setSize, $setSize, $parentChildCount(menuItem, menuItemCheckBox, menuItemRadio)))
-          $description $state $restriction`
+          @describe_index($posInSet, $setSize) $description $state $restriction`
     },
     menuItemCheckBox: {
       speak: `$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF))
           $name $role $checked $state $restriction $description
-          @describe_index($if($posInSet, $posInSet, $indexInParent(menuItem, menuItemCheckBox, menuItemRadio)),
-              $if($setSize, $setSize, $parentChildCount(menuItem, menuItemCheckBox, menuItemRadio))) `
+          @describe_index($posInSet, $setSize)`
     },
     menuItemRadio: {
       speak: `$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF))
           $if($checked, @describe_radio_selected($name),
           @describe_radio_unselected($name)) $state $roleDescription
           $restriction $description
-          @describe_index($if($posInSet, $posInSet, $indexInParent(menuItem, menuItemCheckBox, menuItemRadio)),
-              $if($setSize, $setSize, $parentChildCount(menuItem, menuItemCheckBox, menuItemRadio))) `
+          @describe_index($posInSet, $setSize)`
     },
     menuListOption: {
       speak: `$name $role @describe_index($posInSet, $setSize) $state
@@ -581,10 +571,7 @@
           $name $role $pressed $description $state $restriction`
     },
     toolbar: {enter: `$name $role $description $restriction`},
-    tree: {
-      enter: `$name $role @@list_with_items($countChildren(treeItem))
-          $restriction`
-    },
+    tree: {enter: `$name $role @@list_with_items($setSize) $restriction`},
     treeItem: {
       enter: `$role $expanded $collapsed $restriction
           @describe_index($posInSet, $setSize)
@@ -1324,25 +1311,6 @@
             this.append_(buff, String(count));
             ruleStr.writeTokenWithValue(token, String(count));
           }
-        } else if (token == 'parentChildCount') {
-          if (node.parent) {
-            options.annotation.push(token);
-            var roles;
-            if (tree.firstChild) {
-              roles = this.createRoles_(tree);
-            } else {
-              roles = new Set();
-              roles.add(node.role);
-            }
-
-            var count = node.parent.children
-                            .filter(function(child) {
-                              return roles.has(child.role);
-                            })
-                            .length;
-            this.append_(buff, String(count));
-            ruleStr.writeTokenWithValue(token, String(count));
-          }
         } else if (token == 'restriction') {
           var msg = Output.RESTRICTION_STATE_MAP[node.restriction];
           if (msg) {
@@ -1440,7 +1408,7 @@
           } else if (info) {
             if (this.formatOptions_.braille)
               msg = Msgs.getMsg(info.msgId + '_brl');
-            else
+            else if (info.msgId)
               msg = Msgs.getMsg(info.msgId);
           } else {
             // We can safely ignore this role. ChromeVox output tests cover
@@ -1593,13 +1561,9 @@
             this.format_(node, '$indexInParent', buff, ruleStr);
           }
         } else if (token == 'setSize') {
-          if (node.setSize !== undefined) {
-            this.append_(buff, String(node.setSize));
-            ruleStr.writeTokenWithValue(token, String(node.setSize));
-          } else {
-            ruleStr.writeToken(token);
-            this.format_(node, '$parentChildCount', buff, ruleStr);
-          }
+          var size = node.setSize ? node.setSize : 0;
+          this.append_(buff, String(size));
+          ruleStr.writeTokenWithValue(token, String(node.setSize));
         } else if (tree.firstChild) {
           // Custom functions.
           if (token == 'if') {
@@ -1633,16 +1597,6 @@
                 tree.firstChild.value, node.location || undefined));
             this.append_(buff, '', options);
             ruleStr.writeTokenWithValue(token, tree.firstChild.value);
-          } else if (token == 'countChildren') {
-            var roles = this.createRoles_(tree);
-
-            var count = node.children
-                            .filter(function(e) {
-                              return roles.has(e.role);
-                            })
-                            .length;
-            this.append_(buff, String(count));
-            ruleStr.writeTokenWithValue(token, String(count));
           }
         }
       } else if (prefix == '@') {
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index be91a1c..3425340 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -7,6 +7,7 @@
 
 js_type_check("closure_compile") {
   deps = [
+    ":multidevice_setup_first_run",
     ":offline_ad_login",
     ":oobe_change_picture",
     ":oobe_select",
@@ -41,6 +42,14 @@
   ]
 }
 
+js_library("multidevice_setup_first_run") {
+  deps = [
+    "//ui/webui/resources/cr_components/chromeos/multidevice_setup:mojo_api",
+    "//ui/webui/resources/cr_components/chromeos/multidevice_setup:multidevice_setup",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
 js2gtest("login_unitjs_tests") {
   # These could be unit tests, except they need a browser context in order
   # to construct a DOMParser object - so they are webui tests.
diff --git a/chrome/browser/resources/chromeos/login/multidevice_setup_first_run.html b/chrome/browser/resources/chromeos/login/multidevice_setup_first_run.html
index 85f2f5f..2316e51 100644
--- a/chrome/browser/resources/chromeos/login/multidevice_setup_first_run.html
+++ b/chrome/browser/resources/chromeos/login/multidevice_setup_first_run.html
@@ -5,6 +5,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://oobe/custom_elements.html">
+<link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/mojo_api.html">
 <link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/multidevice_setup_shared_css.html">
 <link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
diff --git a/chrome/browser/resources/chromeos/login/multidevice_setup_first_run.js b/chrome/browser/resources/chromeos/login/multidevice_setup_first_run.js
index fb210cc..c2660bf6 100644
--- a/chrome/browser/resources/chromeos/login/multidevice_setup_first_run.js
+++ b/chrome/browser/resources/chromeos/login/multidevice_setup_first_run.js
@@ -14,9 +14,9 @@
     constructor() {
       /**
        * @private {?chromeos.multideviceSetup.mojom.
-       *               PrivilegedHostDeviceSetterPtr}
+       *               PrivilegedHostDeviceSetterProxy}
        */
-      this.ptr_ = null;
+      this.proxy_ = null;
     }
 
     /** @override */
@@ -30,15 +30,13 @@
       // required.
       assert(!opt_authToken);
 
-      if (!this.ptr_) {
-        this.ptr_ =
-            new chromeos.multideviceSetup.mojom.PrivilegedHostDeviceSetterPtr();
-        Mojo.bindInterface(
-            chromeos.multideviceSetup.mojom.PrivilegedHostDeviceSetter.name,
-            mojo.makeRequest(this.ptr_).handle);
+      if (!this.proxy_) {
+        this.proxy_ = chromeos.multideviceSetup.mojom.PrivilegedHostDeviceSetter
+                          .getProxy();
       }
 
-      return this.ptr_.setHostDevice(hostDeviceId);
+      return /** @type {!Promise<{success: boolean}>} */ (
+          this.proxy_.setHostDevice(hostDeviceId));
     }
 
     /** @override */
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_welcome.js b/chrome/browser/resources/chromeos/login/oobe_screen_welcome.js
index c47509b..812a0256 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_welcome.js
@@ -8,8 +8,7 @@
 
 login.createScreen('WelcomeScreen', 'connect', function() {
   return {
-    EXTERNAL_API:
-        ['onInputMethodIdSetFromBackend', 'onTimezoneIdSetFromBackend'],
+    EXTERNAL_API: ['onInputMethodIdSetFromBackend'],
 
     /** @override */
     decorate: function() {
@@ -23,11 +22,6 @@
       $('oobe-welcome-md').setSelectedKeyboard(inputMethodId);
     },
 
-    onTimezoneIdSetFromBackend: function(timezoneId) {
-      // Timezone change triggers a localized content update so we don't need to
-      // do anything here.
-    },
-
     onLanguageSelected_: function(languageId) {
       chrome.send('WelcomeScreen.setLocaleId', [languageId]);
     },
diff --git a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip_unittest.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip_unittest.cc
index 4cf33cf5..8092d30 100644
--- a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip_unittest.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip_unittest.cc
@@ -16,8 +16,8 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/optional.h"
 #include "base/path_service.h"
 #include "base/strings/string_piece.h"
diff --git a/chrome/browser/resources/discards/graph_doc.js b/chrome/browser/resources/discards/graph_doc.js
index 415dafa..47e4e66 100644
--- a/chrome/browser/resources/discards/graph_doc.js
+++ b/chrome/browser/resources/discards/graph_doc.js
@@ -2,6 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Target y position for page nodes.
+const kPageNodesTargetY = 20;
+
+// Range occupied by page nodes at the top of the graph view.
+const kPageNodesYRange = 100;
+
+// Range occupied by process nodes at the bottom of the graph view.
+const kProcessNodesYRange = 150;
+
+// Target y position for frame nodes.
+const kFrameNodesTargetY = kPageNodesYRange + 50;
+
+// Range that frame nodes cannot enter at the top/bottom of the graph view.
+const kFrameNodesTopMargin = kPageNodesYRange;
+const kFrameNodesBottomMargin = kProcessNodesYRange + 50;
 
 /** @implements {d3.ForceNode} */
 class GraphNode {
@@ -24,19 +39,35 @@
   }
 
   /**
-   * @param {number} height
+   * @param {number} graph_height: Height of the graph view (svg).
    * @return {number}
    */
-  yPosition(height) {
-    // By default, nodes are biased mildly to the center of the graph.
-    return height / 2;
+  targetYPosition(graph_height) {
+    return 0;
   }
 
-  /** @return {number} */
-  yStrength() {
+  /**
+   * @return {number}: The strength of the force that pulls the node towards
+   *                    its target y position.
+   */
+  targetYPositionStrength() {
     return 0.1;
   }
 
+  /**
+   * @param {number} graph_height: Height of the graph view.
+   * @return {!Array<number>}
+   */
+  allowedYRange(graph_height) {
+    // By default, there is no hard constraint on the y position of a node.
+    return [-Infinity, Infinity];
+  }
+
+  /** @return {number}: The strength of the repulsion force with other nodes. */
+  manyBodyStrength() {
+    return -200;
+  }
+
   /** @return {!Array<number>} */
   linkTargets() {
     return [];
@@ -48,6 +79,7 @@
   constructor(page) {
     super(page.id);
     this.page = page;
+    this.y = kPageNodesTargetY;
   }
 
   /** override */
@@ -56,13 +88,23 @@
   }
 
   /** override */
-  yPosition(height) {
-    return 30;
+  targetYPosition(graph_height) {
+    return kPageNodesTargetY;
   }
 
   /** @override */
-  yStrength() {
-    return 1;
+  targetYPositionStrength() {
+    return 10;
+  }
+
+  /** override */
+  allowedYRange(graph_height) {
+    return [0, kPageNodesYRange];
+  }
+
+  /** override */
+  manyBodyStrength() {
+    return -600;
   }
 
   /** override */
@@ -84,6 +126,16 @@
   }
 
   /** override */
+  targetYPosition(graph_height) {
+    return kFrameNodesTargetY;
+  }
+
+  /** override */
+  allowedYRange(graph_height) {
+    return [kFrameNodesTopMargin, graph_height - kFrameNodesBottomMargin];
+  }
+
+  /** override */
   linkTargets() {
     return [this.frame.parentFrameId, this.frame.processId];
   }
@@ -98,18 +150,28 @@
   }
 
   /** override */
-  yPosition(height) {
-    return height - 30;
-  }
-
-  /** @return {number} */
-  yStrength() {
-    return 1;
+  get title() {
+    return `PID: ${this.process.pid.pid}`;
   }
 
   /** override */
-  get title() {
-    return `PID: ${this.process.pid.pid}`;
+  targetYPosition(graph_height) {
+    return graph_height - (kProcessNodesYRange / 2);
+  }
+
+  /** @return {number} */
+  targetYPositionStrength() {
+    return 10;
+  }
+
+  /** override */
+  allowedYRange(graph_height) {
+    return [graph_height - kProcessNodesYRange, graph_height];
+  }
+
+  /** override */
+  manyBodyStrength() {
+    return -600;
   }
 }
 
@@ -172,7 +234,13 @@
 
     const linkForce = d3.forceLink().id(d => d.id);
     simulation.force('link', linkForce);
-    simulation.force('charge', d3.forceManyBody());
+
+    // Sets the repulsion force between nodes (positive number is attraction,
+    // negative number is repulsion).
+    simulation.force(
+        'charge',
+        d3.forceManyBody().strength(this.getManyBodyStrength_.bind(this)));
+
     this.simulation_ = simulation;
 
     // Create the <g> elements that host nodes and links.
@@ -249,14 +317,15 @@
 
   /** @private */
   onTick_() {
+    const circles = this.nodeGroup_.selectAll('circle');
+    circles.attr('cx', this.getClampedXPosition_.bind(this))
+        .attr('cy', this.getClampedYPosition_.bind(this));
+
     const lines = this.linkGroup_.selectAll('line');
     lines.attr('x1', d => d.source.x)
         .attr('y1', d => d.source.y)
         .attr('x2', d => d.target.x)
         .attr('y2', d => d.target.y);
-
-    const circles = this.nodeGroup_.selectAll('circle');
-    circles.attr('cx', d => d.x).attr('cy', d => d.y);
   }
 
   /**
@@ -403,16 +472,43 @@
    * @param {!d3.ForceNode} d The node to position.
    * @private
    */
-  getYPosition_(d) {
-    return d.yPosition(this.height_);
+  getTargetYPosition_(d) {
+    return d.targetYPosition(this.height_);
   }
 
   /**
    * @param {!d3.ForceNode} d The node to position.
    * @private
    */
-  getYStrength_(d) {
-    return d.yStrength();
+  getClampedYPosition_(d) {
+    const range = d.allowedYRange(this.height_);
+    d.y = Math.max(range[0], Math.min(d.y, range[1]));
+    return d.y;
+  }
+
+  /**
+   * @param {!d3.ForceNode} d The node to position.
+   * @private
+   */
+  getClampedXPosition_(d) {
+    d.x = Math.max(10, Math.min(d.x, this.width_ - 10));
+    return d.x;
+  }
+
+  /**
+   * @param {!d3.ForceNode} d The node to position.
+   * @private
+   */
+  getTargetYPositionStrength_(d) {
+    return d.targetYPositionStrength();
+  }
+
+  /**
+   * @param {!d3.ForceNode} d The node to position.
+   * @private
+   */
+  getManyBodyStrength_(d) {
+    return d.manyBodyStrength();
   }
 
   /** @private */
@@ -432,8 +528,8 @@
     // Reset both X and Y attractive forces, as they're cached.
     const xForce = d3.forceX().x(this.width_ / 2).strength(0.1);
     const yForce = d3.forceY()
-                       .y(this.getYPosition_.bind(this))
-                       .strength(this.getYStrength_.bind(this));
+                       .y(this.getTargetYPosition_.bind(this))
+                       .strength(this.getTargetYPositionStrength_.bind(this));
     this.simulation_.force('x_pos', xForce);
     this.simulation_.force('y_pos', yForce);
 
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index 639b754..4212b01 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -264,7 +264,15 @@
  * set if a notification is visible.
  * @type {?Object}
  */
-let delayedHideNotification;
+let delayedHideNotification = null;
+
+
+/**
+ * The currently visible notification element. Null if no notification is
+ * present.
+ * @type {?Object}
+ */
+let currNotification = null;
 
 
 /**
@@ -798,9 +806,15 @@
  * @param {!Element} notificationContainer The notification container element.
  */
 function floatUpNotification(notification, notificationContainer) {
-  // Hide any pre-existing notification.
   if (delayedHideNotification) {
-    delayedHideNotification.trigger();
+    // Hide the current notification if it's a different type (i.e. error vs
+    // success). Otherwise, simply clear the notification timeout and reset it
+    // later.
+    if (currNotification === notificationContainer) {
+      delayedHideNotification.clear();
+    } else {
+      delayedHideNotification.trigger();
+    }
     delayedHideNotification = null;
   }
 
@@ -831,6 +845,7 @@
     // case, we do not want to re-show the promo yet.
     floatDownNotification(notification, notificationContainer, !executedEarly);
   }, NOTIFICATION_TIMEOUT);
+  currNotification = notificationContainer;
 }
 
 
@@ -850,6 +865,7 @@
   if (delayedHideNotification) {
     delayedHideNotification.clear();
     delayedHideNotification = null;
+    currNotification = null;
   }
 
   if (showPromo) {
diff --git a/chrome/browser/resources/settings/crostini_page/BUILD.gn b/chrome/browser/resources/settings/crostini_page/BUILD.gn
index bc66368..db0a920 100644
--- a/chrome/browser/resources/settings/crostini_page/BUILD.gn
+++ b/chrome/browser/resources/settings/crostini_page/BUILD.gn
@@ -7,6 +7,7 @@
 js_type_check("closure_compile") {
   deps = [
     ":crostini_browser_proxy",
+    ":crostini_export_import",
     ":crostini_page",
     ":crostini_shared_paths",
     ":crostini_shared_usb_devices",
@@ -20,6 +21,12 @@
   ]
 }
 
+js_library("crostini_export_import") {
+  deps = [
+    ":crostini_browser_proxy",
+  ]
+}
+
 js_library("crostini_page") {
   deps = [
     ":crostini_browser_proxy",
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_export_import.html b/chrome/browser/resources/settings/crostini_page/crostini_export_import.html
new file mode 100644
index 0000000..cc24850
--- /dev/null
+++ b/chrome/browser/resources/settings/crostini_page/crostini_export_import.html
@@ -0,0 +1,28 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="crostini_browser_proxy.html">
+<link rel="import" href="../i18n_setup.html">
+<link rel="import" href="../settings_shared_css.html">
+
+<dom-module id="settings-crostini-export-import">
+  <template>
+    <style include="settings-shared"></style>
+    <div class="list-frame vertical-list">
+      <div id="export" class="list-item">
+        <div class="start secondary">$i18n{crostiniExportLabel}</div>
+        <paper-button on-click="onExportClick_">
+           $i18n{crostiniExport}
+        </paper-button>
+      </div>
+      <div id="import" class="list-item">
+        <div class="start secondary">$i18n{crostiniImportLabel}</div>
+        <paper-button on-click="onImportClick_">
+           $i18n{crostiniImport}
+        </paper-button>
+      </div>
+    </div>
+  </template>
+  <script src="crostini_export_import.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_export_import.js b/chrome/browser/resources/settings/crostini_page/crostini_export_import.js
new file mode 100644
index 0000000..d1a513bb
--- /dev/null
+++ b/chrome/browser/resources/settings/crostini_page/crostini_export_import.js
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * 'crostini-export-import' is the settings backup and restore subpage for
+ * Crostini.
+ */
+
+Polymer({
+  is: 'settings-crostini-export-import',
+
+  /** @private */
+  onExportClick_: function() {
+    settings.CrostiniBrowserProxyImpl.getInstance().exportCrostiniContainer();
+  },
+
+  /** @private */
+  onImportClick_: function() {
+    settings.CrostiniBrowserProxyImpl.getInstance().importCrostiniContainer();
+  },
+});
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_page.html b/chrome/browser/resources/settings/crostini_page/crostini_page.html
index 895b096c..22908673 100644
--- a/chrome/browser/resources/settings/crostini_page/crostini_page.html
+++ b/chrome/browser/resources/settings/crostini_page/crostini_page.html
@@ -9,9 +9,10 @@
 <link rel="import" href="../settings_page/settings_subpage.html">
 <link rel="import" href="../settings_shared_css.html">
 <link rel="import" href="crostini_browser_proxy.html">
-<link rel="import" href="crostini_subpage.html">
+<link rel="import" href="crostini_export_import.html">
 <link rel="import" href="crostini_shared_paths.html">
 <link rel="import" href="crostini_shared_usb_devices.html">
+<link rel="import" href="crostini_subpage.html">
 
 <dom-module id="settings-crostini-page">
   <template>
@@ -62,6 +63,15 @@
         </settings-subpage>
       </template>
 
+      <template is="dom-if" route-path="/crostini/exportImport">
+        <settings-subpage
+            associated-control="[[$$('#crostini')]]"
+            page-title="$i18n{crostiniExportImportTitle}">
+          <settings-crostini-export-import prefs="{{prefs}}">
+          </settings-crostini-export-import>
+        </settings-subpage>
+      </template>
+
       <template is="dom-if" route-path="/crostini/sharedPaths">
         <settings-subpage
             associated-control="[[$$('#crostini')]]"
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_page.js b/chrome/browser/resources/settings/crostini_page/crostini_page.js
index 9da529cf..3ffc90d0 100644
--- a/chrome/browser/resources/settings/crostini_page/crostini_page.js
+++ b/chrome/browser/resources/settings/crostini_page/crostini_page.js
@@ -31,6 +31,11 @@
               settings.routes.CROSTINI_DETAILS.path,
               '#crostini .subpage-arrow button');
         }
+        if (settings.routes.CROSTINI_EXPORT_IMPORT) {
+          map.set(
+              settings.routes.CROSTINI_EXPORT_IMPORT.path,
+              '#crostini .subpage-arrow button');
+        }
         if (settings.routes.CROSTINI_SHARED_PATHS) {
           map.set(
               settings.routes.CROSTINI_SHARED_PATHS.path,
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_subpage.html b/chrome/browser/resources/settings/crostini_page/crostini_subpage.html
index cbf4e491..0f60be1 100644
--- a/chrome/browser/resources/settings/crostini_page/crostini_subpage.html
+++ b/chrome/browser/resources/settings/crostini_page/crostini_subpage.html
@@ -13,7 +13,7 @@
   <template>
     <style include="settings-shared"></style>
     <div id="crostini-shared-paths" class="settings-box first"
-        actionable on-click="onSharedPathsTap_">
+        on-click="onSharedPathsClick_" actionable>
       <div class="start">$i18n{crostiniSharedPaths}</div>
       <paper-icon-button-light class="subpage-arrow">
         <button aria-label="$i18n{crostiniSharedPaths}"></button>
@@ -21,7 +21,7 @@
     </div>
     <template is="dom-if" if="[[enableCrostiniUsbDeviceSupport_]]">
       <div id="crostini-shared-usb-devices" class="settings-box"
-          actionable on-click="onSharedUsbDevicesTap_">
+          on-click="onSharedUsbDevicesClick_" actionable>
         <div class="start">$i18n{crostiniSharedUsbDevicesLabel}</div>
         <paper-icon-button-light class="subpage-arrow">
           <button aria-label="$i18n{crostiniSharedUsbDevicesLabel}"></button>
@@ -29,26 +29,18 @@
       </div>
     </template>
     <template is="dom-if" if="[[showCrostiniExportImport_]]">
-      <div class="settings-box">$i18n{crostiniExportImportTitle}</div>
-      <div class="list-frame vertical-list">
-        <div id="export" class="list-item">
-          <div class="start secondary">$i18n{crostiniExportLabel}</div>
-          <paper-button on-click="onExportClick_">
-             $i18n{crostiniExport}
-          </paper-button>
-        </div>
-        <div id="import" class="list-item">
-          <div class="start secondary">$i18n{crostiniImportLabel}</div>
-          <paper-button on-click="onImportClick_">
-             $i18n{crostiniImport}
-          </paper-button>
-        </div>
+      <div id="crostini-export-import" class="settings-box"
+          on-click="onExportImportClick_" actionable>
+        <div class="start">$i18n{crostiniExportImportTitle}</div>
+        <paper-icon-button-light class="subpage-arrow">
+          <button aria-label="$i18n{crostiniExportImportTitle}"></button>
+        </paper-icon-button-light>
       </div>
     </template>
     <template is="dom-if" if="[[!hideCrostiniUninstall_]]">
       <div id="remove" class="settings-box">
         <div class="start">$i18n{crostiniRemove}</div>
-        <paper-button on-click="onRemoveTap_">
+        <paper-button on-click="onRemoveClick_">
            $i18n{crostiniRemoveButton}
         </paper-button>
       </div>
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_subpage.js b/chrome/browser/resources/settings/crostini_page/crostini_subpage.js
index 702a290..736b8a8 100644
--- a/chrome/browser/resources/settings/crostini_page/crostini_subpage.js
+++ b/chrome/browser/resources/settings/crostini_page/crostini_subpage.js
@@ -69,32 +69,26 @@
     }
   },
 
+  /** @private */
+  onExportImportClick_: function() {
+    settings.navigateTo(settings.routes.CROSTINI_EXPORT_IMPORT);
+  },
+
   /**
    * Shows a confirmation dialog when removing crostini.
-   * @param {!Event} event
    * @private
    */
-  onRemoveTap_: function(event) {
+  onRemoveClick_: function() {
     settings.CrostiniBrowserProxyImpl.getInstance().requestRemoveCrostini();
   },
 
   /** @private */
-  onSharedPathsTap_: function(event) {
+  onSharedPathsClick_: function() {
     settings.navigateTo(settings.routes.CROSTINI_SHARED_PATHS);
   },
 
   /** @private */
-  onExportClick_: function(event) {
-    settings.CrostiniBrowserProxyImpl.getInstance().exportCrostiniContainer();
-  },
-
-  /** @private */
-  onImportClick_: function(event) {
-    settings.CrostiniBrowserProxyImpl.getInstance().importCrostiniContainer();
-  },
-
-  /** @private */
-  onSharedUsbDevicesTap_: function(event) {
+  onSharedUsbDevicesClick_: function() {
     settings.navigateTo(settings.routes.CROSTINI_SHARED_USB_DEVICES);
   },
 });
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.js b/chrome/browser/resources/settings/internet_page/internet_page.js
index ddf0927..acb70c0 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -326,6 +326,7 @@
    * @private
    */
   showConfig_: function(configAndConnect, type, guid, name) {
+    assert(type != CrOnc.Type.CELLULAR && type != CrOnc.Type.TETHER);
     const configDialog =
         /** @type {!InternetConfigElement} */ (this.$.configDialog);
     configDialog.type =
@@ -611,11 +612,12 @@
   onNetworkConnect_: function(event) {
     const properties = event.detail.networkProperties;
     const name = CrOnc.getNetworkName(properties);
+    const networkType = properties.Type;
     if (!event.detail.bypassConnectionDialog &&
         CrOnc.shouldShowTetherDialogBeforeConnection(properties)) {
       const params = new URLSearchParams;
       params.append('guid', properties.GUID);
-      params.append('type', properties.Type);
+      params.append('type', networkType);
       params.append('name', name);
       params.append('showConfigure', true.toString());
 
@@ -623,9 +625,10 @@
       return;
     }
 
-    if (properties.Connectable === false || properties.ErrorState) {
+    if (!CrOnc.isMobileNetwork(properties) &&
+        (properties.Connectable === false || properties.ErrorState)) {
       this.showConfig_(
-          true /* configAndConnect */, properties.Type, properties.GUID, name);
+          true /* configAndConnect */, networkType, properties.GUID, name);
       return;
     }
 
@@ -640,11 +643,10 @@
             'networkingPrivate.startConnect error: ' + message +
             ' For: ' + properties.GUID);
 
-        // There is no configuration flow for Instant Tethering networks.
-        if (properties.Type != CrOnc.Type.TETHER) {
+        // There is no configuration flow for Mobile Networks.
+        if (!CrOnc.isMobileNetwork(properties)) {
           this.showConfig_(
-              true /* configAndConnect */, properties.Type, properties.GUID,
-              name);
+              true /* configAndConnect */, networkType, properties.GUID, name);
         }
       }
     });
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 368dc1f01..90a2745 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -17,6 +17,7 @@
  *   ANDROID_APPS_DETAILS: (undefined|!settings.Route),
  *   CROSTINI: (undefined|!settings.Route),
  *   CROSTINI_DETAILS: (undefined|!settings.Route),
+ *   CROSTINI_EXPORT_IMPORT: (undefined|!settings.Route),
  *   CROSTINI_SHARED_PATHS: (undefined|!settings.Route),
  *   CROSTINI_SHARED_USB_DEVICES: (undefined|!settings.Route),
  *   APPEARANCE: (undefined|!settings.Route),
@@ -278,6 +279,8 @@
         loadTimeData.getBoolean('showCrostini')) {
       r.CROSTINI = r.BASIC.createSection('/crostini', 'crostini');
       r.CROSTINI_DETAILS = r.CROSTINI.createChild('/crostini/details');
+      r.CROSTINI_EXPORT_IMPORT =
+          r.CROSTINI.createChild('/crostini/exportImport');
       r.CROSTINI_SHARED_PATHS = r.CROSTINI.createChild('/crostini/sharedPaths');
       r.CROSTINI_SHARED_USB_DEVICES =
           r.CROSTINI.createChild('/crostini/sharedUsbDevices');
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 91b9ab3b..b2b4234 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -1255,6 +1255,12 @@
         <structure name="IDR_SETTINGS_CROSTINI_SUBPAGE_JS"
                    file="crostini_page/crostini_subpage.js"
                    type="chrome_html" />
+        <structure name="IDR_SETTINGS_CROSTINI_EXPORT_IMPORT_HTML"
+                   file="crostini_page/crostini_export_import.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_CROSTINI_EXPORT_IMPORT_JS"
+                   file="crostini_page/crostini_export_import.js"
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_CROSTINI_SHARED_PATHS_HTML"
                    file="crostini_page/crostini_shared_paths.html"
                    type="chrome_html" />
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_util.cc b/chrome/browser/safe_browsing/download_protection/download_protection_util.cc
index f289d55..014cce78 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_util.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_util.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
 
+#include "base/hash/sha1.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "net/cert/x509_util.h"
 
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_handler_util.cc b/chrome/browser/safe_browsing/incident_reporting/incident_handler_util.cc
index fe5605e..28ff4e5 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_handler_util.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_handler_util.cc
@@ -6,7 +6,7 @@
 
 #include <string>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "third_party/protobuf/src/google/protobuf/message_lite.h"
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index e547533a..00421a26 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -20,13 +20,13 @@
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/hash/sha1.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/field_trial.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/sha1.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/search/ntp_icon_source.cc b/chrome/browser/search/ntp_icon_source.cc
index 7c909bf7..aee2c79 100644
--- a/chrome/browser/search/ntp_icon_source.cc
+++ b/chrome/browser/search/ntp_icon_source.cc
@@ -11,8 +11,8 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/hash/sha1.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/signin/identity_test_environment_profile_adaptor.cc b/chrome/browser/signin/identity_test_environment_profile_adaptor.cc
index 568f4f0f..45875a7 100644
--- a/chrome/browser/signin/identity_test_environment_profile_adaptor.cc
+++ b/chrome/browser/signin/identity_test_environment_profile_adaptor.cc
@@ -85,9 +85,4 @@
 IdentityTestEnvironmentProfileAdaptor::IdentityTestEnvironmentProfileAdaptor(
     Profile* profile)
     : identity_test_env_(
-          profile->GetPrefs(),
-          AccountTrackerServiceFactory::GetForProfile(profile),
-          AccountFetcherServiceFactory::GetForProfile(profile),
-          static_cast<FakeProfileOAuth2TokenService*>(
-              ProfileOAuth2TokenServiceFactory::GetForProfile(profile)),
           IdentityManagerFactory::GetForProfile(profile)) {}
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
index a8886059..79255e4 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
@@ -14,7 +14,7 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
diff --git a/chrome/browser/subresource_filter/test_ruleset_publisher.cc b/chrome/browser/subresource_filter/test_ruleset_publisher.cc
index acfeb97..729d1758 100644
--- a/chrome/browser/subresource_filter/test_ruleset_publisher.cc
+++ b/chrome/browser/subresource_filter/test_ruleset_publisher.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/subresource_filter/test_ruleset_publisher.h"
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/supervised_user/experimental/supervised_user_blacklist.h b/chrome/browser/supervised_user/experimental/supervised_user_blacklist.h
index f0dd2cb..ac6bda0 100644
--- a/chrome/browser/supervised_user/experimental/supervised_user_blacklist.h
+++ b/chrome/browser/supervised_user/experimental/supervised_user_blacklist.h
@@ -12,9 +12,9 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/hash/sha1.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/sha1.h"
 
 namespace base {
 class FilePath;
diff --git a/chrome/browser/supervised_user/supervised_user_site_list.h b/chrome/browser/supervised_user/supervised_user_site_list.h
index b42bc8bf..c055765 100644
--- a/chrome/browser/supervised_user/supervised_user_site_list.h
+++ b/chrome/browser/supervised_user/supervised_user_site_list.h
@@ -16,9 +16,9 @@
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
+#include "base/hash/sha1.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/sha1.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 12b4f50..a67918e2 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -549,8 +549,8 @@
 #endif  // !defined(OS_ANDROID)
     case syncer::HISTORY_DELETE_DIRECTIVES: {
       history::HistoryService* history = GetHistoryService();
-      return history ? history->AsWeakPtr()
-                     : base::WeakPtr<history::HistoryService>();
+      return history ? history->GetDeleteDirectivesSyncableService()
+                     : base::WeakPtr<syncer::SyncableService>();
     }
 #if BUILDFLAG(ENABLE_SPELLCHECK)
     case syncer::DICTIONARY:
diff --git a/chrome/browser/sync/test/integration/two_client_passwords_sync_test.cc b/chrome/browser/sync/test/integration/two_client_passwords_sync_test.cc
index 5787e6e4..5a5bbee 100644
--- a/chrome/browser/sync/test/integration/two_client_passwords_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_passwords_sync_test.cc
@@ -8,7 +8,7 @@
 #include <tuple>
 
 #include "base/guid.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/rand_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h b/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h
index fedf07b..248f10d 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <functional>
 #include <map>
 #include <set>
 #include <string>
@@ -15,7 +16,7 @@
 #include <unordered_set>
 #include <vector>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index_interface.h"
 #include "chrome/browser/sync_file_system/drive_backend/tracker_id_set.h"
diff --git a/chrome/browser/task_manager/sampling/task_manager_io_thread_helper.h b/chrome/browser/task_manager/sampling/task_manager_io_thread_helper.h
index 55ba378..b2b2dc0b 100644
--- a/chrome/browser/task_manager/sampling/task_manager_io_thread_helper.h
+++ b/chrome/browser/task_manager/sampling/task_manager_io_thread_helper.h
@@ -10,7 +10,7 @@
 #include <unordered_map>
 
 #include "base/callback.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 
diff --git a/chrome/browser/themes/theme_service_factory.cc b/chrome/browser/themes/theme_service_factory.cc
index c509ff5..6ea6811 100644
--- a/chrome/browser/themes/theme_service_factory.cc
+++ b/chrome/browser/themes/theme_service_factory.cc
@@ -86,11 +86,6 @@
   registry->RegisterStringPref(prefs::kCurrentThemeID,
                                ThemeService::kDefaultThemeID);
   registry->RegisterIntegerPref(prefs::kAutogeneratedThemeColor, 0);
-
-  registry->RegisterDictionaryPref(prefs::kCurrentThemeImages);
-  registry->RegisterDictionaryPref(prefs::kCurrentThemeColors);
-  registry->RegisterDictionaryPref(prefs::kCurrentThemeTints);
-  registry->RegisterDictionaryPref(prefs::kCurrentThemeDisplayProperties);
 }
 
 content::BrowserContext* ThemeServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index be34a4e..dc713d4 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -606,8 +606,6 @@
       "android/autofill/card_unmask_prompt_view_android.h",
       "android/autofill/credit_card_scanner_view_android.cc",
       "android/autofill/credit_card_scanner_view_android.h",
-      "android/autofill/password_generation_popup_view_android.cc",
-      "android/autofill/password_generation_popup_view_android.h",
       "android/bluetooth_chooser_android.cc",
       "android/bluetooth_chooser_android.h",
       "android/chrome_http_auth_handler.cc",
@@ -693,6 +691,8 @@
       "android/passwords/manual_filling_view_android.h",
       "android/passwords/password_generation_dialog_view_android.cc",
       "android/passwords/password_generation_dialog_view_android.h",
+      "android/passwords/password_generation_popup_view_android.cc",
+      "android/passwords/password_generation_popup_view_android.h",
       "android/simple_message_box_android.cc",
       "android/snackbars/auto_signin_prompt_controller.cc",
       "android/snackbars/auto_signin_prompt_controller.h",
@@ -2468,6 +2468,8 @@
       "views/content_setting_domain_list_view.h",
       "views/cookie_info_view.cc",
       "views/cookie_info_view.h",
+      "views/desktop_capture/desktop_media_list_controller.cc",
+      "views/desktop_capture/desktop_media_list_controller.h",
       "views/desktop_capture/desktop_media_list_view.cc",
       "views/desktop_capture/desktop_media_list_view.h",
       "views/desktop_capture/desktop_media_picker_views.cc",
diff --git a/chrome/browser/ui/android/autofill/OWNERS b/chrome/browser/ui/android/autofill/OWNERS
deleted file mode 100644
index 97a2b6b2..0000000
--- a/chrome/browser/ui/android/autofill/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-per-file password_generation_popup_view_android.*=rouslan@chromium.org
-
-# COMPONENT: UI>Browser>Autofill
diff --git a/chrome/browser/ui/android/autofill/password_generation_popup_view_android.cc b/chrome/browser/ui/android/passwords/password_generation_popup_view_android.cc
similarity index 88%
rename from chrome/browser/ui/android/autofill/password_generation_popup_view_android.cc
rename to chrome/browser/ui/android/passwords/password_generation_popup_view_android.cc
index eb68f01..48b6d6f 100644
--- a/chrome/browser/ui/android/autofill/password_generation_popup_view_android.cc
+++ b/chrome/browser/ui/android/passwords/password_generation_popup_view_android.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/android/autofill/password_generation_popup_view_android.h"
+#include "chrome/browser/ui/android/passwords/password_generation_popup_view_android.h"
 
 #include <jni.h>
 
@@ -25,7 +25,6 @@
     PasswordGenerationPopupController* controller)
     : controller_(controller) {}
 
-
 void PasswordGenerationPopupViewAndroid::Dismissed(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
@@ -54,7 +53,7 @@
   if (view.is_null())
     return;
   JNIEnv* env = base::android::AttachCurrentThread();
-  java_object_.Reset(autofill::Java_PasswordGenerationPopupBridge_create(
+  java_object_.Reset(Java_PasswordGenerationPopupBridge_create(
       env, view, reinterpret_cast<intptr_t>(this),
       view_android->GetWindowAndroid()->GetJavaObject()));
 
@@ -65,7 +64,7 @@
   controller_ = NULL;
   JNIEnv* env = base::android::AttachCurrentThread();
   if (!java_object_.is_null()) {
-    autofill::Java_PasswordGenerationPopupBridge_hide(env, java_object_);
+    Java_PasswordGenerationPopupBridge_hide(env, java_object_);
   } else {
     // Hide() should delete |this| either via Java dismiss or directly.
     delete this;
@@ -90,12 +89,12 @@
   ScopedJavaLocalRef<jstring> password =
       base::android::ConvertUTF16ToJavaString(env, controller_->password());
   ScopedJavaLocalRef<jstring> suggestion =
-      base::android::ConvertUTF16ToJavaString(
-          env, controller_->SuggestedText());
+      base::android::ConvertUTF16ToJavaString(env,
+                                              controller_->SuggestedText());
   ScopedJavaLocalRef<jstring> help =
       base::android::ConvertUTF16ToJavaString(env, controller_->HelpText());
 
-  autofill::Java_PasswordGenerationPopupBridge_show(
+  Java_PasswordGenerationPopupBridge_show(
       env, java_object_, controller_->IsRTL(),
       controller_->state() ==
           PasswordGenerationPopupController::kOfferGeneration,
@@ -105,7 +104,7 @@
 void PasswordGenerationPopupViewAndroid::PasswordSelectionUpdated() {}
 
 bool PasswordGenerationPopupViewAndroid::IsPointInPasswordBounds(
-        const gfx::Point& point) {
+    const gfx::Point& point) {
   NOTREACHED();
   return false;
 }
diff --git a/chrome/browser/ui/android/autofill/password_generation_popup_view_android.h b/chrome/browser/ui/android/passwords/password_generation_popup_view_android.h
similarity index 86%
rename from chrome/browser/ui/android/autofill/password_generation_popup_view_android.h
rename to chrome/browser/ui/android/passwords/password_generation_popup_view_android.h
index 7adf727..79a3bf5 100644
--- a/chrome/browser/ui/android/autofill/password_generation_popup_view_android.h
+++ b/chrome/browser/ui/android/passwords/password_generation_popup_view_android.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_ANDROID_AUTOFILL_PASSWORD_GENERATION_POPUP_VIEW_ANDROID_H_
-#define CHROME_BROWSER_UI_ANDROID_AUTOFILL_PASSWORD_GENERATION_POPUP_VIEW_ANDROID_H_
+#ifndef CHROME_BROWSER_UI_ANDROID_PASSWORDS_PASSWORD_GENERATION_POPUP_VIEW_ANDROID_H_
+#define CHROME_BROWSER_UI_ANDROID_PASSWORDS_PASSWORD_GENERATION_POPUP_VIEW_ANDROID_H_
 
 #include <jni.h>
 
@@ -53,4 +53,4 @@
   DISALLOW_COPY_AND_ASSIGN(PasswordGenerationPopupViewAndroid);
 };
 
-#endif  // CHROME_BROWSER_UI_ANDROID_AUTOFILL_PASSWORD_GENERATION_POPUP_VIEW_ANDROID_H_
+#endif  // CHROME_BROWSER_UI_ANDROID_PASSWORDS_PASSWORD_GENERATION_POPUP_VIEW_ANDROID_H_
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc
index 5601698e..30c4336e 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc
@@ -9,7 +9,7 @@
 
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor_test_util.h"
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc
index 24e093f..a25e351 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/optional.h"
 #include "base/task/post_task.h"
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
index d7a7088..caee110 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
@@ -9,7 +9,7 @@
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor_test_util.h"
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index dd080ef7..4d7a77d 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -275,6 +275,7 @@
   g_browser_process->platform_part()->InitializeDeviceDisablingManager();
 
   media_client_ = std::make_unique<MediaClient>();
+  media_client_->Init();
 
   // Instantiate DisplaySettingsHandler after CrosSettings has been
   // initialized.
diff --git a/chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_metadata_unittest.cc b/chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_metadata_unittest.cc
index 2d521d3..07f6eb3 100644
--- a/chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_metadata_unittest.cc
+++ b/chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_metadata_unittest.cc
@@ -10,8 +10,8 @@
 #include "ash/components/shortcut_viewer/keyboard_shortcut_item.h"
 #include "ash/components/shortcut_viewer/keyboard_shortcut_viewer_metadata.h"
 #include "ash/public/cpp/accelerators.h"
+#include "base/hash/md5.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/ui/views/accelerator_table.h"
diff --git a/chrome/browser/ui/ash/media_client.cc b/chrome/browser/ui/ash/media_client.cc
index 2dcf758..b8629c7 100644
--- a/chrome/browser/ui/ash/media_client.cc
+++ b/chrome/browser/ui/ash/media_client.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/ash/media_client.h"
 
+#include <utility>
+
 #include "ash/public/interfaces/constants.mojom.h"
 #include "base/bind.h"
 #include "base/location.h"
@@ -24,6 +26,7 @@
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/browser/media_session.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/service_manager_connection.h"
@@ -134,17 +137,9 @@
 
 }  // namespace
 
-MediaClient::MediaClient() : binding_(this), weak_ptr_factory_(this) {
+MediaClient::MediaClient() {
   MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this);
-
-  service_manager::Connector* connector =
-      content::ServiceManagerConnection::GetForProcess()->GetConnector();
-  connector->BindInterface(ash::mojom::kServiceName, &media_controller_);
-
-  // Register this object as the client interface implementation.
-  ash::mojom::MediaClientAssociatedPtrInfo ptr_info;
-  binding_.Bind(mojo::MakeRequest(&ptr_info));
-  media_controller_->SetClient(std::move(ptr_info));
+  BrowserList::GetInstance()->AddObserver(this);
 
   DCHECK(!g_media_client_);
   g_media_client_ = this;
@@ -152,7 +147,9 @@
 
 MediaClient::~MediaClient() {
   g_media_client_ = nullptr;
+
   MediaCaptureDevicesDispatcher::GetInstance()->RemoveObserver(this);
+  BrowserList::GetInstance()->RemoveObserver(this);
 }
 
 // static
@@ -160,56 +157,32 @@
   return g_media_client_;
 }
 
+void MediaClient::Init() {
+  DCHECK(!media_controller_.is_bound());
+
+  service_manager::Connector* connector =
+      content::ServiceManagerConnection::GetForProcess()->GetConnector();
+  connector->BindInterface(ash::mojom::kServiceName, &media_controller_);
+  BindAndSetClient();
+}
+
+void MediaClient::InitForTesting(ash::mojom::MediaControllerPtr controller) {
+  DCHECK(!media_controller_.is_bound());
+
+  media_controller_ = std::move(controller);
+  BindAndSetClient();
+}
+
 void MediaClient::HandleMediaNextTrack() {
-  extensions::MediaPlayerAPI::Get(ProfileManager::GetActiveUserProfile())
-      ->media_player_event_router()
-      ->NotifyNextTrack();
+  HandleMediaAction(ui::VKEY_MEDIA_NEXT_TRACK);
 }
 
 void MediaClient::HandleMediaPlayPause() {
-  // If there is a video playing in Picture-in-Picture, toggle
-  // Picture-in-Picture tab's media session play pause.
-  content::WebContents* pip_web_contents =
-      PictureInPictureWindowManager::GetInstance()->GetWebContents();
-  if (pip_web_contents) {
-    ToggleMediaSessionPlayPause(content::MediaSession::Get(pip_web_contents));
-    return;
-  }
-  // If there is an active browser, handle active tab's media session play
-  // pause.
-  Browser* browser = chrome::FindBrowserWithActiveWindow();
-  if (browser) {
-    ToggleMediaSessionPlayPause(content::MediaSession::Get(
-        browser->tab_strip_model()->GetActiveWebContents()));
-    return;
-  }
-  // Dispatch this event.
-  extensions::MediaPlayerAPI::Get(ProfileManager::GetActiveUserProfile())
-      ->media_player_event_router()
-      ->NotifyTogglePlayState();
-}
-
-void MediaClient::ToggleMediaSessionPlayPause(
-    content::MediaSession* media_session) {
-  media_session->GetMediaSessionInfo(base::BindOnce(
-      [](content::MediaSession* media_session,
-         media_session::mojom::MediaSessionInfoPtr session_info) {
-        if (!session_info->is_controllable)
-          return;
-
-        if (session_info->playback_state ==
-            media_session::mojom::MediaPlaybackState::kPlaying)
-          media_session->Suspend(content::MediaSession::SuspendType::kUI);
-        else
-          media_session->Resume(content::MediaSession::SuspendType::kUI);
-      },
-      media_session));
+  HandleMediaAction(ui::VKEY_MEDIA_PLAY_PAUSE);
 }
 
 void MediaClient::HandleMediaPrevTrack() {
-  extensions::MediaPlayerAPI::Get(ProfileManager::GetActiveUserProfile())
-      ->media_player_event_router()
-      ->NotifyPrevTrack();
+  HandleMediaAction(ui::VKEY_MEDIA_PREV_TRACK);
 }
 
 void MediaClient::RequestCaptureState() {
@@ -241,3 +214,98 @@
       FROM_HERE, base::BindOnce(&MediaClient::RequestCaptureState,
                                 weak_ptr_factory_.GetWeakPtr()));
 }
+
+void MediaClient::OnBrowserSetLastActive(Browser* browser) {
+  active_context_ = browser ? browser->profile() : nullptr;
+
+  UpdateForceMediaClientKeyHandling();
+}
+
+void MediaClient::EnableCustomMediaKeyHandler(
+    content::BrowserContext* context,
+    ui::MediaKeysListener::Delegate* delegate) {
+  auto it = media_key_delegates_.find(context);
+
+  DCHECK(!base::ContainsKey(media_key_delegates_, context) ||
+         it->second == delegate);
+
+  media_key_delegates_.emplace(context, delegate);
+
+  UpdateForceMediaClientKeyHandling();
+}
+
+void MediaClient::DisableCustomMediaKeyHandler(
+    content::BrowserContext* context,
+    ui::MediaKeysListener::Delegate* delegate) {
+  if (!base::ContainsKey(media_key_delegates_, context))
+    return;
+
+  auto it = media_key_delegates_.find(context);
+  DCHECK_EQ(it->second, delegate);
+
+  media_key_delegates_.erase(it);
+
+  UpdateForceMediaClientKeyHandling();
+}
+
+void MediaClient::FlushForTesting() {
+  media_controller_.FlushForTesting();
+}
+
+void MediaClient::BindAndSetClient() {
+  ash::mojom::MediaClientAssociatedPtrInfo ptr_info;
+  binding_.Bind(mojo::MakeRequest(&ptr_info));
+  media_controller_->SetClient(std::move(ptr_info));
+}
+
+void MediaClient::UpdateForceMediaClientKeyHandling() {
+  bool enabled = GetCurrentMediaKeyDelegate() != nullptr;
+
+  if (enabled == is_forcing_media_client_key_handling_)
+    return;
+
+  is_forcing_media_client_key_handling_ = enabled;
+
+  media_controller_->SetForceMediaClientKeyHandling(enabled);
+}
+
+ui::MediaKeysListener::Delegate* MediaClient::GetCurrentMediaKeyDelegate()
+    const {
+  auto it = media_key_delegates_.find(active_context_);
+  if (it != media_key_delegates_.end())
+    return it->second;
+
+  return nullptr;
+}
+
+void MediaClient::HandleMediaAction(ui::KeyboardCode keycode) {
+  if (ui::MediaKeysListener::Delegate* custom = GetCurrentMediaKeyDelegate()) {
+    custom->OnMediaKeysAccelerator(ui::Accelerator(keycode, ui::EF_NONE));
+    return;
+  }
+
+  // This API is used by Chrome apps so we should use the logged in user here.
+  extensions::MediaPlayerAPI* player_api =
+      extensions::MediaPlayerAPI::Get(ProfileManager::GetActiveUserProfile());
+  if (!player_api)
+    return;
+
+  extensions::MediaPlayerEventRouter* router =
+      player_api->media_player_event_router();
+  if (!router)
+    return;
+
+  switch (keycode) {
+    case ui::VKEY_MEDIA_NEXT_TRACK:
+      router->NotifyNextTrack();
+      break;
+    case ui::VKEY_MEDIA_PREV_TRACK:
+      router->NotifyPrevTrack();
+      break;
+    case ui::VKEY_MEDIA_PLAY_PAUSE:
+      router->NotifyTogglePlayState();
+      break;
+    default:
+      break;
+  }
+}
diff --git a/chrome/browser/ui/ash/media_client.h b/chrome/browser/ui/ash/media_client.h
index a67a036..397d9018 100644
--- a/chrome/browser/ui/ash/media_client.h
+++ b/chrome/browser/ui/ash/media_client.h
@@ -6,18 +6,27 @@
 #define CHROME_BROWSER_UI_ASH_MEDIA_CLIENT_H_
 
 #include "ash/public/interfaces/media.mojom.h"
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
-#include "content/public/browser/media_session.h"
+#include "chrome/browser/ui/browser_list_observer.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
+#include "ui/base/accelerators/media_keys_listener.h"
 
 class MediaClient : public ash::mojom::MediaClient,
+                    public BrowserListObserver,
                     MediaCaptureDevicesDispatcher::Observer {
  public:
   MediaClient();
   ~MediaClient() override;
 
+  // Initializes and connects to ash.
+  void Init();
+
+  // Tests can provide a mock mojo interface for the ash controller.
+  void InitForTesting(ash::mojom::MediaControllerPtr controller);
+
   // Returns a pointer to the singleton MediaClient, or nullptr if none exists.
   static MediaClient* Get();
 
@@ -34,19 +43,57 @@
                        blink::MediaStreamType stream_type,
                        const content::MediaRequestState state) override;
 
+  // BrowserListObserver:
+  void OnBrowserSetLastActive(Browser* browser) override;
+
+  // Enables/disables custom media key handling when |context| is the active
+  // browser. Media keys will be forwarded to |delegate|.
+  void EnableCustomMediaKeyHandler(content::BrowserContext* context,
+                                   ui::MediaKeysListener::Delegate* delegate);
+  void DisableCustomMediaKeyHandler(content::BrowserContext* context,
+                                    ui::MediaKeysListener::Delegate* delegate);
+
+  void FlushForTesting();
+
  private:
+  // Binds this object to its mojo interface and sets it as the ash client.
+  void BindAndSetClient();
+
+  // Sets |is_forcing_media_client_key_handling_| to true if
+  // |GetCurrentMediaKeyDelegate| returns a delegate. This will also mirror the
+  // value of |is_forcing_media_client_key_handling_| to Ash.
+  void UpdateForceMediaClientKeyHandling();
+
+  // Gets the current media key delegate that we should forward media keys to.
+  // This will be the delegate that is associated with the current active
+  // browser. If there is no delegate registered or there is no active browser
+  // then this will return |nullptr|.
+  ui::MediaKeysListener::Delegate* GetCurrentMediaKeyDelegate() const;
+
   // Returns the media capture state for the current user at
   // |user_index|. (Note that this isn't stable, see implementation comment on
   // RequestCaptureState()).
   ash::mojom::MediaCaptureState GetMediaCaptureStateByIndex(int user_index);
 
-  void ToggleMediaSessionPlayPause(content::MediaSession* media_session);
+  // Handles the media key action for the key with |code|. If there is a
+  // |GetCurrentMediaKeyDelegate| then the action will be forwarded to the
+  // delegate. Otherwise, we will forward the action to the extensions API.
+  void HandleMediaAction(ui::KeyboardCode code);
 
   ash::mojom::MediaControllerPtr media_controller_;
 
-  mojo::AssociatedBinding<ash::mojom::MediaClient> binding_;
+  base::flat_map<content::BrowserContext*, ui::MediaKeysListener::Delegate*>
+      media_key_delegates_;
 
-  base::WeakPtrFactory<MediaClient> weak_ptr_factory_;
+  // If true then ash will always forward media keys to |this| instead of trying
+  // to handle them first.
+  bool is_forcing_media_client_key_handling_ = false;
+
+  content::BrowserContext* active_context_ = nullptr;
+
+  mojo::AssociatedBinding<ash::mojom::MediaClient> binding_{this};
+
+  base::WeakPtrFactory<MediaClient> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MediaClient);
 };
diff --git a/chrome/browser/ui/ash/media_client_unittest.cc b/chrome/browser/ui/ash/media_client_unittest.cc
new file mode 100644
index 0000000..ef93489
--- /dev/null
+++ b/chrome/browser/ui/ash/media_client_unittest.cc
@@ -0,0 +1,263 @@
+// 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/ash/media_client.h"
+
+#include <memory>
+
+#include "ash/public/interfaces/media.mojom.h"
+#include "base/optional.h"
+#include "chrome/browser/chromeos/extensions/media_player_api.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "components/account_id/account_id.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "ui/base/accelerators/media_keys_listener.h"
+
+namespace {
+
+class TestMediaController : public ash::mojom::MediaController {
+ public:
+  TestMediaController() = default;
+  ~TestMediaController() override = default;
+
+  ash::mojom::MediaControllerPtr CreateMediaControllerPtr() {
+    ash::mojom::MediaControllerPtr ptr;
+    binding_.Bind(mojo::MakeRequest(&ptr));
+    return ptr;
+  }
+
+  // mojom::MediaController:
+  void SetClient(ash::mojom::MediaClientAssociatedPtrInfo client) override {}
+  void SetForceMediaClientKeyHandling(bool enabled) override {
+    force_media_client_key_handling_ = enabled;
+  }
+  void NotifyCaptureState(
+      const base::flat_map<AccountId, ash::mojom::MediaCaptureState>&
+          capture_states) override {}
+
+  bool force_media_client_key_handling() const {
+    return force_media_client_key_handling_;
+  }
+
+ private:
+  bool force_media_client_key_handling_ = false;
+
+  mojo::Binding<ash::mojom::MediaController> binding_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(TestMediaController);
+};
+
+class TestMediaKeysDelegate : public ui::MediaKeysListener::Delegate {
+ public:
+  TestMediaKeysDelegate() = default;
+  ~TestMediaKeysDelegate() override = default;
+
+  void OnMediaKeysAccelerator(const ui::Accelerator& accelerator) override {
+    last_media_key_ = accelerator;
+  }
+
+  base::Optional<ui::Accelerator> ConsumeLastMediaKey() {
+    base::Optional<ui::Accelerator> key = last_media_key_;
+    last_media_key_.reset();
+    return key;
+  }
+
+ private:
+  base::Optional<ui::Accelerator> last_media_key_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMediaKeysDelegate);
+};
+
+}  // namespace
+
+class MediaClientTest : public BrowserWithTestWindowTest {
+ public:
+  MediaClientTest() {}
+  ~MediaClientTest() override = default;
+
+  void SetUp() override {
+    BrowserWithTestWindowTest::SetUp();
+
+    alt_window_.reset(CreateBrowserWindow());
+    alt_browser_.reset(CreateBrowser(alt_profile(), Browser::TYPE_TABBED, false,
+                                     alt_window_.get()));
+
+    extensions::MediaPlayerAPI::Get(profile());
+
+    test_delegate_ = std::make_unique<TestMediaKeysDelegate>();
+    test_media_controller_ = std::make_unique<TestMediaController>();
+
+    media_client_ = std::make_unique<MediaClient>();
+    media_client_->InitForTesting(
+        test_media_controller_->CreateMediaControllerPtr());
+
+    BrowserList::SetLastActive(browser());
+    client()->FlushForTesting();
+
+    ASSERT_FALSE(test_media_controller_->force_media_client_key_handling());
+    ASSERT_EQ(base::nullopt, delegate()->ConsumeLastMediaKey());
+  }
+
+  void TearDown() override {
+    media_client_.reset();
+    test_media_controller_.reset();
+    test_delegate_.reset();
+
+    alt_browser_->tab_strip_model()->CloseAllTabs();
+    alt_browser_.reset();
+    alt_window_.reset();
+
+    BrowserWithTestWindowTest::TearDown();
+  }
+
+  MediaClient* client() { return media_client_.get(); }
+
+  TestMediaController* controller() { return test_media_controller_.get(); }
+
+  Profile* alt_profile() { return profile()->GetOffTheRecordProfile(); }
+
+  Browser* alt_browser() { return alt_browser_.get(); }
+
+  TestMediaKeysDelegate* delegate() { return test_delegate_.get(); }
+
+ private:
+  std::unique_ptr<TestMediaKeysDelegate> test_delegate_;
+  std::unique_ptr<TestMediaController> test_media_controller_;
+  std::unique_ptr<MediaClient> media_client_;
+
+  std::unique_ptr<Browser> alt_browser_;
+  std::unique_ptr<BrowserWindow> alt_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaClientTest);
+};
+
+TEST_F(MediaClientTest, HandleMediaPlayPause) {
+  const ui::Accelerator test_accelerator(ui::VKEY_MEDIA_PLAY_PAUSE,
+                                         ui::EF_NONE);
+
+  // Enable custom media key handling for the current browser. Ensure that the
+  // client set the override on the controller.
+  client()->EnableCustomMediaKeyHandler(profile(), delegate());
+  client()->FlushForTesting();
+  EXPECT_TRUE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check that the delegate received it.
+  client()->HandleMediaPlayPause();
+  EXPECT_EQ(test_accelerator, delegate()->ConsumeLastMediaKey());
+
+  // Change the active browser and ensure the override was disabled.
+  BrowserList::SetLastActive(alt_browser());
+  client()->FlushForTesting();
+  EXPECT_FALSE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check that the delegate did not receive it.
+  client()->HandleMediaPlayPause();
+  EXPECT_EQ(base::nullopt, delegate()->ConsumeLastMediaKey());
+
+  // Change the active browser back and ensure the override was enabled.
+  BrowserList::SetLastActive(browser());
+  client()->FlushForTesting();
+  EXPECT_TRUE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check the delegate received it.
+  client()->HandleMediaPlayPause();
+  EXPECT_EQ(test_accelerator, delegate()->ConsumeLastMediaKey());
+
+  // Disable custom media key handling for the current browser and ensure the
+  // override was disabled.
+  client()->DisableCustomMediaKeyHandler(profile(), delegate());
+  client()->FlushForTesting();
+  EXPECT_FALSE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check the delegate did not receive it.
+  client()->HandleMediaPlayPause();
+  EXPECT_EQ(base::nullopt, delegate()->ConsumeLastMediaKey());
+}
+
+TEST_F(MediaClientTest, HandleMediaNextTrack) {
+  const ui::Accelerator test_accelerator(ui::VKEY_MEDIA_NEXT_TRACK,
+                                         ui::EF_NONE);
+
+  // Enable custom media key handling for the current browser. Ensure that the
+  // client set the override on the controller.
+  client()->EnableCustomMediaKeyHandler(profile(), delegate());
+  client()->FlushForTesting();
+  EXPECT_TRUE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check that the delegate received it.
+  client()->HandleMediaNextTrack();
+  EXPECT_EQ(test_accelerator, delegate()->ConsumeLastMediaKey());
+
+  // Change the active browser and ensure the override was disabled.
+  BrowserList::SetLastActive(alt_browser());
+  client()->FlushForTesting();
+  EXPECT_FALSE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check that the delegate did not receive it.
+  client()->HandleMediaNextTrack();
+  EXPECT_EQ(base::nullopt, delegate()->ConsumeLastMediaKey());
+
+  // Change the active browser back and ensure the override was enabled.
+  BrowserList::SetLastActive(browser());
+  client()->FlushForTesting();
+  EXPECT_TRUE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check the delegate received it.
+  client()->HandleMediaNextTrack();
+  EXPECT_EQ(test_accelerator, delegate()->ConsumeLastMediaKey());
+
+  // Disable custom media key handling for the current browser and ensure the
+  // override was disabled.
+  client()->DisableCustomMediaKeyHandler(profile(), delegate());
+  client()->FlushForTesting();
+  EXPECT_FALSE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check the delegate did not receive it.
+  client()->HandleMediaNextTrack();
+  EXPECT_EQ(base::nullopt, delegate()->ConsumeLastMediaKey());
+}
+
+TEST_F(MediaClientTest, HandleMediaPrevTrack) {
+  const ui::Accelerator test_accelerator(ui::VKEY_MEDIA_PREV_TRACK,
+                                         ui::EF_NONE);
+
+  // Enable custom media key handling for the current browser. Ensure that the
+  // client set the override on the controller.
+  client()->EnableCustomMediaKeyHandler(profile(), delegate());
+  client()->FlushForTesting();
+  EXPECT_TRUE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check that the delegate received it.
+  client()->HandleMediaPrevTrack();
+  EXPECT_EQ(test_accelerator, delegate()->ConsumeLastMediaKey());
+
+  // Change the active browser and ensure the override was disabled.
+  BrowserList::SetLastActive(alt_browser());
+  client()->FlushForTesting();
+  EXPECT_FALSE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check that the delegate did not receive it.
+  client()->HandleMediaPrevTrack();
+  EXPECT_EQ(base::nullopt, delegate()->ConsumeLastMediaKey());
+
+  // Change the active browser back and ensure the override was enabled.
+  BrowserList::SetLastActive(browser());
+  client()->FlushForTesting();
+  EXPECT_TRUE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check the delegate received it.
+  client()->HandleMediaPrevTrack();
+  EXPECT_EQ(test_accelerator, delegate()->ConsumeLastMediaKey());
+
+  // Disable custom media key handling for the current browser and ensure the
+  // override was disabled.
+  client()->DisableCustomMediaKeyHandler(profile(), delegate());
+  client()->FlushForTesting();
+  EXPECT_FALSE(controller()->force_media_client_key_handling());
+
+  // Simulate the media key and check the delegate did not receive it.
+  client()->HandleMediaPrevTrack();
+  EXPECT_EQ(base::nullopt, delegate()->ConsumeLastMediaKey());
+}
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.cc b/chrome/browser/ui/ash/wallpaper_controller_client.cc
index c57544c..9f1280b 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client.cc
@@ -6,8 +6,8 @@
 
 #include "ash/public/interfaces/constants.mojom.h"
 #include "base/bind.h"
+#include "base/hash/sha1.h"
 #include "base/path_service.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 7942511e..d628d52 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -177,6 +177,9 @@
   // frames may need to refresh their title bar.
   virtual void UpdateTitleBar() = 0;
 
+  // Inform the frame that its color has changed.
+  virtual void UpdateFrameColor() = 0;
+
   // Invoked when the state of the bookmark bar changes. This is only invoked if
   // the state changes for the current tab, it is not sent when switching tabs.
   virtual void BookmarkBarStateChanged(
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
index da86d61..bead9066 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -146,7 +146,8 @@
 }
 
 HostedAppBrowserController::HostedAppBrowserController(Browser* browser)
-    : browser_(browser),
+    : content::WebContentsObserver(nullptr),
+      browser_(browser),
       extension_id_(web_app::GetAppIdFromApplicationName(browser->app_name())),
       // If a bookmark app has a URL handler, then it is a PWA.
       // TODO(https://crbug.com/774918): Replace once there is a more explicit
@@ -266,18 +267,27 @@
 }
 
 base::Optional<SkColor> HostedAppBrowserController::GetThemeColor() const {
-  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_->profile());
-  const Extension* extension =
-      registry->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
-  if (extension) {
-    const base::Optional<SkColor> color =
-        AppThemeColorInfo::GetThemeColor(extension);
-    if (color) {
-      // The frame/tabstrip code expects an opaque color.
-      return SkColorSetA(*color, SK_AlphaOPAQUE);
-    }
+  base::Optional<SkColor> result;
+
+  const Extension* extension = GetExtension();
+  if (extension)
+    result = AppThemeColorInfo::GetThemeColor(extension);
+
+  // HTML meta theme-color tag overrides manifest theme_color, see spec:
+  // https://www.w3.org/TR/appmanifest/#theme_color-member
+  content::WebContents* web_contents =
+      browser_->tab_strip_model()->GetActiveWebContents();
+  if (web_contents) {
+    base::Optional<SkColor> color = web_contents->GetThemeColor();
+    if (color)
+      result = color;
   }
-  return base::nullopt;
+
+  if (!result)
+    return base::nullopt;
+
+  // The frame/tabstrip code expects an opaque color.
+  return SkColorSetA(*result, SK_AlphaOPAQUE);
 }
 
 base::string16 HostedAppBrowserController::GetTitle() const {
@@ -356,11 +366,21 @@
   }
 }
 
+void HostedAppBrowserController::DidChangeThemeColor(
+    base::Optional<SkColor> theme_color) {
+  browser_->window()->UpdateFrameColor();
+}
+
 void HostedAppBrowserController::OnTabInserted(content::WebContents* contents) {
+  DCHECK(!web_contents()) << "Hosted app windows are single tabbed only";
   HostedAppBrowserController::SetAppPrefsForWebContents(this, contents);
+  content::WebContentsObserver::Observe(contents);
 }
 
 void HostedAppBrowserController::OnTabRemoved(content::WebContents* contents) {
+  DCHECK_EQ(contents, web_contents());
+  content::WebContentsObserver::Observe(nullptr);
+
   auto* rvh = contents->GetRenderViewHost();
 
   contents->GetMutableRendererPrefs()->can_accept_load_drops = true;
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.h b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
index 49707e14..fb801c5 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.h
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
@@ -12,6 +12,7 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 class Browser;
@@ -33,7 +34,8 @@
 
 // Class to encapsulate logic to control the browser UI for hosted apps.
 class HostedAppBrowserController : public TabStripModelObserver,
-                                   public ExtensionUninstallDialog::Delegate {
+                                   public ExtensionUninstallDialog::Delegate,
+                                   public content::WebContentsObserver {
  public:
   // Returns whether |browser| uses the experimental hosted app experience.
   // Convenience wrapper for checking IsForExperimentalHostedAppBrowser() on
@@ -113,6 +115,9 @@
       const TabStripModelChange& change,
       const TabStripSelectionChange& selection) override;
 
+  // content::WebContentsObserver:
+  void DidChangeThemeColor(base::Optional<SkColor> theme_color) override;
+
  private:
   // Called by OnTabstripModelChanged().
   void OnTabInserted(content::WebContents* contents);
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index e9944576..4776c0f5 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -2730,7 +2730,7 @@
     EXPECT_EQ(web_app::GetAppIdFromApplicationName(app_browser->app_name()),
               app->id());
     EXPECT_EQ(SkColorSetA(*web_app_info.theme_color, SK_AlphaOPAQUE),
-              app_browser->hosted_app_controller()->GetThemeColor().value());
+              app_browser->hosted_app_controller()->GetThemeColor());
   }
   {
     WebApplicationInfo web_app_info;
@@ -2742,8 +2742,8 @@
 
     EXPECT_EQ(web_app::GetAppIdFromApplicationName(app_browser->app_name()),
               app->id());
-    EXPECT_FALSE(
-        app_browser->hosted_app_controller()->GetThemeColor().has_value());
+    EXPECT_EQ(base::nullopt,
+              app_browser->hosted_app_controller()->GetThemeColor());
   }
 }
 
diff --git a/chrome/browser/ui/libgtkui/app_indicator_icon.cc b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
index 3e1aa95..598af116 100644
--- a/chrome/browser/ui/libgtkui/app_indicator_icon.cc
+++ b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/environment.h"
 #include "base/files/file_util.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 9760761..170008c 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -457,6 +457,7 @@
     return nullptr;
   DCHECK(ContainsIndex(index));
 
+  NotifyGroupChange(index, UngroupTab(index), nullptr);
   FixOpeners(index);
 
   // Ask the delegate to save an entry for this tab in the historical tab
@@ -1713,9 +1714,17 @@
   WebContentsData* contents_data = contents_data_[new_index].get();
   contents_data->set_group(new_group);
 
+  NotifyGroupChange(new_index, old_group, new_group);
+}
+
+void TabStripModel::NotifyGroupChange(int index,
+                                      const TabGroupData* old_group,
+                                      const TabGroupData* new_group) {
+  if (old_group == new_group)
+    return;
   TabStripModelChange::Delta delta =
-      TabStripModelChange::CreateGroupChangeDelta(
-          contents_data->web_contents(), new_index, old_group, new_group);
+      TabStripModelChange::CreateGroupChangeDelta(GetWebContentsAt(index),
+                                                  index, old_group, new_group);
   TabStripModelChange change(TabStripModelChange::kGroupChanged, {delta});
   TabStripSelectionChange selection(GetActiveWebContents(), selection_model_);
   for (auto& observer : observers_)
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 3604030..e6235b31 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -587,6 +587,12 @@
   // Notifies any observers that group affiliation has changed for the tab.
   void MoveAndSetGroup(int index, int new_index, const TabGroupData* new_group);
 
+  // Notifies observers that the tab at |index| was moved from |old_group| to
+  // |new_group|.
+  void NotifyGroupChange(int index,
+                         const TabGroupData* old_group,
+                         const TabGroupData* new_group);
+
   // Helper function for MoveAndSetGroup. Removes the tab at |index| from the
   // group that contains it, if any. Also deletes that group, if it now contains
   // no tabs. Returns that group.
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index 18f43b1..c3610d1 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -3255,6 +3255,43 @@
   strip.CloseAllTabs();
 }
 
+TEST_F(TabStripModelTest, CloseTabDeletesGroup) {
+  TestTabStripModelDelegate delegate;
+  TabStripModel strip(&delegate, profile());
+  strip.AppendWebContents(CreateWebContents(), true);
+  strip.AddToNewGroup({0});
+  EXPECT_EQ(strip.ListTabGroups().size(), 1U);
+
+  strip.CloseWebContentsAt(0, TabStripModel::CLOSE_USER_GESTURE);
+
+  EXPECT_EQ(strip.ListTabGroups().size(), 0U);
+}
+
+TEST_F(TabStripModelTest, CloseTabNotifiesObserversOfGroupChange) {
+  TestTabStripModelDelegate delegate;
+  MockTabStripModelObserver observer;
+  TabStripModel strip(&delegate, profile());
+  strip.AddObserver(&observer);
+  strip.AppendWebContents(CreateWebContents(), true);
+  strip.AddToNewGroup({0});
+  const TabGroupData* old_group = strip.GetTabGroupForTab(0);
+  observer.ClearStates();
+
+  strip.CloseWebContentsAt(0, TabStripModel::CLOSE_USER_GESTURE);
+
+  EXPECT_GT(observer.GetStateCount(), 0);
+  int num_group_changed_notifications = 0;
+  for (int i = 0; i < observer.GetStateCount(); i++) {
+    if (observer.GetStateAt(i).action ==
+        MockTabStripModelObserver::GROUP_CHANGED) {
+      observer.StateEquals(
+          i, ExpectedGroupChangeState(strip, 0, old_group, nullptr));
+      num_group_changed_notifications++;
+    }
+  }
+  EXPECT_EQ(num_group_changed_notifications, 1);
+}
+
 // When inserting a WebContents, if a group is not specified, the new tab
 // should be left ungrouped.
 TEST_F(TabStripModelTest, InsertWebContentsAtDoesNotGroupByDefault) {
@@ -3266,12 +3303,12 @@
                                     strip.GetWebContentsAt(1)};
   strip.AddToNewGroup({0, 1});
 
-  strip.InsertWebContentsAt(1, CreateWebContents(), TabStripModel::ADD_NONE);
+  strip.InsertWebContentsAt(2, CreateWebContents(), TabStripModel::ADD_NONE);
 
-  // The newly added tab should not be in the group. The group should be split.
+  // The newly added tab should not be in the group.
   EXPECT_NE(strip.GetTabGroupForTab(0), nullptr);
-  EXPECT_EQ(strip.GetTabGroupForTab(1), nullptr);
-  EXPECT_NE(strip.GetTabGroupForTab(2), nullptr);
+  EXPECT_NE(strip.GetTabGroupForTab(1), nullptr);
+  EXPECT_EQ(strip.GetTabGroupForTab(2), nullptr);
 
   strip.ActivateTabAt(0, {TabStripModel::GestureType::kOther});
   strip.CloseAllTabs();
diff --git a/chrome/browser/ui/test/test_app_window_icon_observer.cc b/chrome/browser/ui/test/test_app_window_icon_observer.cc
index 6a0074f..85541fc 100644
--- a/chrome/browser/ui/test/test_app_window_icon_observer.cc
+++ b/chrome/browser/ui/test/test_app_window_icon_observer.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/test/test_app_window_icon_observer.h"
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/run_loop.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "ui/aura/client/aura_constants.h"
diff --git a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc
index 03288814..d381575 100644
--- a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc
+++ b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc
@@ -85,7 +85,7 @@
     return;
 
   // We will do the capture either now or at some point in the future.
-  constexpr base::TimeDelta kDelayTime = base::TimeDelta::FromMilliseconds(250);
+  constexpr base::TimeDelta kDelayTime = base::TimeDelta::FromMilliseconds(500);
   base::TimeDelta delay;
   if (schedule == CaptureSchedule::kDelayed)
     delay += kDelayTime;
@@ -98,7 +98,7 @@
   // If we would schedule a non-immediate capture too close to an existing
   // capture, push it out or discard it altogether.
   constexpr base::TimeDelta kMinTimeBetweenCaptures =
-      base::TimeDelta::FromMilliseconds(1000);
+      base::TimeDelta::FromMilliseconds(2000);
   if (schedule != CaptureSchedule::kImmediate &&
       delay - until_scheduled < kMinTimeBetweenCaptures) {
     if (until_scheduled > delay)
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller.cc b/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
index 96cdd30a..a455f0afc 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
@@ -6,13 +6,18 @@
 
 #include "base/logging.h"
 #include "build/build_config.h"
+#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/defaults.h"
+#include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/global_error/global_error_service.h"
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/common/channel_info.h"
 #include "components/version_info/channel.h"
+#include "ui/base/theme_provider.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/native_theme/native_theme.h"
 
 namespace {
 
@@ -66,6 +71,31 @@
          channel == version_info::Channel::CANARY;
 }
 
+// Returns the icon color based on |severity|. |promo_highlight_color|, if
+// specified, overrides the basic color when |severity| is NONE.
+SkColor GetIconColorForSeverity(AppMenuIconController::Delegate* delegate,
+                                AppMenuIconController::Severity severity,
+                                base::Optional<SkColor> promo_highlight_color) {
+  ui::NativeTheme::ColorId color_id =
+      ui::NativeTheme::kColorId_AlertSeverityHigh;
+  switch (severity) {
+    case AppMenuIconController::Severity::NONE:
+      if (promo_highlight_color)
+        return promo_highlight_color.value();
+      return delegate->GetViewThemeProvider()->GetColor(
+          ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
+    case AppMenuIconController::Severity::LOW:
+      color_id = ui::NativeTheme::kColorId_AlertSeverityLow;
+      break;
+    case AppMenuIconController::Severity::MEDIUM:
+      color_id = ui::NativeTheme::kColorId_AlertSeverityMedium;
+      break;
+    case AppMenuIconController::Severity::HIGH:
+      break;
+  }
+  return delegate->GetViewNativeTheme()->GetSystemColor(color_id);
+}
+
 }  // namespace
 
 AppMenuIconController::AppMenuIconController(Profile* profile,
@@ -121,6 +151,29 @@
   return {IconType::NONE, Severity::NONE};
 }
 
+gfx::ImageSkia AppMenuIconController::GetIconImage(
+    bool touch_ui,
+    base::Optional<SkColor> promo_highlight_color) const {
+  const auto type_and_severity = GetTypeAndSeverity();
+  const gfx::VectorIcon* icon_id =
+      touch_ui ? &kBrowserToolsTouchIcon : &kBrowserToolsIcon;
+  switch (type_and_severity.type) {
+    case AppMenuIconController::IconType::NONE:
+      break;
+    case AppMenuIconController::IconType::UPGRADE_NOTIFICATION:
+      icon_id =
+          touch_ui ? &kBrowserToolsUpdateTouchIcon : &kBrowserToolsUpdateIcon;
+      break;
+    case AppMenuIconController::IconType::GLOBAL_ERROR:
+      icon_id =
+          touch_ui ? &kBrowserToolsErrorTouchIcon : &kBrowserToolsErrorIcon;
+      break;
+  }
+  return gfx::CreateVectorIcon(
+      *icon_id, GetIconColorForSeverity(delegate_, type_and_severity.severity,
+                                        promo_highlight_color));
+}
+
 void AppMenuIconController::Observe(
     int type,
     const content::NotificationSource& source,
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller.h b/chrome/browser/ui/toolbar/app_menu_icon_controller.h
index d7e18e4..0f5580c 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller.h
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller.h
@@ -8,16 +8,24 @@
 #include <stdint.h>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "build/build_config.h"
 #include "chrome/browser/upgrade_detector/upgrade_observer.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/image/image_skia.h"
 
 class Profile;
 class UpgradeDetector;
 
+namespace ui {
+class NativeTheme;
+class ThemeProvider;
+}  // namespace ui
+
 // AppMenuIconController encapsulates the logic for badging the app menu icon
 // as a result of various events - such as available updates, errors, etc.
 class AppMenuIconController :
@@ -49,6 +57,10 @@
     // |type_and_severity|.
     virtual void UpdateTypeAndSeverity(TypeAndSeverity type_and_severity) = 0;
 
+    // Accessors for properties of the View hosting the controller.
+    virtual const ui::ThemeProvider* GetViewThemeProvider() const = 0;
+    virtual ui::NativeTheme* GetViewNativeTheme() = 0;
+
    protected:
     virtual ~Delegate() {}
   };
@@ -70,6 +82,15 @@
   // Returns the icon type and severity based on the current state.
   TypeAndSeverity GetTypeAndSeverity() const;
 
+  // Returns the image to be used for the app menu's icon and the upgrade item
+  // in the app menu (when the IconType is UPGRADE_NOTIFICATION). |touch_ui|
+  // indicates whether the touch-friendly variant is requested.
+  // |promo_highlight_color|, if provided, overrides the basic color when the
+  // app menu icon's Severity is NONE.
+  gfx::ImageSkia GetIconImage(
+      bool touch_ui,
+      base::Optional<SkColor> promo_highlight_color = base::nullopt) const;
+
  private:
   // content::NotificationObserver:
   void Observe(int type,
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc b/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
index 8db025c2..1adea7bc 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
@@ -28,6 +28,8 @@
  public:
   MOCK_METHOD1(UpdateTypeAndSeverity,
                void(AppMenuIconController::TypeAndSeverity type_and_severity));
+  MOCK_CONST_METHOD0(GetViewThemeProvider, const ui::ThemeProvider*());
+  MOCK_METHOD0(GetViewNativeTheme, ui::NativeTheme*());
 };
 
 // A fake upgrade detector that can broadcast an annoyance level change to its
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index 52997ca5..ea6d9c8 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -312,7 +312,8 @@
 bool AppMenuModel::GetIconForCommandId(int command_id, gfx::Image* icon) const {
   if (command_id == IDC_UPGRADE_DIALOG) {
     DCHECK(browser_defaults::kShowUpgradeMenuItem);
-    *icon = UpgradeDetector::GetInstance()->GetIcon();
+    DCHECK(app_menu_icon_controller_);
+    *icon = gfx::Image(app_menu_icon_controller_->GetIconImage(false));
     return true;
   }
   return false;
diff --git a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
index 8b724e0..224697d 100644
--- a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
@@ -22,6 +22,8 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/default_theme_provider.h"
+#include "ui/native_theme/native_theme.h"
 
 namespace {
 
@@ -59,6 +61,15 @@
   // AppMenuIconController::Delegate:
   void UpdateTypeAndSeverity(
       AppMenuIconController::TypeAndSeverity type_and_severity) override {}
+  const ui::ThemeProvider* GetViewThemeProvider() const override {
+    return &theme_provider_;
+  }
+  ui::NativeTheme* GetViewNativeTheme() override {
+    return ui::NativeTheme::GetInstanceForNativeUi();
+  }
+
+ private:
+  ui::DefaultThemeProvider theme_provider_;
 };
 
 } // namespace
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.cc
new file mode 100644
index 0000000..9a53555
--- /dev/null
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.cc
@@ -0,0 +1,131 @@
+// 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/desktop_capture/desktop_media_list_controller.h"
+
+#include "base/command_line.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h"
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+
+DesktopMediaListController::DesktopMediaListController(
+    DesktopMediaPickerDialogView* parent,
+    std::unique_ptr<DesktopMediaList> media_list)
+    : dialog_(parent), media_list_(std::move(media_list)) {}
+
+DesktopMediaListController::~DesktopMediaListController() = default;
+
+std::unique_ptr<views::View> DesktopMediaListController::CreateView(
+    DesktopMediaSourceViewStyle generic_style,
+    DesktopMediaSourceViewStyle single_style,
+    const base::string16& accessible_name) {
+  DCHECK(!view_);
+
+  auto view = std::make_unique<DesktopMediaListView>(
+      this, generic_style, single_style, accessible_name);
+  view_ = view.get();
+  view_observer_.Add(view_);
+  return view;
+}
+
+void DesktopMediaListController::StartUpdating(
+    content::DesktopMediaID dialog_window_id) {
+  media_list_->SetViewDialogWindowId(dialog_window_id);
+  media_list_->StartUpdating(this);
+}
+
+void DesktopMediaListController::FocusView() {
+  if (view_)
+    view_->RequestFocus();
+}
+
+base::Optional<content::DesktopMediaID>
+DesktopMediaListController::GetSelection() const {
+  if (!view_ || !view_->GetSelection())
+    return base::nullopt;
+  return base::Optional<content::DesktopMediaID>(
+      view_->GetSelection()->source_id());
+}
+
+void DesktopMediaListController::OnSourceListLayoutChanged() {
+  dialog_->OnSourceListLayoutChanged();
+}
+
+void DesktopMediaListController::OnSourceSelectionChanged() {
+  dialog_->OnSelectionChanged();
+}
+
+void DesktopMediaListController::AcceptSource() {
+  dialog_->AcceptSource();
+}
+
+void DesktopMediaListController::AcceptSpecificSource(
+    content::DesktopMediaID source) {
+  dialog_->AcceptSpecificSource(source);
+}
+
+const DesktopMediaList::Source& DesktopMediaListController::GetSource(
+    int index) const {
+  return media_list_->GetSource(index);
+}
+
+void DesktopMediaListController::SetThumbnailSize(const gfx::Size& size) {
+  media_list_->SetThumbnailSize(size);
+}
+
+views::View* DesktopMediaListController::GetViewForInitialFocus() {
+  return view_;
+}
+
+void DesktopMediaListController::OnSourceAdded(DesktopMediaList* list,
+                                               int index) {
+  if (view_)
+    view_->OnSourceAdded(index);
+
+  std::string autoselect_source =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kAutoSelectDesktopCaptureSource);
+  const DesktopMediaList::Source& source = GetSource(index);
+  if (autoselect_source.empty() ||
+      base::ASCIIToUTF16(autoselect_source) != source.name) {
+    return;
+  }
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindOnce(&DesktopMediaListController::AcceptSpecificSource,
+                     weak_factory_.GetWeakPtr(), source.id));
+}
+
+void DesktopMediaListController::OnSourceRemoved(DesktopMediaList* list,
+                                                 int index) {
+  if (view_)
+    view_->OnSourceRemoved(index);
+}
+
+void DesktopMediaListController::OnSourceMoved(DesktopMediaList* list,
+                                               int old_index,
+                                               int new_index) {
+  if (view_)
+    view_->OnSourceMoved(old_index, new_index);
+}
+void DesktopMediaListController::OnSourceNameChanged(DesktopMediaList* list,
+                                                     int index) {
+  if (view_)
+    view_->OnSourceNameChanged(index);
+}
+void DesktopMediaListController::OnSourceThumbnailChanged(
+    DesktopMediaList* list,
+    int index) {
+  if (view_)
+    view_->OnSourceThumbnailChanged(index);
+}
+
+void DesktopMediaListController::OnViewIsDeleting(views::View* view) {
+  view_observer_.Remove(view);
+  view_ = nullptr;
+}
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h b/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h
new file mode 100644
index 0000000..f9925292
--- /dev/null
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h
@@ -0,0 +1,100 @@
+// 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_DESKTOP_CAPTURE_DESKTOP_MEDIA_LIST_CONTROLLER_H_
+#define CHROME_BROWSER_UI_VIEWS_DESKTOP_CAPTURE_DESKTOP_MEDIA_LIST_CONTROLLER_H_
+
+#include <memory>
+
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/media/webrtc/desktop_media_list.h"
+#include "chrome/browser/media/webrtc/desktop_media_list_observer.h"
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_source_view.h"
+#include "ui/views/view.h"
+#include "ui/views/view_observer.h"
+
+class DesktopMediaListView;
+class DesktopMediaPickerDialogView;
+
+// This class is the controller for a DesktopMediaListView. It is responsible
+// for:
+//   * Observing a DesktopMediaList
+//   * Updating its internal view (currently a DesktopMediaListView) when that
+//     DesktopMediaList changes
+//   * Providing access to the state of its internal view to the dialog
+//   * Proxying between its internal view's callbacks and the dialog's callbacks
+class DesktopMediaListController : public DesktopMediaListObserver,
+                                   public views::ViewObserver {
+ public:
+  DesktopMediaListController(DesktopMediaPickerDialogView* dialog,
+                             std::unique_ptr<DesktopMediaList> media_list);
+  ~DesktopMediaListController() override;
+
+  // Create this controller's corresponding View. There can only be one View per
+  // controller; attempting to call this method twice on the same
+  // DesktopMediaListController is not allowed.
+  std::unique_ptr<views::View> CreateView(
+      DesktopMediaSourceViewStyle generic_style,
+      DesktopMediaSourceViewStyle single_style,
+      const base::string16& accessible_name);
+
+  // Starts observing the DesktopMediaList given earlier, ignoring any entries
+  // whose id matches dialog_window_id.
+  void StartUpdating(content::DesktopMediaID dialog_window_id);
+
+  // Focuses this controller's view.
+  void FocusView();
+
+  // Returns the DesktopMediaID corresponding to the current selection in this
+  // controller's view, if there is one.
+  base::Optional<content::DesktopMediaID> GetSelection() const;
+
+  // These three methods are called by the view to inform the controller of
+  // events. The first two indicate changes in the visual state of the view; the
+  // last indicates that the user performed an action on the source view that
+  // should serve to accept the entire dialog.
+  void OnSourceListLayoutChanged();
+  void OnSourceSelectionChanged();
+  void AcceptSource();
+
+  // Returns the view that should receive initial focus in the dialog if this
+  // controller's source list is the one being shown.
+  views::View* GetViewForInitialFocus();
+
+  // These two methods are used by the view (or its subviews) to query and
+  // update the underlying DesktopMediaList.
+  const DesktopMediaList::Source& GetSource(int index) const;
+  void SetThumbnailSize(const gfx::Size& size);
+
+ private:
+  friend class DesktopMediaPickerViewsTestApi;
+
+  // This method is used as a callback to support source auto-selection, which
+  // is used in some tests; it acts as though the user had selected (in the
+  // view) the element corresponding to the given source and accepted the
+  // dialog.
+  void AcceptSpecificSource(content::DesktopMediaID source);
+
+  // DesktopMediaListObserver:
+  void OnSourceAdded(DesktopMediaList* list, int index) override;
+  void OnSourceRemoved(DesktopMediaList* list, int index) override;
+  void OnSourceMoved(DesktopMediaList* list,
+                     int old_index,
+                     int new_index) override;
+  void OnSourceNameChanged(DesktopMediaList* list, int index) override;
+  void OnSourceThumbnailChanged(DesktopMediaList* list, int index) override;
+
+  // ViewObserver:
+  void OnViewIsDeleting(views::View* view) override;
+
+  DesktopMediaPickerDialogView* dialog_;
+  std::unique_ptr<DesktopMediaList> media_list_;
+  DesktopMediaListView* view_{nullptr};
+  ScopedObserver<views::View, views::ViewObserver> view_observer_{this};
+
+  base::WeakPtrFactory<DesktopMediaListController> weak_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_DESKTOP_CAPTURE_DESKTOP_MEDIA_LIST_CONTROLLER_H_
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
index ecccafb..2800c9a 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
@@ -8,10 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/post_task.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "chrome/browser/media/webrtc/window_icon_util.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h"
@@ -19,8 +15,6 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/theme_resources.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
 #include "extensions/grit/extensions_browser_resources.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/window.h"
@@ -55,18 +49,15 @@
 }  // namespace
 
 DesktopMediaListView::DesktopMediaListView(
-    DesktopMediaPickerDialogView* parent,
-    std::unique_ptr<DesktopMediaList> media_list,
+    DesktopMediaListController* controller,
     DesktopMediaSourceViewStyle generic_style,
     DesktopMediaSourceViewStyle single_style,
     const base::string16& accessible_name)
-    : parent_(parent),
-      media_list_(std::move(media_list)),
+    : controller_(controller),
       single_style_(single_style),
       generic_style_(generic_style),
       active_style_(&single_style_),
-      accessible_name_(accessible_name),
-      weak_factory_(this) {
+      accessible_name_(accessible_name) {
   SetStyle(&single_style_);
 
   SetFocusBehavior(FocusBehavior::ALWAYS);
@@ -74,17 +65,12 @@
 
 DesktopMediaListView::~DesktopMediaListView() {}
 
-void DesktopMediaListView::StartUpdating(DesktopMediaID dialog_window_id) {
-  media_list_->SetViewDialogWindowId(dialog_window_id);
-  media_list_->StartUpdating(this);
-}
-
 void DesktopMediaListView::OnSelectionChanged() {
-  parent_->OnSelectionChanged();
+  controller_->OnSourceSelectionChanged();
 }
 
 void DesktopMediaListView::OnDoubleClick() {
-  parent_->OnDoubleClick();
+  controller_->AcceptSource();
 }
 
 DesktopMediaSourceView* DesktopMediaListView::GetSelection() {
@@ -161,8 +147,8 @@
   return true;
 }
 
-void DesktopMediaListView::OnSourceAdded(DesktopMediaList* list, int index) {
-  const DesktopMediaList::Source& source = media_list_->GetSource(index);
+void DesktopMediaListView::OnSourceAdded(int index) {
+  const DesktopMediaList::Source& source = controller_->GetSource(index);
 
   // We are going to have a second item, apply the generic style.
   if (child_count() == 1)
@@ -189,26 +175,12 @@
   AddChildViewAt(source_view, index);
 
   if ((child_count() - 1) % active_style_->columns == 0)
-    parent_->OnMediaListRowsChanged();
+    controller_->OnSourceListLayoutChanged();
 
   PreferredSizeChanged();
-
-  std::string autoselect_source =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kAutoSelectDesktopCaptureSource);
-  if (!autoselect_source.empty() &&
-      base::ASCIIToUTF16(autoselect_source) == source.name) {
-    // Select, then accept and close the dialog when we're done adding sources.
-    parent_->SelectTab(source.id.type);
-    source_view->OnFocus();
-    base::PostTaskWithTraits(
-        FROM_HERE, {content::BrowserThread::UI},
-        base::BindOnce(&DesktopMediaListView::AcceptSelection,
-                       weak_factory_.GetWeakPtr()));
-  }
 }
 
-void DesktopMediaListView::OnSourceRemoved(DesktopMediaList* list, int index) {
+void DesktopMediaListView::OnSourceRemoved(int index) {
   DesktopMediaSourceView* view = GetChild(index);
   DCHECK(view);
 
@@ -220,7 +192,7 @@
     OnSelectionChanged();
 
   if (child_count() % active_style_->columns == 0)
-    parent_->OnMediaListRowsChanged();
+    controller_->OnSourceListLayoutChanged();
 
   // Apply single-item styling when the second source is removed.
   if (child_count() == 1)
@@ -229,35 +201,26 @@
   PreferredSizeChanged();
 }
 
-void DesktopMediaListView::OnSourceMoved(DesktopMediaList* list,
-                                         int old_index,
-                                         int new_index) {
+void DesktopMediaListView::OnSourceMoved(int old_index, int new_index) {
   ReorderChildView(child_at(old_index), new_index);
   PreferredSizeChanged();
 }
 
-void DesktopMediaListView::OnSourceNameChanged(DesktopMediaList* list,
-                                               int index) {
-  const DesktopMediaList::Source& source = media_list_->GetSource(index);
+void DesktopMediaListView::OnSourceNameChanged(int index) {
+  const DesktopMediaList::Source& source = controller_->GetSource(index);
   DesktopMediaSourceView* source_view = GetChild(index);
   source_view->SetName(source.name);
 }
 
-void DesktopMediaListView::OnSourceThumbnailChanged(DesktopMediaList* list,
-                                                    int index) {
-  const DesktopMediaList::Source& source = media_list_->GetSource(index);
+void DesktopMediaListView::OnSourceThumbnailChanged(int index) {
+  const DesktopMediaList::Source& source = controller_->GetSource(index);
   DesktopMediaSourceView* source_view = GetChild(index);
   source_view->SetThumbnail(source.thumbnail);
 }
 
-void DesktopMediaListView::AcceptSelection() {
-  OnSelectionChanged();
-  OnDoubleClick();
-}
-
 void DesktopMediaListView::SetStyle(DesktopMediaSourceViewStyle* style) {
   active_style_ = style;
-  media_list_->SetThumbnailSize(gfx::Size(
+  controller_->SetThumbnailSize(gfx::Size(
       style->image_rect.width() - 2 * style->selection_border_thickness,
       style->image_rect.height() - 2 * style->selection_border_thickness));
 
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h b/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h
index e6e4a78..62d19e40 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h
@@ -7,28 +7,24 @@
 
 #include <memory>
 
-#include "chrome/browser/media/webrtc/desktop_media_list_observer.h"
+#include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_source_view.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "ui/views/view.h"
 
-class DesktopMediaPickerDialogView;
+class DesktopMediaListController;
 
 // View that shows a list of desktop media sources available from
 // DesktopMediaList.
-class DesktopMediaListView : public views::View,
-                             public DesktopMediaListObserver {
+class DesktopMediaListView : public views::View {
  public:
-  DesktopMediaListView(DesktopMediaPickerDialogView* parent,
-                       std::unique_ptr<DesktopMediaList> media_list,
+  DesktopMediaListView(DesktopMediaListController* controller,
                        DesktopMediaSourceViewStyle generic_style,
                        DesktopMediaSourceViewStyle single_style,
                        const base::string16& accessible_name);
 
   ~DesktopMediaListView() override;
 
-  void StartUpdating(content::DesktopMediaID dialog_window_id);
-
   // Called by DesktopMediaSourceView when selection has changed.
   void OnSelectionChanged();
 
@@ -44,27 +40,20 @@
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
+  void OnSourceAdded(int index);
+  void OnSourceRemoved(int index);
+  void OnSourceMoved(int old_index, int new_index);
+  void OnSourceNameChanged(int index);
+  void OnSourceThumbnailChanged(int index);
+
  private:
-  // DesktopMediaList::Observer interface
-  void OnSourceAdded(DesktopMediaList* list, int index) override;
-  void OnSourceRemoved(DesktopMediaList* list, int index) override;
-  void OnSourceMoved(DesktopMediaList* list,
-                     int old_index,
-                     int new_index) override;
-  void OnSourceNameChanged(DesktopMediaList* list, int index) override;
-  void OnSourceThumbnailChanged(DesktopMediaList* list, int index) override;
-
-  // Accepts whatever happens to be selected right now.
-  void AcceptSelection();
-
   // Change the source style of this list on the fly.
   void SetStyle(DesktopMediaSourceViewStyle* style);
 
   // Helper for child_at().
   DesktopMediaSourceView* GetChild(int index);
 
-  DesktopMediaPickerDialogView* const parent_;
-  std::unique_ptr<DesktopMediaList> media_list_;
+  DesktopMediaListController* controller_;
 
   DesktopMediaSourceViewStyle single_style_;
   DesktopMediaSourceViewStyle generic_style_;
@@ -72,8 +61,6 @@
 
   const base::string16 accessible_name_;
 
-  base::WeakPtrFactory<DesktopMediaListView> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(DesktopMediaListView);
 };
 
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index 5f3e83cb..5e31d8e 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
-#include "chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_source_view.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -107,11 +106,11 @@
             views::ScrollView::CreateScrollViewWithBorder();
         base::string16 screen_title_text = l10n_util::GetStringUTF16(
             IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_SCREEN);
-        auto list_view = std::make_unique<DesktopMediaListView>(
-            this, std::move(source_list), kGenericScreenStyle,
-            kSingleScreenStyle, screen_title_text);
-        list_views_.push_back(
-            screen_scroll_view->SetContents(std::move(list_view)));
+        auto list_controller = std::make_unique<DesktopMediaListController>(
+            this, std::move(source_list));
+        screen_scroll_view->SetContents(list_controller->CreateView(
+            kGenericScreenStyle, kSingleScreenStyle, screen_title_text));
+        list_controllers_.push_back(std::move(list_controller));
 
         screen_scroll_view->ClipHeightTo(
             kGenericScreenStyle.item_size.height(),
@@ -139,11 +138,11 @@
             views::ScrollView::CreateScrollViewWithBorder();
         base::string16 window_title_text = l10n_util::GetStringUTF16(
             IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_WINDOW);
-        auto list_view = std::make_unique<DesktopMediaListView>(
-            this, std::move(source_list), kWindowStyle, kWindowStyle,
-            window_title_text);
-        list_views_.push_back(
-            window_scroll_view->SetContents(std::move(list_view)));
+        auto list_controller = std::make_unique<DesktopMediaListController>(
+            this, std::move(source_list));
+        window_scroll_view->SetContents(list_controller->CreateView(
+            kWindowStyle, kWindowStyle, window_title_text));
+        list_controllers_.push_back(std::move(list_controller));
 
         window_scroll_view->ClipHeightTo(kWindowStyle.item_size.height(),
                                          kWindowStyle.item_size.height() * 2);
@@ -170,10 +169,11 @@
             views::ScrollView::CreateScrollViewWithBorder();
         base::string16 tab_title_text =
             l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_TAB);
-        auto list_view = std::make_unique<DesktopMediaListView>(
-            this, std::move(source_list), kTabStyle, kTabStyle, tab_title_text);
-        list_views_.push_back(
-            tab_scroll_view->SetContents(std::move(list_view)));
+        auto list_controller = std::make_unique<DesktopMediaListController>(
+            this, std::move(source_list));
+        tab_scroll_view->SetContents(
+            list_controller->CreateView(kTabStyle, kTabStyle, tab_title_text));
+        list_controllers_.push_back(std::move(list_controller));
 
         tab_scroll_view->ClipHeightTo(kTabStyle.item_size.height() * 10,
                                       kTabStyle.item_size.height() * 10);
@@ -256,15 +256,15 @@
 #endif
   }
 
-  for (auto* list_view : list_views_)
-    list_view->StartUpdating(dialog_window_id);
+  for (const auto& list_controller : list_controllers_)
+    list_controller->StartUpdating(dialog_window_id);
 }
 
 DesktopMediaPickerDialogView::~DesktopMediaPickerDialogView() {}
 
 void DesktopMediaPickerDialogView::TabSelectedAt(int index) {
   OnSourceTypeSwitched(index);
-  list_views_[index]->RequestFocus();
+  list_controllers_[index]->FocusView();
   DialogModelChanged();
 }
 
@@ -292,6 +292,16 @@
   }
 }
 
+const DesktopMediaListController*
+DesktopMediaPickerDialogView::GetSelectedController() const {
+  return list_controllers_[pane_->GetSelectedTabIndex()].get();
+}
+
+DesktopMediaListController*
+DesktopMediaPickerDialogView::GetSelectedController() {
+  return list_controllers_[pane_->GetSelectedTabIndex()].get();
+}
+
 void DesktopMediaPickerDialogView::DetachParent() {
   parent_ = nullptr;
 }
@@ -311,13 +321,12 @@
 
 bool DesktopMediaPickerDialogView::IsDialogButtonEnabled(
     ui::DialogButton button) const {
-  if (button == ui::DIALOG_BUTTON_OK)
-    return list_views_[pane_->GetSelectedTabIndex()]->GetSelection() != nullptr;
-  return true;
+  return button != ui::DIALOG_BUTTON_OK ||
+         GetSelectedController()->GetSelection().has_value();
 }
 
 views::View* DesktopMediaPickerDialogView::GetInitiallyFocusedView() {
-  return list_views_[0];
+  return list_controllers_[0]->GetViewForInitialFocus();
 }
 
 int DesktopMediaPickerDialogView::GetDefaultDialogButton() const {
@@ -338,12 +347,11 @@
 }
 
 bool DesktopMediaPickerDialogView::Accept() {
-  DesktopMediaSourceView* selection =
-      list_views_[pane_->GetSelectedTabIndex()]->GetSelection();
-
   // Ok button should only be enabled when a source is selected.
-  DCHECK(selection);
-  DesktopMediaID source = selection->source_id();
+  base::Optional<DesktopMediaID> source_optional =
+      accepted_source_.has_value() ? accepted_source_
+                                   : GetSelectedController()->GetSelection();
+  DesktopMediaID source = source_optional.value();
   source.audio_share = audio_share_checkbox_ &&
                        audio_share_checkbox_->visible() &&
                        audio_share_checkbox_->checked();
@@ -392,11 +400,16 @@
   DialogModelChanged();
 }
 
-void DesktopMediaPickerDialogView::OnDoubleClick() {
+void DesktopMediaPickerDialogView::AcceptSource() {
   // This will call Accept() and close the dialog.
   GetDialogClientView()->AcceptWindow();
 }
 
+void DesktopMediaPickerDialogView::AcceptSpecificSource(DesktopMediaID source) {
+  accepted_source_ = base::Optional<DesktopMediaID>(source);
+  AcceptSource();
+}
+
 void DesktopMediaPickerDialogView::SelectTab(
     content::DesktopMediaID::Type source_type) {
   for (size_t i = 0; i < source_types_.size(); i++) {
@@ -407,7 +420,7 @@
   }
 }
 
-void DesktopMediaPickerDialogView::OnMediaListRowsChanged() {
+void DesktopMediaPickerDialogView::OnSourceListLayoutChanged() {
   PreferredSizeChanged();
   // TODO(pbos): Ideally this would use shared logic similar to
   // BubbleDialogDelegateView::SizeToContents() instead of implementing sizing
@@ -427,37 +440,6 @@
   GetWidget()->CenterWindow(new_size);
 }
 
-DesktopMediaListView* DesktopMediaPickerDialogView::GetMediaListViewForTesting()
-    const {
-  return list_views_[pane_->GetSelectedTabIndex()];
-}
-
-DesktopMediaSourceView*
-DesktopMediaPickerDialogView::GetMediaSourceViewForTesting(int index) const {
-  if (list_views_[pane_->GetSelectedTabIndex()]->child_count() <= index)
-    return nullptr;
-
-  return reinterpret_cast<DesktopMediaSourceView*>(
-      list_views_[pane_->GetSelectedTabIndex()]->child_at(index));
-}
-
-views::Checkbox* DesktopMediaPickerDialogView::GetCheckboxForTesting() const {
-  return audio_share_checkbox_;
-}
-
-int DesktopMediaPickerDialogView::GetIndexOfSourceTypeForTesting(
-    DesktopMediaID::Type source_type) const {
-  for (size_t i = 0; i < source_types_.size(); i++) {
-    if (source_types_[i] == source_type)
-      return i;
-  }
-  return -1;
-}
-
-views::TabbedPane* DesktopMediaPickerDialogView::GetPaneForTesting() const {
-  return pane_;
-}
-
 DesktopMediaPickerViews::DesktopMediaPickerViews() : dialog_(nullptr) {}
 
 DesktopMediaPickerViews::~DesktopMediaPickerViews() {
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
index 63bb315..ae3843d 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
 #include "ui/views/window/dialog_delegate.h"
@@ -16,8 +17,6 @@
 class TabbedPane;
 }  // namespace views
 
-class DesktopMediaListView;
-class DesktopMediaSourceView;
 class DesktopMediaPickerViews;
 
 // Dialog view used for DesktopMediaPickerViews.
@@ -33,9 +32,11 @@
   // Called by parent (DesktopMediaPickerViews) when it's destroyed.
   void DetachParent();
 
-  // Called by DesktopMediaListView.
+  // Called by DesktopMediaListController.
   void OnSelectionChanged();
-  void OnDoubleClick();
+  void AcceptSource();
+  void AcceptSpecificSource(content::DesktopMediaID source);
+  void OnSourceListLayoutChanged();
   void SelectTab(content::DesktopMediaID::Type source_type);
 
   // views::TabbedPaneListener overrides.
@@ -56,18 +57,14 @@
   bool ShouldShowCloseButton() const override;
   void DeleteDelegate() override;
 
-  void OnMediaListRowsChanged();
-
-  DesktopMediaListView* GetMediaListViewForTesting() const;
-  DesktopMediaSourceView* GetMediaSourceViewForTesting(int index) const;
-  views::Checkbox* GetCheckboxForTesting() const;
-  int GetIndexOfSourceTypeForTesting(
-      content::DesktopMediaID::Type source_type) const;
-  views::TabbedPane* GetPaneForTesting() const;
-
  private:
+  friend class DesktopMediaPickerViewsTestApi;
+
   void OnSourceTypeSwitched(int index);
 
+  const DesktopMediaListController* GetSelectedController() const;
+  DesktopMediaListController* GetSelectedController();
+
   DesktopMediaPickerViews* parent_;
   ui::ModalType modality_;
 
@@ -76,9 +73,11 @@
   views::Checkbox* audio_share_checkbox_;
 
   views::TabbedPane* pane_;
-  std::vector<DesktopMediaListView*> list_views_;
+  std::vector<std::unique_ptr<DesktopMediaListController>> list_controllers_;
   std::vector<content::DesktopMediaID::Type> source_types_;
 
+  base::Optional<content::DesktopMediaID> accepted_source_;
+
   DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerDialogView);
 };
 
@@ -100,6 +99,8 @@
   }
 
  private:
+  friend class DesktopMediaPickerViewsTestApi;
+
   DoneCallback callback_;
 
   // The |dialog_| is owned by the corresponding views::Widget instance.
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.cc
new file mode 100644
index 0000000..ec63391
--- /dev/null
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.cc
@@ -0,0 +1,81 @@
+// 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/desktop_capture/desktop_media_picker_views_test_api.h"
+
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h"
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h"
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h"
+
+#include "ui/events/base_event_utils.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
+
+DesktopMediaPickerViewsTestApi::DesktopMediaPickerViewsTestApi() = default;
+DesktopMediaPickerViewsTestApi::~DesktopMediaPickerViewsTestApi() = default;
+
+void DesktopMediaPickerViewsTestApi::FocusSourceAtIndex(int index) {
+  GetSourceAtIndex(index)->RequestFocus();
+}
+
+void DesktopMediaPickerViewsTestApi::FocusAudioCheckbox() {
+  picker_->dialog_->audio_share_checkbox_->RequestFocus();
+}
+
+void DesktopMediaPickerViewsTestApi::PressMouseOnSourceAtIndex(
+    int index,
+    bool double_click) {
+  int flags = ui::EF_LEFT_MOUSE_BUTTON;
+  if (double_click)
+    flags |= ui::EF_IS_DOUBLE_CLICK;
+  GetSourceAtIndex(index)->OnMousePressed(
+      ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+                     ui::EventTimeForNow(), flags, ui::EF_LEFT_MOUSE_BUTTON));
+}
+
+void DesktopMediaPickerViewsTestApi::DoubleTapSourceAtIndex(int index) {
+  ui::GestureEventDetails details(ui::ET_GESTURE_TAP);
+  details.set_tap_count(2);
+  ui::GestureEvent double_tap(10, 10, 0, base::TimeTicks(), details);
+  GetSourceAtIndex(index)->OnGestureEvent(&double_tap);
+}
+
+void DesktopMediaPickerViewsTestApi::SelectTabForSourceType(
+    content::DesktopMediaID::Type source_type) {
+  const auto& source_types = picker_->dialog_->source_types_;
+  const auto i =
+      std::find(source_types.cbegin(), source_types.cend(), source_type);
+  DCHECK(i != source_types.cend());
+  picker_->dialog_->pane_->SelectTabAt(std::distance(source_types.cbegin(), i));
+}
+
+int DesktopMediaPickerViewsTestApi::GetSelectedSourceId() const {
+  DesktopMediaListController* controller =
+      picker_->dialog_->GetSelectedController();
+  base::Optional<content::DesktopMediaID> source = controller->GetSelection();
+  return source.has_value() ? source.value().id : -1;
+}
+
+bool DesktopMediaPickerViewsTestApi::HasSourceAtIndex(int index) const {
+  return bool{GetSourceAtIndex(index)};
+}
+
+views::View* DesktopMediaPickerViewsTestApi::GetSelectedListView() {
+  return picker_->dialog_->GetSelectedController()->view_;
+}
+
+views::Checkbox* DesktopMediaPickerViewsTestApi::GetAudioShareCheckbox() {
+  return picker_->dialog_->audio_share_checkbox_;
+}
+
+const views::View* DesktopMediaPickerViewsTestApi::GetSourceAtIndex(
+    int index) const {
+  views::View* list = picker_->dialog_->GetSelectedController()->view_;
+  return (index < list->child_count()) ? list->child_at(index) : nullptr;
+}
+
+views::View* DesktopMediaPickerViewsTestApi::GetSourceAtIndex(int index) {
+  views::View* list = picker_->dialog_->GetSelectedController()->view_;
+  return (index < list->child_count()) ? list->child_at(index) : nullptr;
+}
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h
new file mode 100644
index 0000000..14bc7d2
--- /dev/null
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_DESKTOP_CAPTURE_DESKTOP_MEDIA_PICKER_VIEWS_TEST_API_H_
+#define CHROME_BROWSER_UI_VIEWS_DESKTOP_CAPTURE_DESKTOP_MEDIA_PICKER_VIEWS_TEST_API_H_
+
+#include "content/public/browser/desktop_media_id.h"
+
+class DesktopMediaPickerViews;
+
+namespace views {
+class Checkbox;
+class View;
+}  // namespace views
+
+class DesktopMediaPickerViewsTestApi {
+ public:
+  DesktopMediaPickerViewsTestApi();
+  DesktopMediaPickerViewsTestApi(const DesktopMediaPickerViewsTestApi&) =
+      delete;
+  DesktopMediaPickerViewsTestApi operator=(
+      const DesktopMediaPickerViewsTestApi&) = delete;
+  ~DesktopMediaPickerViewsTestApi();
+
+  void set_picker(DesktopMediaPickerViews* picker) { picker_ = picker; }
+
+  void FocusAudioCheckbox();
+  void PressMouseOnSourceAtIndex(int index, bool double_click = false);
+  void SelectTabForSourceType(content::DesktopMediaID::Type source_type);
+  views::Checkbox* GetAudioShareCheckbox();
+
+  bool HasSourceAtIndex(int index) const;
+  void FocusSourceAtIndex(int index);
+  void DoubleTapSourceAtIndex(int index);
+  int GetSelectedSourceId() const;
+  views::View* GetSelectedListView();
+
+ private:
+  const views::View* GetSourceAtIndex(int index) const;
+  views::View* GetSourceAtIndex(int index);
+
+  DesktopMediaPickerViews* picker_;
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_DESKTOP_CAPTURE_DESKTOP_MEDIA_PICKER_VIEWS_TEST_API_H_
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
index 1e5fe00..7eeb883 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
@@ -14,7 +14,9 @@
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/fake_desktop_media_list.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h"
+#include "chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_source_view.h"
 #include "components/web_modal/test_web_contents_modal_dialog_host.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -64,6 +66,7 @@
     base::string16 app_name = base::ASCIIToUTF16("foo");
 
     picker_views_.reset(new DesktopMediaPickerViews());
+    test_api_.set_picker(picker_views_.get());
     DesktopMediaPicker::Params picker_params;
     picker_params.context = test_helper_.GetContext();
     picker_params.app_name = app_name;
@@ -85,18 +88,6 @@
     return picker_views_->GetDialogViewForTesting();
   }
 
-  bool ClickSourceTypeButton(DesktopMediaID::Type source_type) {
-    int index =
-        GetPickerDialogView()->GetIndexOfSourceTypeForTesting(source_type);
-
-    if (index < 0)
-      return false;
-
-    GetPickerDialogView()->GetPaneForTesting()->SelectTabAt(
-        static_cast<size_t>(index));
-    return true;
-  }
-
   MOCK_METHOD1(OnPickerDone, void(content::DesktopMediaID));
 
  protected:
@@ -104,6 +95,7 @@
   views::ScopedViewsTestHelper test_helper_;
   std::map<DesktopMediaID::Type, FakeDesktopMediaList*> media_lists_;
   std::unique_ptr<DesktopMediaPickerViews> picker_views_;
+  DesktopMediaPickerViewsTestApi test_api_;
 };
 
 TEST_F(DesktopMediaPickerViewsTest, DoneCallbackCalledWhenWindowClosed) {
@@ -118,14 +110,13 @@
   EXPECT_CALL(*this, OnPickerDone(kFakeId));
 
   media_lists_[DesktopMediaID::TYPE_WINDOW]->AddSourceByFullMediaID(kFakeId);
-  GetPickerDialogView()->GetCheckboxForTesting()->SetChecked(true);
+  test_api_.GetAudioShareCheckbox()->SetChecked(true);
 
   EXPECT_FALSE(
       GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
 
-  EXPECT_TRUE(ClickSourceTypeButton(DesktopMediaID::TYPE_WINDOW));
-
-  GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnFocus();
+  test_api_.SelectTabForSourceType(DesktopMediaID::TYPE_WINDOW);
+  test_api_.FocusSourceAtIndex(0);
 
   EXPECT_TRUE(
       GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
@@ -138,39 +129,20 @@
 // original selected MediaSourceView gets unselected.
 TEST_F(DesktopMediaPickerViewsTest, SelectMediaSourceViewOnSingleClick) {
   for (auto source_type : kSourceTypes) {
-    EXPECT_TRUE(ClickSourceTypeButton(source_type));
+    test_api_.SelectTabForSourceType(source_type);
     media_lists_[source_type]->AddSourceByFullMediaID(
-        DesktopMediaID(source_type, 0));
+        DesktopMediaID(source_type, 10));
     media_lists_[source_type]->AddSourceByFullMediaID(
-        DesktopMediaID(source_type, 1));
-
-    DesktopMediaSourceView* source_view_0 =
-        GetPickerDialogView()->GetMediaSourceViewForTesting(0);
-
-    DesktopMediaSourceView* source_view_1 =
-        GetPickerDialogView()->GetMediaSourceViewForTesting(1);
+        DesktopMediaID(source_type, 20));
 
     // By default, nothing should be selected.
-    EXPECT_FALSE(source_view_0->is_selected());
-    EXPECT_FALSE(source_view_1->is_selected());
+    EXPECT_EQ(-1, test_api_.GetSelectedSourceId());
 
-    // Source view 0 is selected with mouse click.
-    ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
-                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
+    test_api_.PressMouseOnSourceAtIndex(0);
+    EXPECT_EQ(10, test_api_.GetSelectedSourceId());
 
-    GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnMousePressed(
-        press);
-
-    EXPECT_TRUE(source_view_0->is_selected());
-    EXPECT_FALSE(source_view_1->is_selected());
-
-    // Source view 1 is selected and source view 0 is unselected with mouse
-    // click.
-    GetPickerDialogView()->GetMediaSourceViewForTesting(1)->OnMousePressed(
-        press);
-
-    EXPECT_FALSE(source_view_0->is_selected());
-    EXPECT_TRUE(source_view_1->is_selected());
+    test_api_.PressMouseOnSourceAtIndex(1);
+    EXPECT_EQ(20, test_api_.GetSelectedSourceId());
   }
 }
 
@@ -180,16 +152,10 @@
 
   media_lists_[DesktopMediaID::TYPE_WEB_CONTENTS]->AddSourceByFullMediaID(
       kFakeId);
-  EXPECT_TRUE(ClickSourceTypeButton(DesktopMediaID::TYPE_WEB_CONTENTS));
-  GetPickerDialogView()->GetCheckboxForTesting()->SetChecked(false);
+  test_api_.SelectTabForSourceType(DesktopMediaID::TYPE_WEB_CONTENTS);
+  test_api_.GetAudioShareCheckbox()->SetChecked(false);
 
-  ui::MouseEvent double_click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
-                              ui::EventTimeForNow(),
-                              ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK,
-                              ui::EF_LEFT_MOUSE_BUTTON);
-
-  GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnMousePressed(
-      double_click);
+  test_api_.PressMouseOnSourceAtIndex(0, true);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -197,16 +163,11 @@
   const DesktopMediaID kFakeId(DesktopMediaID::TYPE_SCREEN, 222);
   EXPECT_CALL(*this, OnPickerDone(kFakeId));
 
-  EXPECT_TRUE(ClickSourceTypeButton(DesktopMediaID::TYPE_SCREEN));
-  GetPickerDialogView()->GetCheckboxForTesting()->SetChecked(false);
+  test_api_.SelectTabForSourceType(DesktopMediaID::TYPE_SCREEN);
+  test_api_.GetAudioShareCheckbox()->SetChecked(false);
 
   media_lists_[DesktopMediaID::TYPE_SCREEN]->AddSourceByFullMediaID(kFakeId);
-  ui::GestureEventDetails details(ui::ET_GESTURE_TAP);
-  details.set_tap_count(2);
-  ui::GestureEvent double_tap(10, 10, 0, base::TimeTicks(), details);
-
-  GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnGestureEvent(
-      &double_tap);
+  test_api_.DoubleTapSourceAtIndex(0);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -219,19 +180,19 @@
 // updated.
 TEST_F(DesktopMediaPickerViewsTest, AddAndRemoveMediaSource) {
   for (auto source_type : kSourceTypes) {
-    EXPECT_TRUE(ClickSourceTypeButton(source_type));
+    test_api_.SelectTabForSourceType(source_type);
     // No media source at first.
-    EXPECT_FALSE(GetPickerDialogView()->GetMediaSourceViewForTesting(0));
+    EXPECT_FALSE(test_api_.HasSourceAtIndex(0));
 
     for (int i = 0; i < 3; ++i) {
       media_lists_[source_type]->AddSourceByFullMediaID(
           DesktopMediaID(source_type, i));
-      EXPECT_TRUE(GetPickerDialogView()->GetMediaSourceViewForTesting(i));
+      EXPECT_TRUE(test_api_.HasSourceAtIndex(i));
     }
 
     for (int i = 2; i >= 0; --i) {
       media_lists_[source_type]->RemoveSource(i);
-      EXPECT_FALSE(GetPickerDialogView()->GetMediaSourceViewForTesting(i));
+      EXPECT_FALSE(test_api_.HasSourceAtIndex(i));
     }
   }
 }
@@ -240,38 +201,30 @@
 // original selected MediaSourceView gets unselected.
 TEST_F(DesktopMediaPickerViewsTest, FocusMediaSourceViewToSelect) {
   for (auto source_type : kSourceTypes) {
-    ClickSourceTypeButton(source_type);
+    test_api_.SelectTabForSourceType(source_type);
     media_lists_[source_type]->AddSourceByFullMediaID(
-        DesktopMediaID(source_type, 0));
+        DesktopMediaID(source_type, 10));
     media_lists_[source_type]->AddSourceByFullMediaID(
-        DesktopMediaID(source_type, 1));
+        DesktopMediaID(source_type, 20));
 
-    DesktopMediaSourceView* source_view_0 =
-        GetPickerDialogView()->GetMediaSourceViewForTesting(0);
+    test_api_.FocusSourceAtIndex(0);
+    EXPECT_EQ(10, test_api_.GetSelectedSourceId());
 
-    DesktopMediaSourceView* source_view_1 =
-        GetPickerDialogView()->GetMediaSourceViewForTesting(1);
+    test_api_.FocusAudioCheckbox();
+    EXPECT_EQ(10, test_api_.GetSelectedSourceId());
 
-    source_view_0->OnFocus();
-    EXPECT_TRUE(source_view_0->is_selected());
-
-    // Removing the focus does not undo the selection.
-    source_view_0->OnBlur();
-    EXPECT_TRUE(source_view_0->is_selected());
-
-    source_view_1->OnFocus();
-    EXPECT_FALSE(source_view_0->is_selected());
-    EXPECT_TRUE(source_view_1->is_selected());
+    test_api_.FocusSourceAtIndex(1);
+    EXPECT_EQ(20, test_api_.GetSelectedSourceId());
   }
 }
 
 TEST_F(DesktopMediaPickerViewsTest, OkButtonDisabledWhenNoSelection) {
   for (auto source_type : kSourceTypes) {
-    EXPECT_TRUE(ClickSourceTypeButton(source_type));
+    test_api_.SelectTabForSourceType(source_type);
     media_lists_[source_type]->AddSourceByFullMediaID(
         DesktopMediaID(source_type, 111));
 
-    GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnFocus();
+    test_api_.FocusSourceAtIndex(0);
     EXPECT_TRUE(
         GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
 
@@ -283,24 +236,23 @@
 
 // Verifies that the MediaListView gets the initial focus.
 TEST_F(DesktopMediaPickerViewsTest, ListViewHasInitialFocus) {
-  EXPECT_TRUE(GetPickerDialogView()->GetMediaListViewForTesting()->HasFocus());
+  EXPECT_TRUE(test_api_.GetSelectedListView()->HasFocus());
 }
 
 // Verifies the visible status of audio checkbox.
 TEST_F(DesktopMediaPickerViewsTest, AudioCheckboxState) {
   bool expect_value = false;
-  EXPECT_TRUE(ClickSourceTypeButton(DesktopMediaID::TYPE_SCREEN));
+  test_api_.SelectTabForSourceType(DesktopMediaID::TYPE_SCREEN);
 #if defined(OS_WIN) || defined(USE_CRAS)
   expect_value = true;
 #endif
-  EXPECT_EQ(expect_value,
-            GetPickerDialogView()->GetCheckboxForTesting()->visible());
+  EXPECT_EQ(expect_value, test_api_.GetAudioShareCheckbox()->visible());
 
-  EXPECT_TRUE(ClickSourceTypeButton(DesktopMediaID::TYPE_WINDOW));
-  EXPECT_FALSE(GetPickerDialogView()->GetCheckboxForTesting()->visible());
+  test_api_.SelectTabForSourceType(DesktopMediaID::TYPE_WINDOW);
+  EXPECT_FALSE(test_api_.GetAudioShareCheckbox()->visible());
 
-  EXPECT_TRUE(ClickSourceTypeButton(DesktopMediaID::TYPE_WEB_CONTENTS));
-  EXPECT_TRUE(GetPickerDialogView()->GetCheckboxForTesting()->visible());
+  test_api_.SelectTabForSourceType(DesktopMediaID::TYPE_WEB_CONTENTS);
+  EXPECT_TRUE(test_api_.GetAudioShareCheckbox()->visible());
 }
 
 // Verifies that audio share information is recorded in the ID if the checkbox
@@ -317,9 +269,9 @@
   media_lists_[DesktopMediaID::TYPE_WEB_CONTENTS]->AddSourceByFullMediaID(
       originId);
 
-  EXPECT_TRUE(ClickSourceTypeButton(DesktopMediaID::TYPE_WEB_CONTENTS));
-  GetPickerDialogView()->GetCheckboxForTesting()->SetChecked(true);
-  GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnFocus();
+  test_api_.SelectTabForSourceType(DesktopMediaID::TYPE_WEB_CONTENTS);
+  test_api_.GetAudioShareCheckbox()->SetChecked(true);
+  test_api_.FocusSourceAtIndex(0);
 
   GetPickerDialogView()->GetDialogClientView()->AcceptWindow();
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 2c50892..7e08fab 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -137,6 +137,11 @@
   return !browser_view_->browser()->hosted_app_controller();
 }
 
+SkColor BrowserNonClientFrameView::GetCaptionColor(
+    ActiveState active_state) const {
+  return color_utils::GetColorWithMaxContrast(GetFrameColor(active_state));
+}
+
 SkColor BrowserNonClientFrameView::GetFrameColor(
     ActiveState active_state) const {
   ThemeProperties::OverwritableByUserThemeProperty color_id;
@@ -157,6 +162,14 @@
                                           browser_view_->IsIncognito());
 }
 
+void BrowserNonClientFrameView::UpdateFrameColor() {
+  // Only hosted app windows support dynamic frame colors set by HTML meta tags.
+  if (!hosted_app_button_container_)
+    return;
+  hosted_app_button_container_->UpdateCaptionColors();
+  SchedulePaint();
+}
+
 SkColor BrowserNonClientFrameView::GetToolbarTopSeparatorColor() const {
   const int color_id =
       ShouldPaintAsActive()
@@ -224,11 +237,6 @@
     hosted_app_button_container_->UpdateStatusIconsVisibility();
 }
 
-SkColor BrowserNonClientFrameView::GetCaptionColor(
-    ActiveState active_state) const {
-  return color_utils::GetColorWithMaxContrast(GetFrameColor(active_state));
-}
-
 bool BrowserNonClientFrameView::ShouldPaintAsActive(
     ActiveState active_state) const {
   return (active_state == kUseCurrent) ? ShouldPaintAsActive()
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 2660986..7059ce23 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -93,10 +93,18 @@
   // Returns whether tab strokes can be drawn.
   virtual bool CanDrawStrokes() const;
 
+  // Returns the color to use for text, caption buttons, and other title bar
+  // elements.
+  virtual SkColor GetCaptionColor(ActiveState active_state = kUseCurrent) const;
+
   // Returns the color of the browser frame, which is also the color of the
   // tabstrip background.
   SkColor GetFrameColor(ActiveState active_state = kUseCurrent) const;
 
+  // Called by BrowserView to signal the frame color has changed and needs
+  // to be repainted.
+  void UpdateFrameColor();
+
   // Returns COLOR_TOOLBAR_TOP_SEPARATOR[,_INACTIVE] depending on the activation
   // state of the window.
   SkColor GetToolbarTopSeparatorColor() const;
@@ -130,10 +138,6 @@
   }
 
  protected:
-  // Returns the color to use for text, caption buttons, and other title bar
-  // elements.
-  virtual SkColor GetCaptionColor(ActiveState active_state = kUseCurrent) const;
-
   // Converts an ActiveState to a bool representing whether the frame should be
   // treated as active.
   bool ShouldPaintAsActive(ActiveState active_state) const;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
index ce441fef..f23d09d 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "ui/base/theme_provider.h"
 
@@ -27,9 +28,11 @@
   BrowserNonClientFrameViewBrowserTest() = default;
   ~BrowserNonClientFrameViewBrowserTest() override = default;
 
-  void SetUpOnMainThread() override {
-    ExtensionBrowserTest::SetUpOnMainThread();
+  void SetUp() override {
     scoped_feature_list_.InitAndEnableFeature(features::kDesktopPWAWindowing);
+    ASSERT_TRUE(embedded_test_server()->Start());
+
+    extensions::ExtensionBrowserTest::SetUp();
   }
 
   // Note: A "bookmark app" is a type of hosted app. All of these tests apply
@@ -45,11 +48,11 @@
     const extensions::Extension* app =
         extensions::browsertest_util::InstallBookmarkApp(browser()->profile(),
                                                          web_app_info);
-    content::TestNavigationObserver navigation_observer(GetAppURL());
-    navigation_observer.StartWatchingNewWebContents();
     app_browser_ = extensions::browsertest_util::LaunchAppBrowser(
         browser()->profile(), app);
-    navigation_observer.WaitForNavigationFinished();
+    web_contents_ = app_browser_->tab_strip_model()->GetActiveWebContents();
+    // Ensure the main page has loaded and is ready for ExecJs DOM manipulation.
+    ASSERT_TRUE(content::NavigateToURL(web_contents_, GetAppURL()));
 
     BrowserView* browser_view =
         BrowserView::GetBrowserViewForBrowser(app_browser_);
@@ -59,10 +62,11 @@
  protected:
   base::Optional<SkColor> app_theme_color_ = SK_ColorBLUE;
   Browser* app_browser_ = nullptr;
+  content::WebContents* web_contents_ = nullptr;
   BrowserNonClientFrameView* app_frame_view_ = nullptr;
 
  private:
-  GURL GetAppURL() { return GURL("https://test.org"); }
+  GURL GetAppURL() { return embedded_test_server()->GetURL("/empty.html"); }
 
   base::test::ScopedFeatureList scoped_feature_list_;
 
@@ -162,10 +166,8 @@
   InstallAndLaunchBookmarkApp();
   EXPECT_GT(app_frame_view_->GetTopInset(false), 0);
 
-  content::WebContents* web_contents =
-      app_frame_view_->browser_view()->GetActiveWebContents();
   static_cast<content::WebContentsDelegate*>(app_browser_)
-      ->EnterFullscreenModeForTab(web_contents, web_contents->GetURL(), {});
+      ->EnterFullscreenModeForTab(web_contents_, web_contents_->GetURL(), {});
 
   EXPECT_EQ(app_frame_view_->GetTopInset(false), 0);
 }
@@ -175,14 +177,30 @@
                        CustomTabBarIsVisibleInFullscreen) {
   InstallAndLaunchBookmarkApp();
 
-  content::WebContents* web_contents =
-      app_frame_view_->browser_view()->GetActiveWebContents();
-
   ui_test_utils::NavigateToURL(app_browser_, GURL("http://example.com"));
 
   static_cast<content::WebContentsDelegate*>(app_browser_)
-      ->EnterFullscreenModeForTab(web_contents, web_contents->GetURL(), {});
+      ->EnterFullscreenModeForTab(web_contents_, web_contents_->GetURL(), {});
 
   EXPECT_TRUE(
       app_frame_view_->browser_view()->toolbar()->custom_tab_bar()->IsDrawn());
 }
+
+// Tests that hosted app frames reflect the theme color set by HTML meta tags.
+IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewBrowserTest,
+                       HTMLMetaThemeColorOverridesManifest) {
+  // Ensure we're not using the system theme on Linux.
+  ThemeService* theme_service =
+      ThemeServiceFactory::GetForProfile(browser()->profile());
+  theme_service->UseDefaultTheme();
+
+  InstallAndLaunchBookmarkApp();
+  EXPECT_EQ(app_frame_view_->GetFrameColor(), *app_theme_color_);
+
+  EXPECT_TRUE(content::ExecJs(web_contents_, R"(
+      document.documentElement.innerHTML =
+          '<meta name="theme-color" content="yellow">';
+  )"));
+  EXPECT_EQ(app_frame_view_->GetFrameColor(), SK_ColorYELLOW);
+  DCHECK_NE(*app_theme_color_, SK_ColorYELLOW);
+}
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 5771b23..4a334e6c 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -764,6 +764,10 @@
     frame_->UpdateWindowIcon();
 }
 
+void BrowserView::UpdateFrameColor() {
+  frame_->GetFrameView()->UpdateFrameColor();
+}
+
 void BrowserView::BookmarkBarStateChanged(
     BookmarkBar::AnimateChangeType change_type) {
   if (bookmark_bar_view_.get()) {
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 9b52e8b..bbe01ee 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -306,6 +306,7 @@
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   StatusBubble* GetStatusBubble() override;
   void UpdateTitleBar() override;
+  void UpdateFrameColor() override;
   void BookmarkBarStateChanged(
       BookmarkBar::AnimateChangeType change_type) override;
   void UpdateDevTools() override;
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index af0ce2e5..461c8b9 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -195,6 +195,14 @@
   return BrowserNonClientFrameView::CanDrawStrokes();
 }
 
+SkColor GlassBrowserFrameView::GetCaptionColor(ActiveState active_state) const {
+  const SkAlpha title_alpha = ShouldPaintAsActive(active_state)
+                                  ? SK_AlphaOPAQUE
+                                  : kInactiveTitlebarFeatureAlpha;
+  return SkColorSetA(GetReadableFeatureColor(GetFrameColor(active_state)),
+                     title_alpha);
+}
+
 void GlassBrowserFrameView::UpdateThrobber(bool running) {
   if (ShowCustomIcon())
     window_icon_->Update();
@@ -220,14 +228,6 @@
   return min_size;
 }
 
-SkColor GlassBrowserFrameView::GetCaptionColor(ActiveState active_state) const {
-  const SkAlpha title_alpha = ShouldPaintAsActive(active_state)
-                                  ? SK_AlphaOPAQUE
-                                  : kInactiveTitlebarFeatureAlpha;
-  return SkColorSetA(GetReadableFeatureColor(GetFrameColor(active_state)),
-                     title_alpha);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // GlassBrowserFrameView, views::NonClientFrameView implementation:
 
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
index 7c8da89..90eb6b2 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
@@ -40,9 +40,9 @@
   int GetThemeBackgroundXInset() const override;
   bool HasVisibleBackgroundTabShapes(ActiveState active_state) const override;
   bool CanDrawStrokes() const override;
+  SkColor GetCaptionColor(ActiveState active_state) const override;
   void UpdateThrobber(bool running) override;
   gfx::Size GetMinimumSize() const override;
-  SkColor GetCaptionColor(ActiveState active_state) const override;
 
   // views::NonClientFrameView:
   gfx::Rect GetBoundsForClientView() const override;
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.cc b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
index a1183f7..d808a89a7 100644
--- a/chrome/browser/ui/views/frame/hosted_app_button_container.cc
+++ b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
@@ -214,7 +214,7 @@
   params.types_enabled.push_back(PageActionIconType::kTranslate);
   params.types_enabled.push_back(PageActionIconType::kZoom);
   params.icon_size = GetLayoutConstant(HOSTED_APP_PAGE_ACTION_ICON_SIZE);
-  params.icon_color = GetIconColor();
+  params.icon_color = GetCaptionColor();
   params.between_icon_spacing = HorizontalPaddingBetweenItems();
   params.browser = browser_view_->browser();
   params.command_updater = browser_view_->browser()->command_controller();
@@ -259,6 +259,16 @@
   page_action_icon_container_view_->UpdateAll();
 }
 
+void HostedAppButtonContainer::UpdateCaptionColors() {
+  const BrowserNonClientFrameView* frame_view =
+      browser_view_->frame()->GetFrameView();
+  active_color_ = frame_view->GetCaptionColor(
+      BrowserNonClientFrameView::ActiveState::kActive);
+  inactive_color_ = frame_view->GetCaptionColor(
+      BrowserNonClientFrameView::ActiveState::kInactive);
+  UpdateChildrenColor();
+}
+
 void HostedAppButtonContainer::SetPaintAsActive(bool active) {
   if (paint_as_active_ == active)
     return;
@@ -311,7 +321,7 @@
 }
 
 SkColor HostedAppButtonContainer::GetContentSettingInkDropColor() const {
-  return GetIconColor();
+  return GetCaptionColor();
 }
 
 content::WebContents* HostedAppButtonContainer::GetContentSettingWebContents() {
@@ -337,7 +347,7 @@
 }
 
 SkColor HostedAppButtonContainer::GetPageActionInkDropColor() const {
-  return GetIconColor();
+  return GetCaptionColor();
 }
 
 content::WebContents*
@@ -454,12 +464,12 @@
   return content_settings_container_->GetContentSettingViewsForTesting();
 }
 
-SkColor HostedAppButtonContainer::GetIconColor() const {
+SkColor HostedAppButtonContainer::GetCaptionColor() const {
   return paint_as_active_ ? active_color_ : inactive_color_;
 }
 
 void HostedAppButtonContainer::UpdateChildrenColor() {
-  SkColor icon_color = GetIconColor();
+  SkColor icon_color = GetCaptionColor();
   hosted_app_origin_text_->SetTextColor(icon_color);
   content_settings_container_->SetIconColor(icon_color);
   page_action_icon_container_view_->SetIconColor(icon_color);
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.h b/chrome/browser/ui/views/frame/hosted_app_button_container.h
index dd732b68..f8aa41b 100644
--- a/chrome/browser/ui/views/frame/hosted_app_button_container.h
+++ b/chrome/browser/ui/views/frame/hosted_app_button_container.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/views/accessible_pane_view.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/button/menu_button_listener.h"
@@ -71,6 +72,8 @@
 
   void UpdateStatusIconsVisibility();
 
+  void UpdateCaptionColors();
+
   // Sets the container to paints its buttons the active/inactive color.
   void SetPaintAsActive(bool active);
 
@@ -151,7 +154,7 @@
   const std::vector<ContentSettingImageView*>&
   GetContentSettingViewsForTesting() const;
 
-  SkColor GetIconColor() const;
+  SkColor GetCaptionColor() const;
   void UpdateChildrenColor();
 
   // Whether we're waiting for the widget to become visible.
@@ -168,8 +171,8 @@
 
   // Button and text colors.
   bool paint_as_active_ = true;
-  const SkColor active_color_;
-  const SkColor inactive_color_;
+  SkColor active_color_;
+  SkColor inactive_color_;
 
   // Owned by the views hierarchy.
   HostedAppOriginText* hosted_app_origin_text_ = nullptr;
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index 5cf42d5e..e493479 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -240,7 +240,7 @@
       PaymentRequestSheetController::GetHeaderBackground();
   if (web_contents()) {
     return views::CreateSolidBackground(color_utils::GetResultingPaintColor(
-        web_contents()->GetThemeColor(),
+        web_contents()->GetThemeColor().value_or(SK_ColorTRANSPARENT),
         default_header_background->get_color()));
   }
   return default_header_background;
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.cc b/chrome/browser/ui/views/tabs/tab_close_button.cc
index f1698a8..0931e67 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_close_button.cc
@@ -8,7 +8,7 @@
 #include <memory>
 #include <vector>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/no_destructor.h"
 #include "base/stl_util.h"
 #include "chrome/app/vector_icons/vector_icons.h"
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index 7d36c059..014ca04 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -314,11 +314,13 @@
 
   // If the preview image feature is not enabled, this will be null.
   if (preview_image_) {
-    // If there is no valid thumbnail data, remove the preview, else wait for
+    // If there is no valid thumbnail data, blank out the preview, else wait for
     // the image data to be decoded and update momentarily.
-    preview_image_->SetVisible(data.thumbnail.AsImageSkiaAsync(
-        base::BindOnce(&TabHoverCardBubbleView::UpdatePreviewImage,
-                       weak_factory_.GetWeakPtr())));
+    if (!data.thumbnail.AsImageSkiaAsync(
+            base::BindOnce(&TabHoverCardBubbleView::UpdatePreviewImage,
+                           weak_factory_.GetWeakPtr()))) {
+      preview_image_->SetImage(gfx::ImageSkia());
+    }
   }
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
index 7cf03a6..ddd14efa86 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
@@ -42,6 +42,7 @@
 
  private:
   friend class TabHoverCardBubbleViewBrowserTest;
+  friend class TabHoverCardBubbleViewInteractiveUiTest;
   class WidgetFadeAnimationDelegate;
 
   // Get delay in milliseconds based on tab width.
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view_interactive_uitest.cc
new file mode 100644
index 0000000..4a9ceaa
--- /dev/null
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view_interactive_uitest.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 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/test/scoped_feature_list.h"
+#include "build/build_config.h"
+#include "chrome/browser/browser_features.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_observer.h"
+
+using views::Widget;
+
+// Helper to wait until the hover card widget is visible.
+class HoverCardVisibleWaiter : public views::WidgetObserver {
+ public:
+  explicit HoverCardVisibleWaiter(Widget* hover_card)
+      : hover_card_(hover_card) {
+    hover_card_->AddObserver(this);
+  }
+  ~HoverCardVisibleWaiter() override { hover_card_->RemoveObserver(this); }
+
+  void Wait() {
+    if (hover_card_->IsVisible())
+      return;
+    run_loop_.Run();
+  }
+
+  // WidgetObserver overrides:
+  void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
+    if (visible)
+      run_loop_.Quit();
+  }
+
+ private:
+  Widget* const hover_card_;
+  base::RunLoop run_loop_;
+};
+
+class TabHoverCardBubbleViewInteractiveUiTest : public InProcessBrowserTest {
+ public:
+  TabHoverCardBubbleViewInteractiveUiTest() {
+    TabHoverCardBubbleView::disable_animations_for_testing_ = true;
+    scoped_feature_list_.InitAndEnableFeature(features::kTabHoverCards);
+  }
+
+  ~TabHoverCardBubbleViewInteractiveUiTest() override = default;
+
+  static TabHoverCardBubbleView* GetHoverCard(const TabStrip* tabstrip) {
+    return tabstrip->hover_card_;
+  }
+
+  static Widget* GetHoverCardWidget(const TabHoverCardBubbleView* hover_card) {
+    return hover_card->widget_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TabHoverCardBubbleViewInteractiveUiTest);
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+#if defined(USE_AURA)
+// Verify that the hover card is not visible when any key is pressed.
+IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewInteractiveUiTest,
+                       HoverCardHidesOnAnyKeyPressInSameWindow) {
+  TabStrip* tab_strip =
+      BrowserView::GetBrowserViewForBrowser(browser())->tabstrip();
+  Tab* tab = tab_strip->tab_at(0);
+  ui::MouseEvent hover_event(ui::ET_MOUSE_ENTERED, gfx::Point(), gfx::Point(),
+                             base::TimeTicks(), ui::EF_NONE, 0);
+  tab->OnMouseEntered(hover_event);
+  TabHoverCardBubbleView* hover_card = GetHoverCard(tab_strip);
+  Widget* widget = GetHoverCardWidget(hover_card);
+  HoverCardVisibleWaiter waiter(widget);
+  waiter.Wait();
+
+  EXPECT_TRUE(widget != nullptr);
+  EXPECT_TRUE(widget->IsVisible());
+
+  EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_DOWN, false,
+                                              false, false, false));
+  // Note, fade in/out animations are disabled for testing so there is no need
+  // to account for them here.
+  EXPECT_FALSE(widget->IsVisible());
+}
+#endif
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index db27231..67a6ef73 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -115,20 +115,28 @@
 int g_drop_indicator_width = 0;
 int g_drop_indicator_height = 0;
 
-#if defined(USE_AURA)
-
 // Listens in on the browser event stream (as a pre target event handler) and
 // hides an associated hover card on any keypress.
 class TabHoverCardEventSniffer : public ui::EventHandler {
  public:
   TabHoverCardEventSniffer(TabHoverCardBubbleView* hover_card,
-                           gfx::NativeWindow native_window)
-      : hover_card_(hover_card), native_window_(native_window) {
-    native_window_->AddPreTargetHandler(this);
+                           views::Widget* widget)
+      : hover_card_(hover_card), widget_(widget) {
+#if defined(OS_MACOSX)
+    if (widget_->GetRootView())
+      widget_->GetRootView()->AddPreTargetHandler(this);
+#else
+    if (widget_->GetNativeWindow())
+      widget_->GetNativeWindow()->AddPreTargetHandler(this);
+#endif
   }
 
   ~TabHoverCardEventSniffer() override {
-    native_window_->RemovePreTargetHandler(this);
+#if defined(OS_MACOSX)
+    widget_->GetRootView()->RemovePreTargetHandler(this);
+#else
+    widget_->GetNativeWindow()->RemovePreTargetHandler(this);
+#endif
   }
 
  protected:
@@ -139,11 +147,9 @@
 
  private:
   TabHoverCardBubbleView* const hover_card_;
-  gfx::NativeWindow native_window_;
+  views::Widget* widget_;
 };
 
-#endif  // defined(USE_AURA)
-
 // Animation delegate used for any automatic tab movement.  Hides the tab if it
 // is not fully visible within the tabstrip area, to prevent overflow clipping.
 class TabAnimationDelegate : public gfx::AnimationDelegate {
@@ -636,6 +642,8 @@
 
   UpdateAccessibleTabIndices();
 
+  UpdateHoverCard(nullptr, false);
+
   for (TabStripObserver& observer : observers_)
     observer.OnTabRemoved(model_index);
 
@@ -812,6 +820,8 @@
       ->NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
   selected_tabs_ = new_selection;
 
+  UpdateHoverCard(nullptr, false);
+
   // Notify all tabs whose selected state changed.
   for (auto tab_index :
        base::STLSetUnion<ui::ListSelectionModel::SelectedIndices>(
@@ -1174,12 +1184,10 @@
       return;
     hover_card_ = new TabHoverCardBubbleView(tab);
     hover_card_->views::View::AddObserver(this);
-#if defined(USE_AURA)
-    if (GetWidget() && GetWidget()->GetNativeWindow()) {
-      hover_card_event_sniffer_ = std::make_unique<TabHoverCardEventSniffer>(
-          hover_card_, GetWidget()->GetNativeWindow());
+    if (GetWidget()) {
+      hover_card_event_sniffer_ =
+          std::make_unique<TabHoverCardEventSniffer>(hover_card_, GetWidget());
     }
-#endif
   }
   if (should_show)
     hover_card_->UpdateAndShow(tab);
@@ -2873,9 +2881,7 @@
 void TabStrip::OnViewIsDeleting(views::View* observed_view) {
   if (observed_view == hover_card_) {
     hover_card_->views::View::RemoveObserver(this);
-#if defined(USE_AURA)
     hover_card_event_sniffer_.reset();
-#endif
     hover_card_ = nullptr;
   }
 }
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 094988d..f8e2519 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -17,6 +17,7 @@
 #include "base/observer_list.h"
 #include "base/scoped_observer.h"
 #include "base/timer/timer.h"
+#include "build/build_config.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/views/frame/browser_root_view.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
@@ -324,6 +325,7 @@
   friend class TabDragController;
   friend class TabDragControllerTest;
   friend class TabHoverCardBubbleViewBrowserTest;
+  friend class TabHoverCardBubbleViewInteractiveUiTest;
   friend class TabStripTest;
 
   // Used during a drop session of a url. Tracks the position of the drop as
@@ -655,9 +657,7 @@
   // The view tracker is used to keep track of if the hover card has been
   // destroyed by its widget.
   TabHoverCardBubbleView* hover_card_ = nullptr;
-#if defined(USE_AURA)
   std::unique_ptr<ui::EventHandler> hover_card_event_sniffer_;
-#endif
 
   std::unique_ptr<TabStripController> controller_;
 
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
index 8fde1dd..5382fa0a 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -13,8 +13,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "cc/paint/paint_flags.h"
-#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_otr_state.h"
 #include "chrome/browser/ui/layout_constants.h"
@@ -30,7 +28,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/base/theme_provider.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/compositor/paint_recorder.h"
 #include "ui/gfx/animation/animation_delegate.h"
@@ -38,7 +35,6 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
-#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/animation/ink_drop.h"
 #include "ui/views/animation/ink_drop_highlight.h"
 #include "ui/views/animation/ink_drop_mask.h"
@@ -254,52 +250,10 @@
 }
 
 void BrowserAppMenuButton::UpdateIcon() {
-  SkColor severity_color = gfx::kPlaceholderColor;
-
-  const ui::NativeTheme* native_theme = GetNativeTheme();
-  switch (type_and_severity_.severity) {
-    case AppMenuIconController::Severity::NONE:
-      severity_color = GetThemeProvider()->GetColor(
-          ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
-#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
-      if (promo_feature_)
-        severity_color = GetPromoHighlightColor();
-#endif
-      break;
-    case AppMenuIconController::Severity::LOW:
-      severity_color = native_theme->GetSystemColor(
-          ui::NativeTheme::kColorId_AlertSeverityLow);
-      break;
-    case AppMenuIconController::Severity::MEDIUM:
-      severity_color = native_theme->GetSystemColor(
-          ui::NativeTheme::kColorId_AlertSeverityMedium);
-      break;
-    case AppMenuIconController::Severity::HIGH:
-      severity_color = native_theme->GetSystemColor(
-          ui::NativeTheme::kColorId_AlertSeverityHigh);
-      break;
-  }
-
-  const bool touch_ui = ui::MaterialDesignController::touch_ui();
-  const gfx::VectorIcon* icon_id = nullptr;
-  switch (type_and_severity_.type) {
-    case AppMenuIconController::IconType::NONE:
-      icon_id = touch_ui ? &kBrowserToolsTouchIcon : &kBrowserToolsIcon;
-      DCHECK_EQ(AppMenuIconController::Severity::NONE,
-                type_and_severity_.severity);
-      break;
-    case AppMenuIconController::IconType::UPGRADE_NOTIFICATION:
-      icon_id =
-          touch_ui ? &kBrowserToolsUpdateTouchIcon : &kBrowserToolsUpdateIcon;
-      break;
-    case AppMenuIconController::IconType::GLOBAL_ERROR:
-      icon_id =
-          touch_ui ? &kBrowserToolsErrorTouchIcon : &kBrowserToolsErrorIcon;
-      break;
-  }
-
-  SetImage(views::Button::STATE_NORMAL,
-           gfx::CreateVectorIcon(*icon_id, severity_color));
+  SetImage(
+      views::Button::STATE_NORMAL,
+      toolbar_view_->app_menu_icon_controller()->GetIconImage(
+          ui::MaterialDesignController::touch_ui(), GetPromoHighlightColor()));
 }
 
 void BrowserAppMenuButton::SetTrailingMargin(int margin) {
@@ -328,14 +282,18 @@
     SetBorder(views::CreateEmptyBorder(new_insets));
 }
 
+base::Optional<SkColor> BrowserAppMenuButton::GetPromoHighlightColor() const {
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
-SkColor BrowserAppMenuButton::GetPromoHighlightColor() const {
-  return ToolbarButton::AdjustHighlightColorForContrast(
-      GetThemeProvider(), kFeaturePromoHighlightDarkColor,
-      kFeaturePromoHighlightLightColor, kFeaturePromoHighlightDarkExtremeColor,
-      kFeaturePromoHighlightLightExtremeColor);
-}
+  if (promo_feature_) {
+    return ToolbarButton::AdjustHighlightColorForContrast(
+        GetThemeProvider(), kFeaturePromoHighlightDarkColor,
+        kFeaturePromoHighlightLightColor,
+        kFeaturePromoHighlightDarkExtremeColor,
+        kFeaturePromoHighlightLightExtremeColor);
+  }
 #endif
+  return base::nullopt;
+}
 
 gfx::Rect BrowserAppMenuButton::GetAnchorBoundsInScreen() const {
   gfx::Rect bounds = GetBoundsInScreen();
@@ -423,9 +381,7 @@
 }
 
 SkColor BrowserAppMenuButton::GetInkDropBaseColor() const {
-#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
-  if (promo_feature_)
-    return GetPromoHighlightColor();
-#endif
-  return AppMenuButton::GetInkDropBaseColor();
+  auto promo_highlight_color = GetPromoHighlightColor();
+  return promo_highlight_color ? promo_highlight_color.value()
+                               : AppMenuButton::GetInkDropBaseColor();
 }
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
index 280f650..836e1fe 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
 #include "chrome/browser/ui/views/frame/app_menu_button.h"
@@ -70,10 +71,9 @@
  private:
   void UpdateBorder();
 
-#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
-  // Picks the best promo color given the current background color.
-  SkColor GetPromoHighlightColor() const;
-#endif
+  // If the button is being used as an anchor for a promo, returns the best
+  // promo color given the current background color.
+  base::Optional<SkColor> GetPromoHighlightColor() const;
 
   // AppMenuButton:
   const char* GetClassName() const override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index ae164f7..bc309e41 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -716,6 +716,14 @@
   app_menu_button_->SetTypeAndSeverity(type_and_severity);
 }
 
+const ui::ThemeProvider* ToolbarView::GetViewThemeProvider() const {
+  return GetThemeProvider();
+}
+
+ui::NativeTheme* ToolbarView::GetViewNativeTheme() {
+  return GetNativeTheme();
+}
+
 // ToolbarButtonProvider:
 BrowserActionsContainer* ToolbarView::GetBrowserActionsContainer() {
   return browser_actions_;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index f71d237b..6a1edcd 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -216,6 +216,8 @@
   // AppMenuIconController::Delegate:
   void UpdateTypeAndSeverity(
       AppMenuIconController::TypeAndSeverity type_and_severity) override;
+  const ui::ThemeProvider* GetViewThemeProvider() const override;
+  ui::NativeTheme* GetViewNativeTheme() override;
 
   // ToolbarButtonProvider:
   BrowserActionsContainer* GetBrowserActionsContainer() override;
diff --git a/chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.cc b/chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.cc
index 21c3cd2..fbb57f7a 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.h"
 
+#include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/webauthn/authenticator_request_sheet_model.h"
@@ -15,7 +16,6 @@
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/image_button_factory.h"
-#include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/progress_bar.h"
 #include "ui/views/layout/box_layout.h"
@@ -84,7 +84,7 @@
   auto image_with_overlays = std::make_unique<views::View>();
   image_with_overlays->SetPreferredSize(illustration_size);
 
-  auto image_view = std::make_unique<views::ImageView>();
+  auto image_view = std::make_unique<NonAccessibleImageView>();
   image_view->SetImage(model()->GetStepIllustration());
   image_view->SetPreferredSize(illustration_size);
   image_view->SizeToPreferredSize();
diff --git a/chrome/browser/ui/views/webauthn/authenticator_select_account_sheet_view.cc b/chrome/browser/ui/views/webauthn/authenticator_select_account_sheet_view.cc
index 1d2130a0..f1b6e52 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_select_account_sheet_view.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_select_account_sheet_view.cc
@@ -7,6 +7,7 @@
 
 #include "chrome/browser/ui/views/webauthn/authenticator_select_account_sheet_view.h"
 #include "chrome/grit/generated_resources.h"
+#include "device/fido/authenticator_get_assertion_response.h"
 #include "ui/base/models/table_model.h"
 #include "ui/base/models/table_model_observer.h"
 #include "ui/views/controls/scroll_view.h"
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index a44755b3..73da431 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -17,6 +17,7 @@
 #include "chrome/grit/theme_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/elide_url.h"
+#include "device/fido/authenticator_get_assertion_response.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/text_utils.h"
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc
index cb5fdf2..ca14aa8 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc
@@ -10,6 +10,10 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "base/base64.h"
 #include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
@@ -17,8 +21,10 @@
 #include "chrome/browser/chromeos/arc/tracing/arc_graphics_jank_detector.h"
 #include "chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h"
 #include "chrome/browser/chromeos/arc/tracing/arc_tracing_model.h"
+#include "chrome/browser/chromeos/file_manager/path_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
+#include "components/arc/arc_prefs.h"
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/surface.h"
 #include "components/exo/wm_helper.h"
@@ -37,15 +43,43 @@
 constexpr char kKeyTitle[] = "title";
 constexpr char kKeyTasks[] = "tasks";
 
+constexpr char kLastTracingModelName[] = "last_tracing_model.json";
+
 // Maximum interval to display.
 constexpr base::TimeDelta kMaxIntervalToDisplay =
     base::TimeDelta::FromSecondsD(2.0);
 
-std::unique_ptr<base::Value> BuildGraphicsModel(
+base::FilePath GetLastTracingModelPath(Profile* profile) {
+  DCHECK(profile);
+  return file_manager::util::GetDownloadsFolderForProfile(profile).AppendASCII(
+      kLastTracingModelName);
+}
+
+std::pair<base::Value, std::string> MaybeLoadLastGraphicsModel(
+    const base::FilePath& last_model_path) {
+  std::string json_content;
+  if (!base::ReadFileToString(last_model_path, &json_content))
+    return std::make_pair(base::Value(), std::string());
+
+  base::Optional<base::Value> model = base::JSONReader::Read(json_content);
+  if (!model || !model->is_dict())
+    return std::make_pair(base::Value(), "Failed to read last tracing model");
+
+  arc::ArcTracingGraphicsModel graphics_model;
+  base::DictionaryValue* dictionary = nullptr;
+  model->GetAsDictionary(&dictionary);
+  if (!graphics_model.LoadFromValue(*dictionary))
+    return std::make_pair(base::Value(), "Failed to load last tracing model");
+
+  return std::make_pair(std::move(*model), "Loaded last tracing model");
+}
+
+std::pair<base::Value, std::string> BuildGraphicsModel(
     const std::string& data,
     base::DictionaryValue tasks_info,
     const base::TimeTicks& time_min,
-    const base::TimeTicks& time_max) {
+    const base::TimeTicks& time_max,
+    const base::FilePath& last_model_path) {
   arc::ArcTracingModel common_model;
   const base::TimeTicks time_min_clamped =
       std::max(time_min, time_max - kMaxIntervalToDisplay);
@@ -53,21 +87,28 @@
       (time_min_clamped - base::TimeTicks()).InMicroseconds(),
       (time_max - base::TimeTicks()).InMicroseconds());
 
-  if (!common_model.Build(data)) {
-    LOG(ERROR) << "Failed to build common model";
-    return nullptr;
-  }
+  if (!common_model.Build(data))
+    return std::make_pair(base::Value(), "Failed to process tracing data");
 
   arc::ArcTracingGraphicsModel graphics_model;
-  if (!graphics_model.Build(common_model)) {
-    LOG(ERROR) << "Failed to build graphic buffers model";
-    return nullptr;
-  }
+  if (!graphics_model.Build(common_model))
+    return std::make_pair(base::Value(), "Failed to build tracing model");
 
   std::unique_ptr<base::DictionaryValue> model = graphics_model.Serialize();
   model->SetKey(kKeyTasks, std::move(tasks_info));
 
-  return model;
+  std::string json_content;
+  base::JSONWriter::WriteWithOptions(
+      *model, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_content);
+  DCHECK(!json_content.empty());
+
+  if (!base::WriteFile(last_model_path, json_content.c_str(),
+                       json_content.length())) {
+    LOG(ERROR) << "Failed serialize model to " << last_model_path.value()
+               << ".";
+  }
+
+  return std::make_pair(std::move(*model), "Tracing model is ready");
 }
 
 }  // namespace
@@ -77,17 +118,30 @@
                                               : nullptr),
       weak_ptr_factory_(this) {
   DCHECK(wm_helper_);
+
+  aura::Window* const current_active = wm_helper_->GetActiveWindow();
+  if (current_active) {
+    OnWindowActivated(ActivationReason::ACTIVATION_CLIENT /* not used */,
+                      current_active, nullptr);
+  }
+  wm_helper_->AddActivationObserver(this);
 }
 
 ArcGraphicsTracingHandler::~ArcGraphicsTracingHandler() {
+  wm_helper_->RemoveActivationObserver(this);
+  DiscardActiveArcWindow();
+
   if (tracing_active_)
     StopTracing();
 }
 
 void ArcGraphicsTracingHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
-      "startTracing",
-      base::BindRepeating(&ArcGraphicsTracingHandler::HandleStartTracing,
+      "ready", base::BindRepeating(&ArcGraphicsTracingHandler::HandleReady,
+                                   base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "setStopOnJank",
+      base::BindRepeating(&ArcGraphicsTracingHandler::HandleSetStopOnJank,
                           base::Unretained(this)));
 }
 
@@ -104,6 +158,8 @@
 
   arc_active_window_ = gained_active;
   arc_active_window_->AddObserver(this);
+  arc_active_window_->AddPreTargetHandler(this);
+
   // Limit tracing by newly activated window.
   tracing_time_min_ = TRACE_TIME_TICKS_NOW();
   jank_detector_ =
@@ -125,7 +181,8 @@
 
 void ArcGraphicsTracingHandler::OnJankDetected(const base::Time& timestamp) {
   VLOG(1) << "Jank detected " << timestamp;
-  StopTracing();
+  if (tracing_active_ && stop_on_jank_)
+    StopTracing();
 }
 
 void ArcGraphicsTracingHandler::OnWindowPropertyChanged(aura::Window* window,
@@ -143,6 +200,18 @@
   DiscardActiveArcWindow();
 }
 
+void ArcGraphicsTracingHandler::OnKeyEvent(ui::KeyEvent* event) {
+  DCHECK(arc_active_window_);
+  if (event->type() != ui::ET_KEY_RELEASED || event->key_code() != ui::VKEY_G ||
+      !event->IsControlDown() || !event->IsShiftDown()) {
+    return;
+  }
+  if (tracing_active_)
+    StopTracing();
+  else
+    StartTracing();
+}
+
 void ArcGraphicsTracingHandler::UpdateActiveArcWindowInfo() {
   DCHECK(arc_active_window_);
   base::DictionaryValue task_information;
@@ -176,28 +245,32 @@
   DCHECK(surface);
   surface->SetCommitCallback(exo::Surface::CommitCallback());
 
+  arc_active_window_->RemovePreTargetHandler(this);
   arc_active_window_->RemoveObserver(this);
   jank_detector_.reset();
   arc_active_window_ = nullptr;
 }
 
-void ArcGraphicsTracingHandler::StartTracing(double duration) {
+void ArcGraphicsTracingHandler::StartTracing() {
+  SetStatus("Collecting samples...");
+
   base::trace_event::TraceConfig config(
       "-*,exo,viz,toplevel,gpu,cc,blink,disabled-by-default-android "
       "gfx,disabled-by-default-android hal",
       base::trace_event::RECORD_CONTINUOUSLY);
-  tracing_active_ = true;
   config.EnableSystrace();
+  tracing_active_ = true;
+  if (jank_detector_)
+    jank_detector_->Reset();
   content::TracingController::GetInstance()->StartTracing(
       config, base::BindOnce(&ArcGraphicsTracingHandler::OnTracingStarted,
-                             weak_ptr_factory_.GetWeakPtr(), duration));
+                             weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ArcGraphicsTracingHandler::StopTracing() {
+  SetStatus("Building model...");
+
   tracing_active_ = false;
-  DiscardActiveArcWindow();
-  tracing_timer_.Stop();
-  wm_helper_->RemoveActivationObserver(this);
 
   tracing_time_max_ = TRACE_TIME_TICKS_NOW();
 
@@ -212,21 +285,17 @@
                           weak_ptr_factory_.GetWeakPtr())));
 }
 
-void ArcGraphicsTracingHandler::OnTracingStarted(double duration) {
-  tasks_info_.Clear();
+void ArcGraphicsTracingHandler::SetStatus(const std::string& status) {
+  AllowJavascript();
+  CallJavascriptFunction("cr.ArcGraphicsTracing.setStatus",
+                         base::Value(status.empty() ? "Idle" : status));
+}
 
-  aura::Window* const current_active = wm_helper_->GetActiveWindow();
-  if (current_active) {
-    OnWindowActivated(ActivationReason::ACTIVATION_CLIENT /* not used */,
-                      current_active, nullptr);
-  }
-  wm_helper_->AddActivationObserver(this);
+void ArcGraphicsTracingHandler::OnTracingStarted() {
+  tasks_info_.Clear();
+  UpdateActiveArcWindowInfo();
 
   tracing_time_min_ = TRACE_TIME_TICKS_NOW();
-
-  tracing_timer_.Start(FROM_HERE, base::TimeDelta::FromSecondsD(duration),
-                       base::BindOnce(&ArcGraphicsTracingHandler::StopTracing,
-                                      base::Unretained(this)));
 }
 
 void ArcGraphicsTracingHandler::OnTracingStopped(
@@ -239,32 +308,40 @@
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
       base::BindOnce(&BuildGraphicsModel, std::move(string_data),
                      std::move(tasks_info_), tracing_time_min_,
-                     tracing_time_max_),
+                     tracing_time_max_,
+                     GetLastTracingModelPath(Profile::FromWebUI(web_ui()))),
       base::BindOnce(&ArcGraphicsTracingHandler::OnGraphicsModelReady,
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ArcGraphicsTracingHandler::OnGraphicsModelReady(
-    std::unique_ptr<base::Value> model) {
-  if (!model)
+    std::pair<base::Value, std::string> result) {
+  SetStatus(result.second);
+
+  if (!result.first.is_dict())
     return;
-  AllowJavascript();
-  CallJavascriptFunction("cr.ArcGraphicsTracing.setModel", *model);
+
+  CallJavascriptFunction("cr.ArcGraphicsTracing.setModel",
+                         std::move(result.first));
 }
 
-void ArcGraphicsTracingHandler::HandleStartTracing(
+void ArcGraphicsTracingHandler::HandleReady(const base::ListValue* args) {
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&MaybeLoadLastGraphicsModel,
+                     GetLastTracingModelPath(Profile::FromWebUI(web_ui()))),
+      base::BindOnce(&ArcGraphicsTracingHandler::OnGraphicsModelReady,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ArcGraphicsTracingHandler::HandleSetStopOnJank(
     const base::ListValue* args) {
-  DCHECK_EQ(2U, args->GetSize());
-  if ((!args->GetList()[0].is_double() && !args->GetList()[0].is_int()) ||
-      (!args->GetList()[1].is_double() && !args->GetList()[1].is_int())) {
+  DCHECK_EQ(1U, args->GetSize());
+  if (!args->GetList()[0].is_bool()) {
     LOG(ERROR) << "Invalid input";
     return;
   }
-  const double delay = args->GetList()[0].GetDouble();
-  const double duration = args->GetList()[1].GetDouble();
-  tracing_timer_.Start(FROM_HERE, base::TimeDelta::FromSecondsD(delay),
-                       base::BindOnce(&ArcGraphicsTracingHandler::StartTracing,
-                                      base::Unretained(this), duration));
+  stop_on_jank_ = args->GetList()[0].GetBool();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h
index 6357d8e..c923a5b 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h
+++ b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h
@@ -11,9 +11,9 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/aura/window_observer.h"
+#include "ui/events/event_handler.h"
 #include "ui/wm/public/activation_change_observer.h"
 
 namespace arc {
@@ -34,7 +34,8 @@
 
 class ArcGraphicsTracingHandler : public content::WebUIMessageHandler,
                                   public wm::ActivationChangeObserver,
-                                  public aura::WindowObserver {
+                                  public aura::WindowObserver,
+                                  public ui::EventHandler {
  public:
   ArcGraphicsTracingHandler();
   ~ArcGraphicsTracingHandler() override;
@@ -53,19 +54,26 @@
                                intptr_t old) override;
   void OnWindowDestroying(aura::Window* window) override;
 
- private:
-  void StartTracing(double duration);
-  void StopTracing();
+  // ui::EventHandler:
+  void OnKeyEvent(ui::KeyEvent* event) override;
 
-  void OnTracingStarted(double duration);
+ private:
+  void StartTracing();
+  void StopTracing();
+  void SetStatus(const std::string& status);
+
+  void OnTracingStarted();
   void OnTracingStopped(std::unique_ptr<const base::DictionaryValue> metadata,
                         base::RefCountedString* trace_data);
 
-  // Called when graphics model is built and ready.
-  void OnGraphicsModelReady(std::unique_ptr<base::Value> model);
+  // Called when graphics model is built or load. Extra string parameter
+  // contains a status. In case model cannot be built/load empty |base::Value|
+  // is returned.
+  void OnGraphicsModelReady(std::pair<base::Value, std::string> result);
 
   // Handlers for calls from JS.
-  void HandleStartTracing(const base::ListValue* args);
+  void HandleReady(const base::ListValue* args);
+  void HandleSetStopOnJank(const base::ListValue* args);
 
   // Updates title and icon for the active ARC window.
   void UpdateActiveArcWindowInfo();
@@ -82,8 +90,8 @@
   // Indicates that tracing was initiated by this handler.
   bool tracing_active_ = false;
 
-  // To implement start/stop tracing.
-  base::OneShotTimer tracing_timer_;
+  // Determines if tracing should stop in case jank is detected runtime.
+  bool stop_on_jank_ = true;
 
   exo::WMHelper* const wm_helper_;
   aura::Window* arc_active_window_ = nullptr;
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
index 265d67c..94db4b0 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h"
 
 #include "base/command_line.h"
+#include "base/hash/sha1.h"
 #include "base/i18n/timezone.h"
-#include "base/sha1.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
index d9a1a10..d8c998b 100644
--- a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
@@ -108,10 +108,6 @@
   CallJS("login.WelcomeScreen.onInputMethodIdSetFromBackend", input_method_id);
 }
 
-void WelcomeScreenHandler::SetTimezoneId(const std::string& timezone_id) {
-  CallJS("login.WelcomeScreen.onTimezoneIdSetFromBackend", timezone_id);
-}
-
 // WelcomeScreenHandler, BaseScreenHandler implementation: --------------------
 
 void WelcomeScreenHandler::DeclareLocalizedValues(
diff --git a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
index de60b3c..32b0de7 100644
--- a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
@@ -37,7 +37,6 @@
   void StopDemoModeDetection() override;
   void ReloadLocalizedContent() override;
   void SetInputMethodId(const std::string& input_method_id) override;
-  void SetTimezoneId(const std::string& timezone_id) override;
 
   // BaseScreenHandler implementation:
   void DeclareLocalizedValues(
diff --git a/chrome/browser/ui/webui/log_web_ui_url.cc b/chrome/browser/ui/webui/log_web_ui_url.cc
index cb42bf24..2c0253d 100644
--- a/chrome/browser/ui/webui/log_web_ui_url.cc
+++ b/chrome/browser/ui/webui/log_web_ui_url.cc
@@ -6,7 +6,7 @@
 
 #include <stdint.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/common/url_constants.h"
diff --git a/chrome/browser/ui/webui/log_web_ui_url_browsertest.cc b/chrome/browser/ui/webui/log_web_ui_url_browsertest.cc
index 47835d2b..9bf7d52 100644
--- a/chrome/browser/ui/webui/log_web_ui_url_browsertest.cc
+++ b/chrome/browser/ui/webui/log_web_ui_url_browsertest.cc
@@ -8,7 +8,7 @@
 
 #include <vector>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/webui/signin_internals_ui.cc b/chrome/browser/ui/webui/signin_internals_ui.cc
index 3ff768b7..9782023 100644
--- a/chrome/browser/ui/webui/signin_internals_ui.cc
+++ b/chrome/browser/ui/webui/signin_internals_ui.cc
@@ -8,7 +8,7 @@
 #include <string>
 #include <vector>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/about_signin_internals_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
diff --git a/chrome/browser/upgrade_detector/upgrade_detector.cc b/chrome/browser/upgrade_detector/upgrade_detector.cc
index 5bc0266..a384e6c 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector.cc
+++ b/chrome/browser/upgrade_detector/upgrade_detector.cc
@@ -8,7 +8,6 @@
 #include "base/command_line.h"
 #include "base/time/clock.h"
 #include "base/time/tick_clock.h"
-#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/ui/browser_otr_state.h"
@@ -17,8 +16,6 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "ui/base/idle/idle.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/paint_vector_icon.h"
 
 // How long to wait between checks for whether the user has been idle.
 static const int kIdleRepeatingTimerWait = 10;  // Minutes (seconds if testing).
@@ -41,29 +38,6 @@
   registry->RegisterBooleanPref(prefs::kAttemptedToEnableAutoupdate, false);
 }
 
-gfx::Image UpgradeDetector::GetIcon() {
-  SkColor color = gfx::kPlaceholderColor;
-  switch (upgrade_notification_stage_) {
-    case UPGRADE_ANNOYANCE_NONE:
-      return gfx::Image();
-    case UPGRADE_ANNOYANCE_VERY_LOW:
-    case UPGRADE_ANNOYANCE_LOW:
-      color = gfx::kGoogleGreen700;
-      break;
-    case UPGRADE_ANNOYANCE_ELEVATED:
-      color = gfx::kGoogleYellow700;
-      break;
-    case UPGRADE_ANNOYANCE_HIGH:
-    case UPGRADE_ANNOYANCE_CRITICAL:
-      color = gfx::kGoogleRed700;
-      break;
-  }
-  DCHECK_NE(gfx::kPlaceholderColor, color)
-      << static_cast<int>(upgrade_notification_stage_);
-
-  return gfx::Image(gfx::CreateVectorIcon(kBrowserToolsUpdateIcon, color));
-}
-
 UpgradeDetector::UpgradeDetector(const base::Clock* clock,
                                  const base::TickClock* tick_clock)
     : clock_(clock),
diff --git a/chrome/browser/upgrade_detector/upgrade_detector.h b/chrome/browser/upgrade_detector/upgrade_detector.h
index e47e5c45..89bddbb 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector.h
+++ b/chrome/browser/upgrade_detector/upgrade_detector.h
@@ -12,7 +12,6 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/upgrade_detector/upgrade_observer.h"
 #include "components/prefs/pref_change_registrar.h"
-#include "ui/gfx/image/image.h"
 
 class PrefRegistrySimple;
 class UpgradeObserver;
@@ -97,11 +96,6 @@
   bool is_rollback() const { return is_rollback_; }
 #endif  // defined(OS_CHROMEOS)
 
-  // Retrieves the right icon based on the degree of severity (each
-  // UpgradeNotificationAnnoyanceLevel has an an accompanying icon) to display
-  // within the app menu.
-  gfx::Image GetIcon();
-
   UpgradeNotificationAnnoyanceLevel upgrade_notification_stage() const {
     return upgrade_notification_stage_;
   }
diff --git a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
index 5c76fb10..f0eb05d 100644
--- a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
+++ b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.cc
@@ -13,9 +13,12 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/bookmark_app_helper.h"
 #include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/install_manager_observer.h"
+#include "chrome/browser/web_applications/components/install_options.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
+#include "chrome/browser/web_applications/components/web_app_data_retriever.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/common/web_application_info.h"
 #include "content/public/browser/web_contents.h"
@@ -28,26 +31,38 @@
 
 // A single installation task. It is possible to have many concurrent
 // installations per one |web_contents|.
-// This class is a simple holder of BookmarkAppHelper and limits its lifetime to
-// match WebContents.
+// This class is a holder of WebAppDataRetriever or BookmarkAppHelper and limits
+// their lifetime to match WebContents, InstallManager and Profile lifetimes.
 class InstallTask : public content::WebContentsObserver,
                     public web_app::InstallManagerObserver {
  public:
   InstallTask(BookmarkAppInstallManager* install_manager,
-              std::unique_ptr<BookmarkAppHelper> bookmark_app_helper,
               web_app::InstallManager::OnceInstallCallback callback)
       : WebContentsObserver(),
-        bookmark_app_helper_(std::move(bookmark_app_helper)),
         callback_(std::move(callback)) {
     manager_observer_.Add(install_manager);
   }
 
   ~InstallTask() override { DCHECK(!callback_); }
 
-  void AttachLifetimeTo(content::WebContents* web_contents) {
+  void SetWebContents(content::WebContents* web_contents) {
     Observe(web_contents);
   }
 
+  void SetBookmarkAppHelper(
+      std::unique_ptr<BookmarkAppHelper> bookmark_app_helper) {
+    DCHECK(!data_retriever_);
+    bookmark_app_helper_ = std::move(bookmark_app_helper);
+  }
+
+  void SetDataRetriever(
+      std::unique_ptr<web_app::WebAppDataRetriever> data_retriever) {
+    DCHECK(!bookmark_app_helper_);
+    data_retriever_ = std::move(data_retriever);
+  }
+
+  void ResetDataRetriever() { data_retriever_.reset(); }
+
   // WebContentsObserver:
   void WebContentsDestroyed() override {
     DCHECK(callback_);
@@ -57,9 +72,9 @@
     // BookmarkAppHelper should not outsurvive |web_contents|.
     // This |reset| invalidates all weak references to BookmarkAppHelper and
     // cancels BookmarkAppHelper-related tasks posted to message loops.
-    // This |reset| also destroys |this| InstallTask since it is owned by the
-    // callback bind state.
-    bookmark_app_helper_.reset();
+    // This |ResetAndDeleteThisTask| call also destroys |this| InstallTask since
+    // it is owned by a callback bind state.
+    return ResetAndDeleteThisTask();
   }
 
   // InstallManagerObserver:
@@ -69,9 +84,9 @@
     CallInstallCallback(web_app::AppId(),
                         web_app::InstallResultCode::kInstallManagerDestroyed);
     // BookmarkAppHelper should not outsurvive profile and its keyed services.
-    // This |reset| also destroys |this| InstallTask since it is owned by the
-    // callback bind state.
-    bookmark_app_helper_.reset();
+    // This |ResetAndDeleteThisTask| call also destroys |this| InstallTask since
+    // it is owned by a callback bind state.
+    return ResetAndDeleteThisTask();
   }
 
   void CallInstallCallback(const web_app::AppId& app_id,
@@ -84,7 +99,20 @@
   }
 
  private:
+  void ResetAndDeleteThisTask() {
+    // One of these |reset|s deletes |this| InstallTask since it is owned by a
+    // callback bind state. We can not touch data members after it.
+    if (data_retriever_)
+      data_retriever_.reset();
+    else
+      bookmark_app_helper_.reset();
+  }
+
+  // The object invariant: InstallTask is owned either by data_retriever_ or
+  // bookmark_app_helper_. Just one of these ptrs is valid at any moment.
+  std::unique_ptr<web_app::WebAppDataRetriever> data_retriever_;
   std::unique_ptr<BookmarkAppHelper> bookmark_app_helper_;
+
   web_app::InstallManager::OnceInstallCallback callback_;
   ScopedObserver<web_app::InstallManager, InstallTask> manager_observer_{this};
 
@@ -112,10 +140,122 @@
       FROM_HERE, base::BindOnce(DestroyInstallTask, std::move(install_task)));
 }
 
+WebappInstallSource ConvertOptionsToMetricsInstallSource(
+    const web_app::InstallOptions& options) {
+  WebappInstallSource metrics_install_source = WebappInstallSource::COUNT;
+  switch (options.install_source) {
+    case web_app::InstallSource::kInternal:
+      metrics_install_source = WebappInstallSource::INTERNAL_DEFAULT;
+      break;
+    case web_app::InstallSource::kExternalDefault:
+      metrics_install_source = WebappInstallSource::EXTERNAL_DEFAULT;
+      break;
+    case web_app::InstallSource::kExternalPolicy:
+      metrics_install_source = WebappInstallSource::EXTERNAL_POLICY;
+      break;
+    case web_app::InstallSource::kSystemInstalled:
+      metrics_install_source = WebappInstallSource::SYSTEM_DEFAULT;
+      break;
+    case web_app::InstallSource::kArc:
+      NOTREACHED();
+      break;
+  }
+
+  return metrics_install_source;
+}
+
+void SetBookmarkAppHelperOptions(const web_app::InstallOptions& options,
+                                 BookmarkAppHelper* helper) {
+  switch (options.launch_container) {
+    case web_app::LaunchContainer::kDefault:
+      break;
+    case web_app::LaunchContainer::kTab:
+      helper->set_forced_launch_type(LAUNCH_TYPE_REGULAR);
+      break;
+    case web_app::LaunchContainer::kWindow:
+      helper->set_forced_launch_type(LAUNCH_TYPE_WINDOW);
+      break;
+  }
+
+  switch (options.install_source) {
+    // TODO(nigeltao/ortuno): should these two cases lead to different
+    // Manifest::Location values: INTERNAL vs EXTERNAL_PREF_DOWNLOAD?
+    case web_app::InstallSource::kInternal:
+    case web_app::InstallSource::kExternalDefault:
+      helper->set_is_default_app();
+      break;
+    case web_app::InstallSource::kExternalPolicy:
+      helper->set_is_policy_installed_app();
+      break;
+    case web_app::InstallSource::kSystemInstalled:
+      helper->set_is_system_app();
+      break;
+    case web_app::InstallSource::kArc:
+      NOTREACHED();
+      break;
+  }
+
+  if (!options.create_shortcuts)
+    helper->set_skip_shortcut_creation();
+
+  if (options.bypass_service_worker_check)
+    helper->set_bypass_service_worker_check();
+
+  if (options.require_manifest)
+    helper->set_require_manifest();
+}
+
+void OnGetWebApplicationInfo(const BookmarkAppInstallManager* install_manager,
+                             std::unique_ptr<InstallTask> install_task,
+                             const web_app::InstallOptions& install_options,
+                             std::unique_ptr<WebApplicationInfo> web_app_info) {
+  if (!web_app_info) {
+    install_task->CallInstallCallback(
+        web_app::AppId(),
+        web_app::InstallResultCode::kGetWebApplicationInfoFailed);
+
+    // OnGetWebApplicationInfo is called synchronously by WebAppDataRetriever
+    // as a tail call. We can delete InstallTask with data_retriever_ safely.
+    install_task.reset();
+    return;
+  }
+
+  WebappInstallSource metrics_install_source =
+      ConvertOptionsToMetricsInstallSource(install_options);
+
+  Profile* profile = Profile::FromBrowserContext(
+      install_task->web_contents()->GetBrowserContext());
+  DCHECK(profile);
+
+  auto bookmark_app_helper = install_manager->bookmark_app_helper_factory().Run(
+      profile, *web_app_info, install_task->web_contents(),
+      metrics_install_source);
+
+  BookmarkAppHelper* helper_ptr = bookmark_app_helper.get();
+  SetBookmarkAppHelperOptions(install_options, bookmark_app_helper.get());
+
+  install_task->ResetDataRetriever();
+  install_task->SetBookmarkAppHelper(std::move(bookmark_app_helper));
+
+  helper_ptr->Create(base::BindRepeating(
+      OnBookmarkAppInstalled, base::Passed(std::move(install_task))));
+}
+
 }  // namespace
 
 BookmarkAppInstallManager::BookmarkAppInstallManager(Profile* profile)
-    : profile_(profile) {}
+    : profile_(profile) {
+  bookmark_app_helper_factory_ = base::BindRepeating(
+      [](Profile* profile, const WebApplicationInfo& web_app_info,
+         content::WebContents* web_contents,
+         WebappInstallSource install_source) {
+        return std::make_unique<BookmarkAppHelper>(
+            profile, web_app_info, web_contents, install_source);
+      });
+
+  data_retriever_factory_ = base::BindRepeating(
+      []() { return std::make_unique<web_app::WebAppDataRetriever>(); });
+}
 
 BookmarkAppInstallManager::~BookmarkAppInstallManager() = default;
 
@@ -165,9 +305,9 @@
 
   BookmarkAppHelper* helper = bookmark_app_helper.get();
 
-  auto install_task = std::make_unique<InstallTask>(
-      this, std::move(bookmark_app_helper), std::move(callback));
-  install_task->AttachLifetimeTo(web_contents);
+  auto install_task = std::make_unique<InstallTask>(this, std::move(callback));
+  install_task->SetBookmarkAppHelper(std::move(bookmark_app_helper));
+  install_task->SetWebContents(web_contents);
 
   // InstallTask is owned by the bind state and will be disposed in
   // DestroyInstallTask.
@@ -192,8 +332,8 @@
 
   BookmarkAppHelper* helper = bookmark_app_helper.get();
 
-  auto install_task = std::make_unique<InstallTask>(
-      this, std::move(bookmark_app_helper), std::move(callback));
+  auto install_task = std::make_unique<InstallTask>(this, std::move(callback));
+  install_task->SetBookmarkAppHelper(std::move(bookmark_app_helper));
 
   // InstallTask is owned by the bind state and will be disposed in
   // DestroyInstallTask.
@@ -201,4 +341,35 @@
                                      base::Passed(std::move(install_task))));
 }
 
+void BookmarkAppInstallManager::InstallWebAppWithOptions(
+    content::WebContents* web_contents,
+    const web_app::InstallOptions& install_options,
+    OnceInstallCallback callback) {
+  auto data_retriever = data_retriever_factory_.Run();
+
+  web_app::WebAppDataRetriever* data_retriever_ptr = data_retriever.get();
+
+  auto install_task = std::make_unique<InstallTask>(this, std::move(callback));
+  install_task->SetDataRetriever(std::move(data_retriever));
+  install_task->SetWebContents(web_contents);
+
+  // Unretained |this| is used here because |install_task| is
+  // InstallManagerObserver which guarantees that it'll never run the callback
+  // if |this| is destroyed.
+  data_retriever_ptr->GetWebApplicationInfo(
+      web_contents,
+      base::BindOnce(OnGetWebApplicationInfo, base::Unretained(this),
+                     std::move(install_task), install_options));
+}
+
+void BookmarkAppInstallManager::SetBookmarkAppHelperFactoryForTesting(
+    BookmarkAppHelperFactory bookmark_app_helper_factory) {
+  bookmark_app_helper_factory_ = std::move(bookmark_app_helper_factory);
+}
+
+void BookmarkAppInstallManager::SetDataRetrieverFactoryForTesting(
+    DataRetrieverFactory data_retriever_factory) {
+  data_retriever_factory_ = std::move(data_retriever_factory);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h
index d7da6f4..518a5af 100644
--- a/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h
+++ b/chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h
@@ -7,13 +7,26 @@
 
 #include <memory>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "chrome/browser/web_applications/components/install_manager.h"
 
 class Profile;
+enum class WebappInstallSource;
+struct WebApplicationInfo;
+
+namespace content {
+class WebContents;
+}
+
+namespace web_app {
+class WebAppDataRetriever;
+}
 
 namespace extensions {
 
+class BookmarkAppHelper;
+
 // TODO(loyso): Erase this subclass together with BookmarkAppHelper.
 // crbug.com/915043.
 class BookmarkAppInstallManager final : public web_app::InstallManager {
@@ -37,10 +50,34 @@
       bool no_network_install,
       WebappInstallSource install_source,
       OnceInstallCallback callback) override;
+  void InstallWebAppWithOptions(content::WebContents* web_contents,
+                                const web_app::InstallOptions& install_options,
+                                OnceInstallCallback callback) override;
+
+  using BookmarkAppHelperFactory =
+      base::RepeatingCallback<std::unique_ptr<BookmarkAppHelper>(
+          Profile*,
+          const WebApplicationInfo&,
+          content::WebContents*,
+          WebappInstallSource)>;
+
+  const BookmarkAppHelperFactory& bookmark_app_helper_factory() const {
+    return bookmark_app_helper_factory_;
+  }
+  void SetBookmarkAppHelperFactoryForTesting(
+      BookmarkAppHelperFactory bookmark_app_helper_factory);
+
+  using DataRetrieverFactory =
+      base::RepeatingCallback<std::unique_ptr<web_app::WebAppDataRetriever>()>;
+  void SetDataRetrieverFactoryForTesting(
+      DataRetrieverFactory data_retriever_factory);
 
  private:
   Profile* profile_;
 
+  BookmarkAppHelperFactory bookmark_app_helper_factory_;
+  DataRetrieverFactory data_retriever_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(BookmarkAppInstallManager);
 };
 
diff --git a/chrome/browser/web_applications/components/install_manager.h b/chrome/browser/web_applications/components/install_manager.h
index 9fa4328e..ba7bb18d 100644
--- a/chrome/browser/web_applications/components/install_manager.h
+++ b/chrome/browser/web_applications/components/install_manager.h
@@ -23,6 +23,7 @@
 
 enum class InstallResultCode;
 class InstallManagerObserver;
+struct InstallOptions;
 
 // TODO(loyso): Rework this interface once BookmarkAppHelper erased. Unify the
 // API and merge similar InstallWebAppZZZZ functions. crbug.com/915043.
@@ -75,6 +76,12 @@
       WebappInstallSource install_source,
       OnceInstallCallback callback) = 0;
 
+  // Starts a background web app installation process for a given
+  // |web_contents|.
+  virtual void InstallWebAppWithOptions(content::WebContents* web_contents,
+                                        const InstallOptions& install_options,
+                                        OnceInstallCallback callback) = 0;
+
   InstallManager();
   virtual ~InstallManager();
 
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.cc b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
index 52c1e17..9e2e884 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_win.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
@@ -13,9 +13,9 @@
 #include "base/command_line.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn
index accf6157..e7d1112b 100644
--- a/chrome/browser/web_applications/extensions/BUILD.gn
+++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -59,6 +59,7 @@
     "//chrome/browser",
     "//chrome/browser/web_applications:web_app_group",
     "//chrome/browser/web_applications:web_applications_test_support",
+    "//chrome/browser/web_applications/bookmark_apps",
     "//chrome/browser/web_applications/components",
     "//chrome/common",
     "//chrome/test:test_support",
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
index f4b8c25..2e683bf 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
@@ -4,40 +4,25 @@
 
 #include "chrome/browser/web_applications/extensions/bookmark_app_installation_task.h"
 
-#include <memory>
-#include <utility>
-
 #include "base/bind.h"
 #include "base/callback.h"
-#include "chrome/browser/extensions/bookmark_app_helper.h"
 #include "chrome/browser/favicon/favicon_utils.h"
 #include "chrome/browser/installable/installable_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
+#include "chrome/browser/web_applications/components/install_manager.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
-#include "chrome/browser/web_applications/components/web_app_data_retriever.h"
-#include "chrome/common/web_application_info.h"
+#include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 
 namespace extensions {
 
-namespace {
-
-std::unique_ptr<BookmarkAppHelper> BookmarkAppHelperCreateWrapper(
-    Profile* profile,
-    const WebApplicationInfo& web_app_info,
-    content::WebContents* web_contents,
-    WebappInstallSource install_source) {
-  return std::make_unique<BookmarkAppHelper>(profile, web_app_info,
-                                             web_contents, install_source);
-}
-
-}  // namespace
-
-BookmarkAppInstallationTask::Result::Result(web_app::InstallResultCode code,
-                                            base::Optional<std::string> app_id)
+BookmarkAppInstallationTask::Result::Result(
+    web_app::InstallResultCode code,
+    base::Optional<web_app::AppId> app_id)
     : code(code), app_id(std::move(app_id)) {
   DCHECK_EQ(code == web_app::InstallResultCode::kSuccess, app_id.has_value());
 }
@@ -59,121 +44,41 @@
     web_app::InstallOptions install_options)
     : profile_(profile),
       extension_ids_map_(profile_->GetPrefs()),
-      install_options_(std::move(install_options)),
-      helper_factory_(base::BindRepeating(&BookmarkAppHelperCreateWrapper)),
-      data_retriever_(std::make_unique<web_app::WebAppDataRetriever>()) {}
+      install_options_(std::move(install_options)) {}
 
 BookmarkAppInstallationTask::~BookmarkAppInstallationTask() = default;
 
 void BookmarkAppInstallationTask::Install(content::WebContents* web_contents,
-                                          ResultCallback callback) {
+                                          ResultCallback result_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  data_retriever_->GetWebApplicationInfo(
-      web_contents,
-      base::BindOnce(&BookmarkAppInstallationTask::OnGetWebApplicationInfo,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-                     web_contents));
+
+  DCHECK_EQ(web_contents->GetBrowserContext(), profile_);
+
+  auto* provider = web_app::WebAppProviderBase::GetProviderBase(profile_);
+  DCHECK(provider);
+
+  provider->install_manager().InstallWebAppWithOptions(
+      web_contents, install_options_,
+      base::BindOnce(&BookmarkAppInstallationTask::OnWebAppInstalled,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(result_callback)));
 }
 
-void BookmarkAppInstallationTask::SetBookmarkAppHelperFactoryForTesting(
-    BookmarkAppHelperFactory helper_factory) {
-  helper_factory_ = helper_factory;
-}
-
-void BookmarkAppInstallationTask::SetDataRetrieverForTesting(
-    std::unique_ptr<web_app::WebAppDataRetriever> data_retriever) {
-  data_retriever_ = std::move(data_retriever);
-}
-
-void BookmarkAppInstallationTask::OnGetWebApplicationInfo(
+void BookmarkAppInstallationTask::OnWebAppInstalled(
     ResultCallback result_callback,
-    content::WebContents* web_contents,
-    std::unique_ptr<WebApplicationInfo> web_app_info) {
-  if (!web_app_info) {
-    std::move(result_callback)
-        .Run(Result(web_app::InstallResultCode::kGetWebApplicationInfoFailed,
-                    std::string()));
-    return;
-  }
+    const web_app::AppId& app_id,
+    web_app::InstallResultCode code) {
+  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
+  const Extension* extension = registry->enabled_extensions().GetByID(app_id);
 
-  auto install_source = WebappInstallSource::COUNT;
-  switch (install_options_.install_source) {
-    case web_app::InstallSource::kInternal:
-      install_source = WebappInstallSource::INTERNAL_DEFAULT;
-      break;
-    case web_app::InstallSource::kExternalDefault:
-      install_source = WebappInstallSource::EXTERNAL_DEFAULT;
-      break;
-    case web_app::InstallSource::kExternalPolicy:
-      install_source = WebappInstallSource::EXTERNAL_POLICY;
-      break;
-    case web_app::InstallSource::kSystemInstalled:
-      install_source = WebappInstallSource::SYSTEM_DEFAULT;
-      break;
-    case web_app::InstallSource::kArc:
-      NOTREACHED();
-      break;
-  }
-  helper_ = helper_factory_.Run(profile_, *web_app_info, web_contents,
-                                install_source);
-
-  switch (install_options_.launch_container) {
-    case web_app::LaunchContainer::kDefault:
-      break;
-    case web_app::LaunchContainer::kTab:
-      helper_->set_forced_launch_type(LAUNCH_TYPE_REGULAR);
-      break;
-    case web_app::LaunchContainer::kWindow:
-      helper_->set_forced_launch_type(LAUNCH_TYPE_WINDOW);
-      break;
-  }
-
-  switch (install_options_.install_source) {
-    // TODO(nigeltao/ortuno): should these two cases lead to different
-    // Manifest::Location values: INTERNAL vs EXTERNAL_PREF_DOWNLOAD?
-    case web_app::InstallSource::kInternal:
-    case web_app::InstallSource::kExternalDefault:
-      helper_->set_is_default_app();
-      break;
-    case web_app::InstallSource::kExternalPolicy:
-      helper_->set_is_policy_installed_app();
-      break;
-    case web_app::InstallSource::kSystemInstalled:
-      helper_->set_is_system_app();
-      break;
-    case web_app::InstallSource::kArc:
-      NOTREACHED();
-      break;
-  }
-
-  if (!install_options_.create_shortcuts)
-    helper_->set_skip_shortcut_creation();
-
-  if (install_options_.bypass_service_worker_check)
-    helper_->set_bypass_service_worker_check();
-
-  if (install_options_.require_manifest)
-    helper_->set_require_manifest();
-
-  helper_->Create(base::Bind(&BookmarkAppInstallationTask::OnInstalled,
-                             weak_ptr_factory_.GetWeakPtr(),
-                             base::Passed(&result_callback)));
-}
-
-void BookmarkAppInstallationTask::OnInstalled(
-    ResultCallback result_callback,
-    const Extension* extension,
-    const WebApplicationInfo& web_app_info) {
-  if (extension) {
+  if (code == web_app::InstallResultCode::kSuccess && extension) {
     extension_ids_map_.Insert(install_options_.url, extension->id(),
                               install_options_.install_source);
     std::move(result_callback)
         .Run(Result(web_app::InstallResultCode::kSuccess, extension->id()));
-    return;
+  } else {
+    std::move(result_callback).Run(Result(code, base::nullopt));
   }
-  std::move(result_callback)
-      .Run(Result(web_app::InstallResultCode::kFailedUnknownReason,
-                  base::nullopt));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
index 32c8973..6776549 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
@@ -5,56 +5,45 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_INSTALLATION_TASK_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_INSTALLATION_TASK_H_
 
-#include <memory>
-#include <string>
-
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
-#include "chrome/browser/web_applications/components/pending_app_manager.h"
+#include "chrome/browser/web_applications/components/install_options.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h"
 
 class Profile;
-enum class WebappInstallSource;
-struct WebApplicationInfo;
 
 namespace content {
 class WebContents;
 }
 
 namespace web_app {
-class WebAppDataRetriever;
 enum class InstallResultCode;
 }
 
 namespace extensions {
 
-class BookmarkAppHelper;
-class Extension;
-
-// Class to install a BookmarkApp-based Shortcut or WebApp from a WebContents
-// or WebApplicationInfo. Can only be called from the UI thread.
+// Class to install a BookmarkApp-based Shortcut or WebApp from a WebContents.
+// Can only be called from the UI thread.
+// TODO(loyso): Erase this class and use InstallManager directly.
 class BookmarkAppInstallationTask {
  public:
+  // TODO(loyso): Use InstallManager::OnceInstallCallback directly.
   struct Result {
-    Result(web_app::InstallResultCode code, base::Optional<std::string> app_id);
+    Result(web_app::InstallResultCode code,
+           base::Optional<web_app::AppId> app_id);
     Result(Result&&);
     ~Result();
 
     const web_app::InstallResultCode code;
-    const base::Optional<std::string> app_id;
+    const base::Optional<web_app::AppId> app_id;
 
     DISALLOW_COPY_AND_ASSIGN(Result);
   };
 
   using ResultCallback = base::OnceCallback<void(Result)>;
-  using BookmarkAppHelperFactory =
-      base::RepeatingCallback<std::unique_ptr<BookmarkAppHelper>(
-          Profile*,
-          const WebApplicationInfo&,
-          content::WebContents*,
-          WebappInstallSource)>;
 
   // Ensures the tab helpers necessary for installing an app are present.
   static void CreateTabHelpers(content::WebContents* web_contents);
@@ -69,23 +58,14 @@
   virtual ~BookmarkAppInstallationTask();
 
   virtual void Install(content::WebContents* web_contents,
-                       ResultCallback callback);
+                       ResultCallback result_callback);
 
   const web_app::InstallOptions& install_options() { return install_options_; }
 
-  void SetBookmarkAppHelperFactoryForTesting(
-      BookmarkAppHelperFactory helper_factory);
-  void SetDataRetrieverForTesting(
-      std::unique_ptr<web_app::WebAppDataRetriever> data_retriever);
-
  private:
-  void OnGetWebApplicationInfo(
-      ResultCallback result_callback,
-      content::WebContents* web_contents,
-      std::unique_ptr<WebApplicationInfo> web_app_info);
-  void OnInstalled(ResultCallback result_callback,
-                   const Extension* extension,
-                   const WebApplicationInfo& web_app_info);
+  void OnWebAppInstalled(ResultCallback result_callback,
+                         const web_app::AppId& app_id,
+                         web_app::InstallResultCode code);
 
   Profile* profile_;
 
@@ -93,13 +73,6 @@
 
   const web_app::InstallOptions install_options_;
 
-  // We temporarily use a BookmarkAppHelper until the WebApp and WebShortcut
-  // installation tasks reach feature parity with BookmarkAppHelper.
-  std::unique_ptr<BookmarkAppHelper> helper_;
-  BookmarkAppHelperFactory helper_factory_;
-
-  std::unique_ptr<web_app::WebAppDataRetriever> data_retriever_;
-
   base::WeakPtrFactory<BookmarkAppInstallationTask> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BookmarkAppInstallationTask);
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
index 3d9d584..d7e59943 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
@@ -16,13 +16,16 @@
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/bookmark_app_helper.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/browser/installable/installable_data.h"
+#include "chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_data_retriever.h"
+#include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h"
 #include "chrome/browser/web_applications/test/test_data_retriever.h"
 #include "chrome/common/web_application_info.h"
@@ -97,16 +100,13 @@
 
 class BookmarkAppInstallationTaskTest : public ChromeRenderViewHostTestHarness {
  public:
-  BookmarkAppInstallationTaskTest() = default;
-  ~BookmarkAppInstallationTaskTest() override = default;
+  BookmarkAppInstallationTaskTest() {}
 
-  void OnInstallationTaskResult(base::OnceClosure quit_closure, Result result) {
-    app_installation_result_ = std::make_unique<Result>(std::move(result));
-    std::move(quit_closure).Run();
-  }
+  ~BookmarkAppInstallationTaskTest() override = default;
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+
     // CrxInstaller in BookmarkAppInstaller needs an ExtensionService, so
     // create one for the profile.
     TestExtensionSystem* test_system =
@@ -114,75 +114,82 @@
     test_system->CreateExtensionService(base::CommandLine::ForCurrentProcess(),
                                         profile()->GetPath(),
                                         false /* autoupdate_enabled */);
+    SetUpTestingFactories();
   }
 
  protected:
-  void SetTestingFactories(BookmarkAppInstallationTask* task,
-                           const GURL& app_url) {
-    WebApplicationInfo info;
-    info.app_url = app_url;
-    info.title = base::UTF8ToUTF16(kWebAppTitle);
-    task->SetDataRetrieverForTesting(
-        std::make_unique<web_app::TestDataRetriever>(
-            std::make_unique<WebApplicationInfo>(std::move(info))));
-    task->SetBookmarkAppHelperFactoryForTesting(helper_factory());
+  const GURL& app_url() const { return app_url_; }
+
+  TestBookmarkAppHelper& test_helper() {
+    DCHECK(test_helper_);
+    return *test_helper_;
   }
 
-  BookmarkAppInstallationTask::BookmarkAppHelperFactory helper_factory() {
-    return base::BindRepeating(
-        &BookmarkAppInstallationTaskTest::CreateTestBookmarkAppHelper,
-        base::Unretained(this));
-  }
-
-  bool app_installed() {
-    bool app_installed =
-        app_installation_result_->code == web_app::InstallResultCode::kSuccess;
-    EXPECT_EQ(app_installed, app_installation_result_->app_id.has_value());
-    return app_installed;
-  }
-
-  const std::string& app_id() {
-    return app_installation_result_->app_id.value();
-  }
-
-  TestBookmarkAppHelper& test_helper() { return *test_helper_; }
-
-  const Result& app_installation_result() { return *app_installation_result_; }
-
  private:
-  std::unique_ptr<BookmarkAppHelper> CreateTestBookmarkAppHelper(
-      Profile* profile,
-      const WebApplicationInfo& web_app_info,
-      content::WebContents* web_contents,
-      WebappInstallSource install_source) {
-    auto helper = std::make_unique<TestBookmarkAppHelper>(
-        profile, web_app_info, web_contents, install_source);
-    test_helper_ = helper.get();
-    return helper;
+  void SetUpTestingFactories() {
+    auto* provider = web_app::WebAppProviderBase::GetProviderBase(profile());
+    BookmarkAppInstallManager* install_manager =
+        static_cast<BookmarkAppInstallManager*>(&provider->install_manager());
+
+    install_manager->SetBookmarkAppHelperFactoryForTesting(
+        base::BindLambdaForTesting(
+            [this](Profile* profile, const WebApplicationInfo& web_app_info,
+                   content::WebContents* web_contents,
+                   WebappInstallSource install_source) {
+              auto test_helper = std::make_unique<TestBookmarkAppHelper>(
+                  profile, web_app_info, web_contents, install_source);
+              test_helper_ = test_helper.get();
+
+              return std::unique_ptr<BookmarkAppHelper>(std::move(test_helper));
+            }));
+
+    install_manager->SetDataRetrieverFactoryForTesting(
+        base::BindLambdaForTesting([this]() {
+          WebApplicationInfo info;
+          info.app_url = app_url_;
+          info.title = base::UTF8ToUTF16(kWebAppTitle);
+          auto data_retriever = std::make_unique<web_app::TestDataRetriever>(
+              std::make_unique<WebApplicationInfo>(std::move(info)));
+
+          return std::unique_ptr<web_app::WebAppDataRetriever>(
+              std::move(data_retriever));
+        }));
   }
 
-  TestBookmarkAppHelper* test_helper_;
-
-  std::unique_ptr<Result> app_installation_result_;
+  TestBookmarkAppHelper* test_helper_ = nullptr;
+  GURL app_url_{kWebAppUrl};
 
   DISALLOW_COPY_AND_ASSIGN(BookmarkAppInstallationTaskTest);
 };
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_InstallationSucceeds) {
-  const GURL app_url(kWebAppUrl);
-
   auto task = std::make_unique<BookmarkAppInstallationTask>(
       profile(),
-      web_app::InstallOptions(app_url, web_app::LaunchContainer::kDefault,
+      web_app::InstallOptions(app_url(), web_app::LaunchContainer::kDefault,
                               web_app::InstallSource::kInternal));
 
-  SetTestingFactories(task.get(), app_url);
-
+  bool callback_called = false;
   task->Install(
       web_contents(),
-      base::BindOnce(&BookmarkAppInstallationTaskTest::OnInstallationTaskResult,
-                     base::Unretained(this), base::DoNothing().Once()));
+      base::BindLambdaForTesting(
+          [&](BookmarkAppInstallationTask::Result result) {
+            base::Optional<std::string> id =
+                web_app::ExtensionIdsMap(profile()->GetPrefs())
+                    .LookupExtensionId(app_url());
+
+            EXPECT_EQ(web_app::InstallResultCode::kSuccess, result.code);
+            EXPECT_TRUE(result.app_id.has_value());
+
+            EXPECT_EQ(result.app_id.value(), id.value());
+
+            EXPECT_TRUE(test_helper().create_shortcuts());
+            EXPECT_FALSE(test_helper().forced_launch_type().has_value());
+            EXPECT_TRUE(test_helper().is_default_app());
+            EXPECT_FALSE(test_helper().is_policy_installed_app());
+            callback_called = true;
+          }));
+
   content::RunAllTasksUntilIdle();
 
   test_helper().CompleteInstallableCheck();
@@ -191,34 +198,32 @@
   test_helper().CompleteIconDownload();
   content::RunAllTasksUntilIdle();
 
-  base::Optional<std::string> id =
-      web_app::ExtensionIdsMap(profile()->GetPrefs())
-          .LookupExtensionId(app_url);
-
-  EXPECT_TRUE(app_installed());
-  EXPECT_EQ(app_id(), id.value());
-
-  EXPECT_TRUE(test_helper().create_shortcuts());
-  EXPECT_FALSE(test_helper().forced_launch_type().has_value());
-  EXPECT_TRUE(test_helper().is_default_app());
-  EXPECT_FALSE(test_helper().is_policy_installed_app());
+  EXPECT_TRUE(callback_called);
 }
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_InstallationFails) {
-  const GURL app_url(kWebAppUrl);
-
   auto task = std::make_unique<BookmarkAppInstallationTask>(
       profile(),
-      web_app::InstallOptions(app_url, web_app::LaunchContainer::kWindow,
+      web_app::InstallOptions(app_url(), web_app::LaunchContainer::kWindow,
                               web_app::InstallSource::kInternal));
 
-  SetTestingFactories(task.get(), app_url);
+  bool callback_called = false;
+  task->Install(web_contents(),
+                base::BindLambdaForTesting(
+                    [&](BookmarkAppInstallationTask::Result result) {
+                      base::Optional<std::string> id =
+                          web_app::ExtensionIdsMap(profile()->GetPrefs())
+                              .LookupExtensionId(app_url());
 
-  task->Install(
-      web_contents(),
-      base::BindOnce(&BookmarkAppInstallationTaskTest::OnInstallationTaskResult,
-                     base::Unretained(this), base::DoNothing().Once()));
+                      EXPECT_NE(web_app::InstallResultCode::kSuccess,
+                                result.code);
+                      EXPECT_FALSE(result.app_id.has_value());
+
+                      EXPECT_FALSE(id.has_value());
+                      callback_called = true;
+                    }));
+
   content::RunAllTasksUntilIdle();
 
   test_helper().CompleteInstallableCheck();
@@ -227,130 +232,140 @@
   test_helper().FailIconDownload();
   content::RunAllTasksUntilIdle();
 
-  base::Optional<std::string> id =
-      web_app::ExtensionIdsMap(profile()->GetPrefs())
-          .LookupExtensionId(app_url);
-
-  EXPECT_FALSE(app_installed());
-  EXPECT_FALSE(id.has_value());
+  EXPECT_TRUE(callback_called);
 }
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_NoShortcuts) {
-  const GURL app_url(kWebAppUrl);
-
-  web_app::InstallOptions install_options(app_url,
+  web_app::InstallOptions install_options(app_url(),
                                           web_app::LaunchContainer::kWindow,
                                           web_app::InstallSource::kInternal);
   install_options.create_shortcuts = false;
   auto task = std::make_unique<BookmarkAppInstallationTask>(
       profile(), std::move(install_options));
 
-  SetTestingFactories(task.get(), app_url);
+  bool callback_called = false;
+  task->Install(web_contents(),
+                base::BindLambdaForTesting(
+                    [&](BookmarkAppInstallationTask::Result result) {
+                      EXPECT_EQ(web_app::InstallResultCode::kSuccess,
+                                result.code);
+                      EXPECT_TRUE(result.app_id.has_value());
 
-  task->Install(
-      web_contents(),
-      base::BindOnce(&BookmarkAppInstallationTaskTest::OnInstallationTaskResult,
-                     base::Unretained(this), base::DoNothing().Once()));
+                      EXPECT_FALSE(test_helper().create_shortcuts());
+                      callback_called = true;
+                    }));
+
   content::RunAllTasksUntilIdle();
 
   test_helper().CompleteInstallation();
-
-  EXPECT_TRUE(app_installed());
-
-  EXPECT_FALSE(test_helper().create_shortcuts());
+  EXPECT_TRUE(callback_called);
 }
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_ForcedContainerWindow) {
-  const GURL app_url(kWebAppUrl);
-
   auto install_options =
-      web_app::InstallOptions(app_url, web_app::LaunchContainer::kWindow,
+      web_app::InstallOptions(app_url(), web_app::LaunchContainer::kWindow,
                               web_app::InstallSource::kInternal);
   auto task = std::make_unique<BookmarkAppInstallationTask>(
       profile(), std::move(install_options));
-  SetTestingFactories(task.get(), app_url);
 
-  task->Install(
-      web_contents(),
-      base::BindOnce(&BookmarkAppInstallationTaskTest::OnInstallationTaskResult,
-                     base::Unretained(this), base::DoNothing().Once()));
+  bool callback_called = false;
+  task->Install(web_contents(),
+                base::BindLambdaForTesting(
+                    [&](BookmarkAppInstallationTask::Result result) {
+                      EXPECT_EQ(web_app::InstallResultCode::kSuccess,
+                                result.code);
+                      EXPECT_TRUE(result.app_id.has_value());
+
+                      EXPECT_EQ(LAUNCH_TYPE_WINDOW,
+                                test_helper().forced_launch_type().value());
+                      callback_called = true;
+                    }));
+
   content::RunAllTasksUntilIdle();
 
   test_helper().CompleteInstallation();
-
-  EXPECT_TRUE(app_installed());
-  EXPECT_EQ(LAUNCH_TYPE_WINDOW, test_helper().forced_launch_type().value());
+  EXPECT_TRUE(callback_called);
 }
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_ForcedContainerTab) {
-  const GURL app_url(kWebAppUrl);
-
   auto install_options =
-      web_app::InstallOptions(app_url, web_app::LaunchContainer::kTab,
+      web_app::InstallOptions(app_url(), web_app::LaunchContainer::kTab,
                               web_app::InstallSource::kInternal);
   auto task = std::make_unique<BookmarkAppInstallationTask>(
       profile(), std::move(install_options));
-  SetTestingFactories(task.get(), app_url);
 
-  task->Install(
-      web_contents(),
-      base::BindOnce(&BookmarkAppInstallationTaskTest::OnInstallationTaskResult,
-                     base::Unretained(this), base::DoNothing().Once()));
+  bool callback_called = false;
+  task->Install(web_contents(),
+                base::BindLambdaForTesting(
+                    [&](BookmarkAppInstallationTask::Result result) {
+                      EXPECT_EQ(web_app::InstallResultCode::kSuccess,
+                                result.code);
+                      EXPECT_TRUE(result.app_id.has_value());
+
+                      EXPECT_EQ(LAUNCH_TYPE_REGULAR,
+                                test_helper().forced_launch_type().value());
+                      callback_called = true;
+                    }));
+
   content::RunAllTasksUntilIdle();
 
   test_helper().CompleteInstallation();
-
-  EXPECT_TRUE(app_installed());
-  EXPECT_EQ(LAUNCH_TYPE_REGULAR, test_helper().forced_launch_type().value());
+  EXPECT_TRUE(callback_called);
 }
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_DefaultApp) {
-  const GURL app_url(kWebAppUrl);
-
   auto install_options =
-      web_app::InstallOptions(app_url, web_app::LaunchContainer::kDefault,
+      web_app::InstallOptions(app_url(), web_app::LaunchContainer::kDefault,
                               web_app::InstallSource::kInternal);
   auto task = std::make_unique<BookmarkAppInstallationTask>(
       profile(), std::move(install_options));
-  SetTestingFactories(task.get(), app_url);
 
-  task->Install(
-      web_contents(),
-      base::BindOnce(&BookmarkAppInstallationTaskTest::OnInstallationTaskResult,
-                     base::Unretained(this), base::DoNothing().Once()));
+  bool callback_called = false;
+  task->Install(web_contents(),
+                base::BindLambdaForTesting(
+                    [&](BookmarkAppInstallationTask::Result result) {
+                      EXPECT_EQ(web_app::InstallResultCode::kSuccess,
+                                result.code);
+                      EXPECT_TRUE(result.app_id.has_value());
+
+                      EXPECT_TRUE(test_helper().is_default_app());
+                      callback_called = true;
+                    }));
+
   content::RunAllTasksUntilIdle();
 
   test_helper().CompleteInstallation();
-
-  EXPECT_TRUE(app_installed());
-  EXPECT_TRUE(test_helper().is_default_app());
+  EXPECT_TRUE(callback_called);
 }
 
 TEST_F(BookmarkAppInstallationTaskTest,
        WebAppOrShortcutFromContents_AppFromPolicy) {
-  const GURL app_url(kWebAppUrl);
-
   auto install_options =
-      web_app::InstallOptions(app_url, web_app::LaunchContainer::kDefault,
+      web_app::InstallOptions(app_url(), web_app::LaunchContainer::kDefault,
                               web_app::InstallSource::kExternalPolicy);
   auto task = std::make_unique<BookmarkAppInstallationTask>(
       profile(), std::move(install_options));
-  SetTestingFactories(task.get(), app_url);
 
-  task->Install(
-      web_contents(),
-      base::BindOnce(&BookmarkAppInstallationTaskTest::OnInstallationTaskResult,
-                     base::Unretained(this), base::DoNothing().Once()));
+  bool callback_called = false;
+  task->Install(web_contents(),
+                base::BindLambdaForTesting(
+                    [&](BookmarkAppInstallationTask::Result result) {
+                      EXPECT_EQ(web_app::InstallResultCode::kSuccess,
+                                result.code);
+                      EXPECT_TRUE(result.app_id.has_value());
+
+                      EXPECT_TRUE(test_helper().is_policy_installed_app());
+                      callback_called = true;
+                    }));
+
   content::RunAllTasksUntilIdle();
 
   test_helper().CompleteInstallation();
-
-  EXPECT_TRUE(app_installed());
-  EXPECT_TRUE(test_helper().is_policy_installed_app());
+  EXPECT_TRUE(callback_called);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc
index 754714d5..6ecb9df 100644
--- a/chrome/browser/web_applications/web_app_install_manager.cc
+++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -83,6 +83,14 @@
   NOTIMPLEMENTED();
 }
 
+void WebAppInstallManager::InstallWebAppWithOptions(
+    content::WebContents* web_contents,
+    const InstallOptions& install_options,
+    OnceInstallCallback callback) {
+  // TODO(loyso): Implement it.
+  NOTIMPLEMENTED();
+}
+
 void WebAppInstallManager::WebContentsDestroyed() {
   ReturnError(InstallResultCode::kWebContentsDestroyed);
 }
diff --git a/chrome/browser/web_applications/web_app_install_manager.h b/chrome/browser/web_applications/web_app_install_manager.h
index 5971c37..99d084a2 100644
--- a/chrome/browser/web_applications/web_app_install_manager.h
+++ b/chrome/browser/web_applications/web_app_install_manager.h
@@ -53,6 +53,9 @@
       bool no_network_install,
       WebappInstallSource install_source,
       OnceInstallCallback callback) override;
+  void InstallWebAppWithOptions(content::WebContents* web_contents,
+                                const InstallOptions& install_options,
+                                OnceInstallCallback callback) override;
 
   // WebContentsObserver:
   void WebContentsDestroyed() override;
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index 400382a2..2f5d8f9 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
+#include "device/fido/fido_authenticator.h"
 
 namespace {
 
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index f17b529..101f5ca4 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -22,6 +22,10 @@
 #include "device/fido/fido_request_handler_base.h"
 #include "device/fido/fido_transport_protocol.h"
 
+namespace device {
+class AuthenticatorGetAssertionResponse;
+}
+
 // Encapsulates the model behind the Web Authentication request dialog's UX
 // flow. This is essentially a state machine going through the states defined in
 // the `Step` enumeration.
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index c6bbbd97..9b19d3dd 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -36,6 +36,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "device/fido/fido_authenticator.h"
 
 #if defined(OS_MACOSX)
 #include "device/fido/mac/credential_metadata.h"
@@ -424,6 +425,10 @@
   weak_dialog_model_->OnBluetoothPoweredStateChanged(is_powered_on);
 }
 
+bool ChromeAuthenticatorRequestDelegate::SupportsPIN() const {
+  return true;
+}
+
 void ChromeAuthenticatorRequestDelegate::CollectPIN(
     base::Optional<int> attempts,
     base::OnceCallback<void(std::string)> provide_pin_cb) {
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
index 83fbb3c..d3651c2e 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -105,6 +105,7 @@
   void FidoAuthenticatorPairingModeChanged(base::StringPiece authenticator_id,
                                            bool is_in_pairing_mode) override;
   void BluetoothAdapterPowerChanged(bool is_powered_on) override;
+  bool SupportsPIN() const override;
   void CollectPIN(
       base::Optional<int> attempts,
       base::OnceCallback<void(std::string)> provide_pin_cb) override;
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 7457236..c6cd1b3 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -77,14 +77,6 @@
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // !defined(OS_ANDROID)
 
-// If enabled, the list of content suggestions on the New Tab page will contain
-// assets (e.g. books, pictures, audio) that the user downloaded for later use.
-// DO NOT check directly whether this feature is enabled (i.e. do not use
-// base::FeatureList::IsEnabled()). It is enabled conditionally. Use
-// |AreAssetDownloadsEnabled| instead.
-const base::Feature kAssetDownloadSuggestionsFeature{
-    "NTPAssetDownloadSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables the built-in DNS resolver.
 const base::Feature kAsyncDns {
   "AsyncDns",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 24b7948..c7b4193c 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -53,9 +53,6 @@
 extern const base::Feature kAppServiceServer;
 #endif  // !defined(OS_ANDROID)
 
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::Feature kAssetDownloadSuggestionsFeature;
-
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kAsyncDns;
 
 #if defined(OS_ANDROID)
diff --git a/chrome/common/cloud_print/cloud_print_helpers.cc b/chrome/common/cloud_print/cloud_print_helpers.cc
index c36ae44..f6a4aa0 100644
--- a/chrome/common/cloud_print/cloud_print_helpers.cc
+++ b/chrome/common/cloud_print/cloud_print_helpers.cc
@@ -10,9 +10,9 @@
 #include <memory>
 #include <utility>
 
+#include "base/hash/md5.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/values.h"
diff --git a/chrome/common/cloud_print/cloud_print_helpers_unittest.cc b/chrome/common/cloud_print/cloud_print_helpers_unittest.cc
index 111cb265..cfd1b65 100644
--- a/chrome/common/cloud_print/cloud_print_helpers_unittest.cc
+++ b/chrome/common/cloud_print/cloud_print_helpers_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/common/cloud_print/cloud_print_helpers.h"
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "chrome/common/channel_info.h"
diff --git a/chrome/common/media_router/media_source.h b/chrome/common/media_router/media_source.h
index 084dbf4..fb3dcc86 100644
--- a/chrome/common/media_router/media_source.h
+++ b/chrome/common/media_router/media_source.h
@@ -8,7 +8,7 @@
 #include <iosfwd>
 #include <string>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "url/gurl.h"
 
 // TODO(mfoltz): Right now this is a wrapper for std::string.  Factor methods
diff --git a/chrome/common/pepper_permission_util.cc b/chrome/common/pepper_permission_util.cc
index 35bf998..c448d46 100644
--- a/chrome/common/pepper_permission_util.cc
+++ b/chrome/common/pepper_permission_util.cc
@@ -7,7 +7,7 @@
 #include <vector>
 
 #include "base/command_line.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_tokenizer.h"
 #include "extensions/common/constants.h"
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 6a336bf..4f1495f 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -949,12 +949,6 @@
 const char kCurrentThemeID[] = "extensions.theme.id";
 const char kAutogeneratedThemeColor[] = "autogenerated.theme.color";
 
-// TODO(crbug.com/937956): These prefs are unused and should be removed.
-const char kCurrentThemeImages[] = "extensions.theme.images";
-const char kCurrentThemeColors[] = "extensions.theme.colors";
-const char kCurrentThemeTints[] = "extensions.theme.tints";
-const char kCurrentThemeDisplayProperties[] = "extensions.theme.properties";
-
 // Boolean pref which persists whether the extensions_ui is in developer mode
 // (showing developer packing tools and extensions details)
 const char kExtensionsUIDeveloperMode[] = "extensions.ui.developer_mode";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index f238913..6ea8b24cc 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -306,10 +306,6 @@
 extern const char kCurrentThemePackFilename[];
 extern const char kCurrentThemeID[];
 extern const char kAutogeneratedThemeColor[];
-extern const char kCurrentThemeImages[];
-extern const char kCurrentThemeColors[];
-extern const char kCurrentThemeTints[];
-extern const char kCurrentThemeDisplayProperties[];
 extern const char kExtensionsUIDeveloperMode[];
 extern const char kExtensionsUIDismissedADTPromo[];
 extern const char kExtensionCommands[];
diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc
index 9de350ed..4e87d52 100644
--- a/chrome/common/service_process_util.cc
+++ b/chrome/common/service_process_util.cc
@@ -12,10 +12,10 @@
 
 #include "base/base_switches.h"
 #include "base/command_line.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "base/path_service.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/installer/mac/third_party/bsdiff/sha1_adapter.cc b/chrome/installer/mac/third_party/bsdiff/sha1_adapter.cc
index aa628611..faacf3e 100644
--- a/chrome/installer/mac/third_party/bsdiff/sha1_adapter.cc
+++ b/chrome/installer/mac/third_party/bsdiff/sha1_adapter.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/installer/mac/third_party/bsdiff/sha1_adapter.h"
 
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 
 void SHA1(const unsigned char* data, size_t len, unsigned char* hash) {
   base::SHA1HashBytes(data, len, hash);
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 6d665d7..0f323495 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -28,9 +28,9 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
diff --git a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
index c71d9d9..fa44e67 100644
--- a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -208,6 +208,7 @@
     case ui::AXEventGenerator::Event::PLACEHOLDER_CHANGED:
     case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
     case ui::AXEventGenerator::Event::READONLY_CHANGED:
+    case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
     case ui::AXEventGenerator::Event::SET_SIZE_CHANGED:
     case ui::AXEventGenerator::Event::VALUE_MAX_CHANGED:
     case ui::AXEventGenerator::Event::VALUE_MIN_CHANGED:
diff --git a/chrome/renderer/pepper/pepper_uma_host.cc b/chrome/renderer/pepper/pepper_uma_host.cc
index f26197e..edd2751 100644
--- a/chrome/renderer/pepper/pepper_uma_host.cc
+++ b/chrome/renderer/pepper/pepper_uma_host.cc
@@ -6,8 +6,8 @@
 
 #include <stddef.h>
 
+#include "base/hash/sha1.h"
 #include "base/metrics/histogram.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/chrome/service/cloud_print/cloud_print_connector.cc b/chrome/service/cloud_print/cloud_print_connector.cc
index 34a3f53cc5..71cf5cf 100644
--- a/chrome/service/cloud_print/cloud_print_connector.cc
+++ b/chrome/service/cloud_print/cloud_print_connector.cc
@@ -12,8 +12,8 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/hash/md5.h"
 #include "base/location.h"
-#include "base/md5.h"
 #include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/service/cloud_print/cloud_print_service_helpers_unittest.cc b/chrome/service/cloud_print/cloud_print_service_helpers_unittest.cc
index 79e766f..a7c8ded 100644
--- a/chrome/service/cloud_print/cloud_print_service_helpers_unittest.cc
+++ b/chrome/service/cloud_print/cloud_print_service_helpers_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/service/cloud_print/cloud_print_service_helpers.h"
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "chrome/common/channel_info.h"
diff --git a/chrome/service/cloud_print/print_system_cups.cc b/chrome/service/cloud_print/print_system_cups.cc
index 64654eec..d38f5b1 100644
--- a/chrome/service/cloud_print/print_system_cups.cc
+++ b/chrome/service/cloud_print/print_system_cups.cc
@@ -17,11 +17,11 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/json/json_reader.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc
index 093cef0..adae1ca 100644
--- a/chrome/service/cloud_print/printer_job_handler.cc
+++ b/chrome/service/cloud_print/printer_job_handler.cc
@@ -10,9 +10,9 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/json/json_reader.h"
 #include "base/location.h"
-#include "base/md5.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/service/cloud_print/printer_job_handler_unittest.cc b/chrome/service/cloud_print/printer_job_handler_unittest.cc
index 6b6d17a..814e686 100644
--- a/chrome/service/cloud_print/printer_job_handler_unittest.cc
+++ b/chrome/service/cloud_print/printer_job_handler_unittest.cc
@@ -8,8 +8,8 @@
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
+#include "base/hash/md5.h"
 #include "base/location.h"
-#include "base/md5.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 10b3be40..13720fe 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -297,6 +297,8 @@
     sources += [
       "../browser/autofill/autofill_uitest_util.cc",
       "../browser/autofill/autofill_uitest_util.h",
+      "../browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.cc",
+      "../browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h",
       "../browser/ui/views/media_router/app_menu_test_api.h",
       "../browser/ui/views/media_router/app_menu_test_api_views.cc",
       "views/accessibility_checker.cc",
@@ -753,6 +755,7 @@
       "../browser/metrics/tab_reactivation_tracker_browsertest.cc",
       "../browser/metrics/tab_stats_tracker_browsertest.cc",
       "../browser/metrics/ukm_browsertest.cc",
+      "../browser/metrics/variations/force_field_trials_browsertest.cc",
       "../browser/navigation_predictor/navigation_predictor_browsertest.cc",
       "../browser/net/chrome_accept_header_browsertest.cc",
       "../browser/net/chrome_mojo_proxy_resolver_factory_browsertest.cc",
@@ -3714,6 +3717,7 @@
       "../browser/ui/ash/launcher/arc_app_shelf_id_unittest.cc",
       "../browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc",
       "../browser/ui/ash/launcher/launcher_context_menu_unittest.cc",
+      "../browser/ui/ash/media_client_unittest.cc",
       "../browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc",
       "../browser/ui/ash/multi_user/multi_user_util_chromeos_unittest.cc",
       "../browser/ui/ash/multi_user/multi_user_window_manager_client_impl_test_helper.cc",
@@ -5161,6 +5165,7 @@
         "../browser/ui/views/status_icons/status_tray_state_changer_interactive_uitest_win.cc",
         "../browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc",
         "../browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h",
+        "../browser/ui/views/tabs/tab_hover_card_bubble_view_interactive_uitest.cc",
         "../browser/ui/views/test/view_event_test_base.cc",
         "../browser/ui/views/test/view_event_test_base.h",
         "../browser/ui/views/test/view_event_test_platform_part.h",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index d23ca2c..eb92ec3 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -94,9 +94,9 @@
     "//third_party/android_deps:com_android_support_recyclerview_v7_java",
     "//third_party/android_deps:com_android_support_support_annotations_java",
     "//third_party/android_deps:com_android_support_support_compat_java",
+    "//third_party/android_sdk:android_test_base_java",
     "//third_party/android_support_test_runner:rules_java",
     "//third_party/android_support_test_runner:runner_java",
-    "//third_party/android_tools:android_test_base_java",
     "//third_party/gvr-android-sdk:gvr_common_java",
     "//third_party/hamcrest:hamcrest_core_java",
     "//third_party/jsr-305:jsr_305_javalib",
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index fbb8bed..22aae8c0 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -60,6 +60,7 @@
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   StatusBubble* GetStatusBubble() override;
   void UpdateTitleBar() override {}
+  void UpdateFrameColor() override {}
   void BookmarkBarStateChanged(
       BookmarkBar::AnimateChangeType change_type) override {}
   void UpdateDevTools() override {}
diff --git a/chrome/test/chromedriver/net/websocket.cc b/chrome/test/chromedriver/net/websocket.cc
index 4043e5e..5fb9034 100644
--- a/chrome/test/chromedriver/net/websocket.cc
+++ b/chrome/test/chromedriver/net/websocket.cc
@@ -15,9 +15,9 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/hash/sha1.h"
 #include "base/json/json_writer.h"
 #include "base/rand_util.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
diff --git a/chrome/test/data/android/manage_render_test_goldens.py b/chrome/test/data/android/manage_render_test_goldens.py
index 51764f1f..b1fbcdf 100755
--- a/chrome/test/data/android/manage_render_test_goldens.py
+++ b/chrome/test/data/android/manage_render_test_goldens.py
@@ -29,6 +29,9 @@
   os.path.join(
       CHROMIUM_SRC, 'components', 'test', 'data', 'vr_browser_ui',
       'render_tests'),
+  os.path.join(
+      CHROMIUM_SRC, 'components', 'test', 'data', 'vr_browser_video',
+      'render_tests'),
 ]
 
 
diff --git a/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/empty.html b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/empty.html
new file mode 100644
index 0000000..d3cdf0a
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/empty.html
@@ -0,0 +1 @@
+<title>Unmodified</title>
diff --git a/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/manifest.json b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/manifest.json
new file mode 100644
index 0000000..8f6ca01
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/manifest.json
@@ -0,0 +1,8 @@
+{
+  "name": "Service Worker-based background script",
+  "version": "0.1",
+  "manifest_version": 2,
+  "description": "Test tabs events APIs for service worker-based background scripts.",
+  "permissions": ["webRequest", "<all_urls>"],
+  "background": {"service_worker_script": "service_worker_background.js"}
+}
diff --git a/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/service_worker_background.js b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/service_worker_background.js
new file mode 100644
index 0000000..b5095fcc
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/web_request/service_worker_background.js
@@ -0,0 +1,27 @@
+// 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.
+
+var baseUrl;
+
+chrome.test.runTests([
+  function setup() {
+    chrome.test.getConfig(function(config) {
+      baseUrl = `http://a.com:${config.testServer.port}/extensions` +
+          '/api_test/service_worker/worker_based_background/web_request/';
+      chrome.test.succeed();
+    });
+  },
+  // Test the onBeforeRequest listener.
+  function testOnBeforeRequest() {
+    updateUrl = baseUrl + 'empty.html';
+    chrome.webRequest.onBeforeRequest.addListener(
+        function localListener(details) {
+          chrome.webRequest.onBeforeRequest.removeListener(localListener);
+          chrome.test.succeed();
+          return {cancel: false};
+        }, { urls: ['<all_urls>']});
+    // Create the tab.
+    chrome.tabs.create({url: updateUrl});
+  },
+]);
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_websocket_clean_close.html b/chrome/test/data/extensions/api_test/webrequest/test_websocket_clean_close.html
new file mode 100644
index 0000000..124cfd75
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/test_websocket_clean_close.html
@@ -0,0 +1,9 @@
+<!--
+ * 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.
+-->
+<body>
+<script src="framework.js"></script>
+<script src="test_websocket_clean_close.js"></script>
+</body>
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_websocket_clean_close.js b/chrome/test/data/extensions/api_test/webrequest/test_websocket_clean_close.js
new file mode 100644
index 0000000..a7648cf
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/test_websocket_clean_close.js
@@ -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.
+
+// Opens a WebSocket, busy waits for 100ms, sends a message. Verifies that the
+// close was clean. If it fails, it will fail flakily, so repeat it 10 times to
+// get a deterministic answer.
+function sendDoesntError(iteration = 0, done = undefined) {
+  let ws = new WebSocket('ws://localhost:' + testWebSocketPort +
+                         '/close-immediately');
+
+  if (!done)
+    done = chrome.test.callbackAdded();
+
+  ws.onclose = event => {
+    chrome.test.log('WebSocket ' + iteration + ' closed ' +
+                    (event.wasClean ? 'cleanly.' : 'uncleanly.'));
+    chrome.test.assertTrue(event.wasClean);
+    if (iteration < 10) {
+      ++iteration;
+      sendDoesntError(iteration, done);
+    } else {
+      done();
+    }
+  }
+
+  ws.onopen = () => {
+    chrome.test.log('WebSocket ' + iteration + ' opened.');
+    const start = performance.now();
+    while (performance.now() - start < 100) {}
+    ws.send('message');
+  };
+}
+
+chrome.tabs.getCurrent(tab => runTestsForTab([sendDoesntError], tab));
diff --git a/chrome/test/data/webui/settings/crostini_page_test.js b/chrome/test/data/webui/settings/crostini_page_test.js
index fc22c7b49..d46b901 100644
--- a/chrome/test/data/webui/settings/crostini_page_test.js
+++ b/chrome/test/data/webui/settings/crostini_page_test.js
@@ -105,8 +105,8 @@
 
     test('Sanity', function() {
       assertTrue(!!subpage.$$('#crostini-shared-paths'));
-      assertTrue(!!subpage.$$('#export'));
-      assertTrue(!!subpage.$$('#import'));
+      assertTrue(!subpage.$$('#crostini-shared-usb-devices'));
+      assertTrue(!!subpage.$$('#crostini-export-import'));
       assertTrue(!!subpage.$$('#remove'));
     });
 
@@ -120,17 +120,27 @@
     });
 
     test('Export', function() {
-      assertTrue(!!subpage.$$('#export paper-button'));
-      subpage.$$('#export paper-button').click();
-      assertEquals(
-          1, crostiniBrowserProxy.getCallCount('exportCrostiniContainer'));
+      assertTrue(!!subpage.$$('#crostini-export-import .subpage-arrow'));
+      subpage.$$('#crostini-export-import .subpage-arrow').click();
+      return flushAsync().then(() => {
+        subpage = crostiniPage.$$('settings-crostini-export-import');
+        assertTrue(!!subpage.$$('#export paper-button'));
+        subpage.$$('#export paper-button').click();
+        assertEquals(
+            1, crostiniBrowserProxy.getCallCount('exportCrostiniContainer'));
+      });
     });
 
     test('Import', function() {
-      assertTrue(!!subpage.$$('#import paper-button'));
-      subpage.$$('#import paper-button').click();
-      assertEquals(
-          1, crostiniBrowserProxy.getCallCount('importCrostiniContainer'));
+      assertTrue(!!subpage.$$('#crostini-export-import .subpage-arrow'));
+      subpage.$$('#crostini-export-import .subpage-arrow').click();
+      return flushAsync().then(() => {
+        subpage = crostiniPage.$$('settings-crostini-export-import');
+        assertTrue(!!subpage.$$('#import paper-button'));
+        subpage.$$('#import paper-button').click();
+        assertEquals(
+            1, crostiniBrowserProxy.getCallCount('importCrostiniContainer'));
+      });
     });
 
     test('Remove', function() {
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_video_controls.html b/chrome/test/data/xr/e2e_test_files/html/test_video_controls.html
new file mode 100644
index 0000000..eb1599a0
--- /dev/null
+++ b/chrome/test/data/xr/e2e_test_files/html/test_video_controls.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<!--
+Test page for verifying that video controls look and function as expected in
+the VR browser.
+-->
+<html>
+  <head>
+    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
+    <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
+  </head>
+  <body>
+    <script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script>
+    <script src="../resources/webxr_e2e.js"></script>
+    <video id="video_element" controls loop>
+      <source src="../resources/media/red_rectangle.webm" type="video/webm">
+    </video>
+    <script>
+      function fullscreenVideo() {
+        document.getElementById('video_element').requestFullscreen();
+      }
+
+      function isVideoFullscreen() {
+        return document.getElementById('video_element').fullscreenElement;
+      }
+    </script>
+    <button type="button" id="fullscreen_button" onclick="fullscreenVideo()">Fullscreen</button>
+  </body>
+</html>
diff --git a/chrome/test/data/xr/e2e_test_files/resources/media/red_rectangle.webm b/chrome/test/data/xr/e2e_test_files/resources/media/red_rectangle.webm
new file mode 100644
index 0000000..1fac013
--- /dev/null
+++ b/chrome/test/data/xr/e2e_test_files/resources/media/red_rectangle.webm
Binary files differ
diff --git a/chrome_elf/dll_hash/dll_hash.cc b/chrome_elf/dll_hash/dll_hash.cc
index 9a353855..14a15c2 100644
--- a/chrome_elf/dll_hash/dll_hash.cc
+++ b/chrome_elf/dll_hash/dll_hash.cc
@@ -4,7 +4,7 @@
 
 #include <stdint.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "chrome_elf/dll_hash/dll_hash.h"
 
 int DllNameToHash(const std::string& dll_name) {
diff --git a/chrome_elf/third_party_dlls/main_unittest.cc b/chrome_elf/third_party_dlls/main_unittest.cc
index 8666a88f3..7c3d78a 100644
--- a/chrome_elf/third_party_dlls/main_unittest.cc
+++ b/chrome_elf/third_party_dlls/main_unittest.cc
@@ -11,10 +11,10 @@
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/hash/sha1.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/scoped_native_library.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc b/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
index 4e8f62bd..f491ef565 100644
--- a/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -209,6 +209,7 @@
     case ui::AXEventGenerator::Event::PLACEHOLDER_CHANGED:
     case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
     case ui::AXEventGenerator::Event::READONLY_CHANGED:
+    case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
     case ui::AXEventGenerator::Event::SET_SIZE_CHANGED:
     case ui::AXEventGenerator::Event::VALUE_MAX_CHANGED:
     case ui::AXEventGenerator::Event::VALUE_MIN_CHANGED:
diff --git a/chromecast/renderer/resources/extensions/automation/automation_node.js b/chromecast/renderer/resources/extensions/automation/automation_node.js
index ea9f407..0383f33 100644
--- a/chromecast/renderer/resources/extensions/automation/automation_node.js
+++ b/chromecast/renderer/resources/extensions/automation/automation_node.js
@@ -3,10 +3,7 @@
 // found in the LICENSE file.
 
 var AutomationEvent = require('automationEvent').AutomationEvent;
-var automationInternal =
-    getInternalApi ?
-        getInternalApi('automationInternal') :
-        require('binding').Binding.create('automationInternal').generate();
+var automationInternal = getInternalApi('automationInternal');
 var exceptionHandler = require('uncaught_exception_handler');
 
 var natives = requireNative('automationInternal');
diff --git a/chromecast/renderer/resources/extensions/automation_custom_bindings.js b/chromecast/renderer/resources/extensions/automation_custom_bindings.js
index 170381d..a215606 100644
--- a/chromecast/renderer/resources/extensions/automation_custom_bindings.js
+++ b/chromecast/renderer/resources/extensions/automation_custom_bindings.js
@@ -5,10 +5,7 @@
 // Custom bindings for the automation API.
 var AutomationNode = require('automationNode').AutomationNode;
 var AutomationRootNode = require('automationNode').AutomationRootNode;
-var automationInternal =
-    getInternalApi ?
-        getInternalApi('automationInternal') :
-        require('binding').Binding.create('automationInternal').generate();
+var automationInternal = getInternalApi('automationInternal');
 var exceptionHandler = require('uncaught_exception_handler');
 var logging = requireNative('logging');
 var nativeAutomationInternal = requireNative('automationInternal');
diff --git a/chromeos/components/multidevice/fake_secure_message_delegate.cc b/chromeos/components/multidevice/fake_secure_message_delegate.cc
index 54b3048c..39f696df 100644
--- a/chromeos/components/multidevice/fake_secure_message_delegate.cc
+++ b/chromeos/components/multidevice/fake_secure_message_delegate.cc
@@ -9,7 +9,7 @@
 #include <algorithm>
 
 #include "base/callback.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/strings/string_util.h"
 
 namespace chromeos {
diff --git a/chromeos/components/nearby/hash_utils_impl.cc b/chromeos/components/nearby/hash_utils_impl.cc
index 9906aa5..fc115cb 100644
--- a/chromeos/components/nearby/hash_utils_impl.cc
+++ b/chromeos/components/nearby/hash_utils_impl.cc
@@ -4,7 +4,7 @@
 
 #include "chromeos/components/nearby/hash_utils_impl.h"
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/memory/ptr_util.h"
 #include "crypto/sha2.h"
 
diff --git a/chromeos/components/proximity_auth/metrics.cc b/chromeos/components/proximity_auth/metrics.cc
index 0b0d673..cb77635 100644
--- a/chromeos/components/proximity_auth/metrics.cc
+++ b/chromeos/components/proximity_auth/metrics.cc
@@ -8,8 +8,8 @@
 
 #include <algorithm>
 
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index fe31a4141..4480e11 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -62,9 +62,10 @@
 const base::Feature kFsNosymfollow{"FsNosymfollow",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enable or disable Unified Input Logic in the IME extension on Chrome OS.
-const base::Feature kImeInputLogic{"ImeInputLogic",
-                                   base::FEATURE_DISABLED_BY_DEFAULT};
+// Enable or disable Unified Input Logic for FST decocder in the IME extension
+// on Chrome OS.
+const base::Feature kImeInputLogicFst{"ImeInputLogicFst",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
 // If enabled, allows the qualified IME extension to connect to IME service.
 const base::Feature kImeServiceConnectable{"ImeServiceConnectable",
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index 51b816d0..4cf0d5c 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -36,7 +36,8 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kEnableSupervisionTransitionScreens;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kFsNosymfollow;
-COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kImeInputLogic;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kImeInputLogicFst;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kImeServiceConnectable;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
diff --git a/chromeos/dbus/auth_policy/fake_auth_policy_client.cc b/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
index f57c620..5caabaa6 100644
--- a/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
+++ b/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
@@ -8,8 +8,8 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/hash/md5.h"
 #include "base/location.h"
-#include "base/md5.h"
 #include "base/strings/string_split.h"
 #include "base/task/post_task.h"
 #include "base/threading/platform_thread.h"
diff --git a/chromeos/printing/ppd_cache_unittest.cc b/chromeos/printing/ppd_cache_unittest.cc
index f5be4e3..af9627e2 100644
--- a/chromeos/printing/ppd_cache_unittest.cc
+++ b/chromeos/printing/ppd_cache_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc
index 0e3bbe95..eec5d2f 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -31,9 +31,13 @@
 #include "chromeos/services/assistant/service.h"
 #include "chromeos/services/assistant/utils.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
+#include "libassistant/shared/internal_api/alarm_timer_manager.h"
+#include "libassistant/shared/internal_api/alarm_timer_types.h"
 #include "libassistant/shared/internal_api/assistant_manager_delegate.h"
 #include "libassistant/shared/internal_api/assistant_manager_internal.h"
 #include "libassistant/shared/public/media_manager.h"
+#include "services/media_session/public/mojom/constants.mojom.h"
+#include "services/media_session/public/mojom/media_session.mojom.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -50,6 +54,7 @@
 
 using ActionModule = assistant_client::ActionModule;
 using Resolution = assistant_client::ConversationStateListener::Resolution;
+using MediaStatus = assistant_client::MediaStatus;
 
 namespace api = ::assistant::api;
 
@@ -71,7 +76,12 @@
 constexpr char kServersideDogfoodExperimentId[] = "20347368";
 constexpr char kServersideOpenAppExperimentId[] = "39651593";
 
+constexpr char kNextTrackClientOp[] = "media.NEXT";
+constexpr char kPauseTrackClientOp[] = "media.PAUSE";
 constexpr char kPlayMediaClientOp[] = "media.PLAY_MEDIA";
+constexpr char kPrevTrackClientOp[] = "media.PREVIOUS";
+constexpr char kResumeTrackClientOp[] = "media.RESUME";
+constexpr char kStopTrackClientOp[] = "media.STOP";
 
 // The screen context query is locale independent. That is the same query
 // applies to all locales.
@@ -101,6 +111,20 @@
   }
 }
 
+ash::mojom::AssistantTimerState GetTimerState(
+    assistant_client::Timer::State state) {
+  switch (state) {
+    case assistant_client::Timer::State::UNKNOWN:
+      return ash::mojom::AssistantTimerState::kUnknown;
+    case assistant_client::Timer::State::SCHEDULED:
+      return ash::mojom::AssistantTimerState::kScheduled;
+    case assistant_client::Timer::State::PAUSED:
+      return ash::mojom::AssistantTimerState::kPaused;
+    case assistant_client::Timer::State::FIRED:
+      return ash::mojom::AssistantTimerState::kFired;
+  }
+}
+
 }  // namespace
 
 AssistantManagerServiceImpl::AssistantManagerServiceImpl(
@@ -123,6 +147,7 @@
           std::make_unique<AssistantSettingsManagerImpl>(service, this)),
       service_(service),
       background_thread_("background thread"),
+      media_controller_observer_binding_(this),
       weak_factory_(this) {
   background_thread_.Start();
   platform_api_ = std::make_unique<PlatformApiImpl>(
@@ -131,6 +156,12 @@
       network_connection_tracker);
   connector->BindInterface(ash::mojom::kServiceName,
                            &ash_message_center_controller_);
+
+  media_session::mojom::MediaControllerManagerPtr controller_manager_ptr;
+  connector->BindInterface(media_session::mojom::kServiceName,
+                           mojo::MakeRequest(&controller_manager_ptr));
+  controller_manager_ptr->CreateActiveMediaController(
+      mojo::MakeRequest(&media_controller_));
 }
 
 AssistantManagerServiceImpl::~AssistantManagerServiceImpl() {
@@ -174,6 +205,8 @@
     assistant_manager_->ResetAllDataAndShutdown();
   }
 
+  media_controller_observer_binding_.Close();
+
   assistant_manager_internal_ = nullptr;
   assistant_manager_.reset(nullptr);
 }
@@ -209,10 +242,36 @@
   // Register handler for media actions.
   assistant_manager_internal_->RegisterFallbackMediaHandler(
       [this](std::string action_name, std::string media_action_args_proto) {
-        if (action_name == kPlayMediaClientOp)
+        if (action_name == kPlayMediaClientOp) {
           OnPlayMedia(media_action_args_proto);
-        // TODO(llin): Handle other media actions.
+        } else {
+          OnMediaControlAction(action_name, media_action_args_proto);
+        }
       });
+};
+
+void AssistantManagerServiceImpl::AddMediaControllerObserver() {
+  if (features::IsMediaSessionIntegrationEnabled()) {
+    media_session::mojom::MediaControllerObserverPtr observer;
+    media_controller_observer_binding_.Bind(mojo::MakeRequest(&observer));
+    media_controller_->AddObserver(std::move(observer));
+  }
+}
+
+void AssistantManagerServiceImpl::RegisterAlarmsTimersListener() {
+  if (!assistant_manager_internal_)
+    return;
+
+  auto* alarm_timer_manager =
+      assistant_manager_internal_->GetAlarmTimerManager();
+
+  alarm_timer_manager->RegisterRingingStateListener([this]() {
+    service_->main_task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &AssistantManagerServiceImpl::OnAlarmTimerStateChangedOnMainThread,
+            weak_factory_.GetWeakPtr()));
+  });
 }
 
 void AssistantManagerServiceImpl::EnableListening(bool enable) {
@@ -599,6 +658,39 @@
   }
 }
 
+void AssistantManagerServiceImpl::OnMediaControlAction(
+    const std::string& action_name,
+    const std::string& media_action_args_proto) {
+  ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnMediaControlAction,
+                     action_name, media_action_args_proto);
+
+  if (action_name == kPauseTrackClientOp) {
+    media_controller_->Suspend();
+    return;
+  }
+
+  if (action_name == kResumeTrackClientOp) {
+    media_controller_->Resume();
+    return;
+  }
+
+  if (action_name == kNextTrackClientOp) {
+    media_controller_->NextTrack();
+    return;
+  }
+
+  if (action_name == kPrevTrackClientOp) {
+    media_controller_->PreviousTrack();
+    return;
+  }
+
+  if (action_name == kStopTrackClientOp) {
+    media_controller_->Stop();
+    return;
+  }
+  // TODO(llin): Handle media.SEEK_RELATIVE.
+}
+
 void AssistantManagerServiceImpl::OnRecognitionStateChanged(
     assistant_client::ConversationStateListener::RecognitionState state,
     const assistant_client::ConversationStateListener::RecognitionResult&
@@ -944,24 +1036,34 @@
 // assistant_client::DeviceStateListener overrides
 // Run on LibAssistant threads
 void AssistantManagerServiceImpl::OnStartFinished() {
-  service_->main_task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&AssistantManagerServiceImpl::RegisterFallbackMediaHandler,
-                     weak_factory_.GetWeakPtr()));
+  ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnStartFinished);
+
+  RegisterFallbackMediaHandler();
+  AddMediaControllerObserver();
 
   if (service_->assistant_state()->arc_play_store_enabled().has_value()) {
     SetArcPlayStoreEnabled(
         service_->assistant_state()->arc_play_store_enabled().value());
   }
+
+  if (assistant::features::IsAlarmTimerManagerEnabled()) {
+    RegisterAlarmsTimersListener();
+  }
 }
 
 void AssistantManagerServiceImpl::OnTimerSoundingStarted() {
+  if (assistant::features::IsAlarmTimerManagerEnabled())
+    return;
+
   ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnTimerSoundingStarted);
   if (service_->assistant_alarm_timer_controller())
     service_->assistant_alarm_timer_controller()->OnTimerSoundingStarted();
 }
 
 void AssistantManagerServiceImpl::OnTimerSoundingFinished() {
+  if (assistant::features::IsAlarmTimerManagerEnabled())
+    return;
+
   ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnTimerSoundingFinished);
   if (service_->assistant_alarm_timer_controller())
     service_->assistant_alarm_timer_controller()->OnTimerSoundingFinished();
@@ -1008,6 +1110,18 @@
   });
 }
 
+void AssistantManagerServiceImpl::MediaSessionInfoChanged(
+    media_session::mojom::MediaSessionInfoPtr info) {
+  media_session_info_ptr_ = std::move(info);
+  UpdateMediaState();
+}
+
+void AssistantManagerServiceImpl::MediaSessionMetadataChanged(
+    const base::Optional<media_session::MediaMetadata>& metadata) {
+  media_metadata_ = std::move(metadata);
+  UpdateMediaState();
+}
+
 void AssistantManagerServiceImpl::OnConversationTurnStartedOnMainThread(
     bool is_mic_open) {
   platform_api_->GetAudioInputProvider()
@@ -1182,6 +1296,47 @@
       [&speech_level](auto* ptr) { ptr->OnSpeechLevelUpdated(speech_level); });
 }
 
+void AssistantManagerServiceImpl::OnAlarmTimerStateChangedOnMainThread() {
+  // Currently, we only handle ringing events here. After some AlarmTimerManager
+  // API improvement, we will be handling other alarm/timer events.
+  auto* alarm_timer_manager =
+      assistant_manager_internal_->GetAlarmTimerManager();
+  // TODO(llin): Use GetAllEvents after the AlarmTimerManager API improvement is
+  // ready (b/128701326).
+  const assistant_client::AlarmTimerEvent& ringing_event =
+      alarm_timer_manager->GetRingingEvent();
+
+  switch (ringing_event.type) {
+    case assistant_client::AlarmTimerEvent::NONE:
+      service_->assistant_alarm_timer_controller()->OnAlarmTimerStateChanged(
+          nullptr);
+      break;
+    case assistant_client::AlarmTimerEvent::TIMER: {
+      ash::mojom::AssistantAlarmTimerEventPtr alarm_timer_event_ptr =
+          ash::mojom::AssistantAlarmTimerEvent::New();
+      alarm_timer_event_ptr->type =
+          ash::mojom::AssistantAlarmTimerEventType::kTimer;
+
+      if (ringing_event.type == assistant_client::AlarmTimerEvent::TIMER) {
+        alarm_timer_event_ptr->data = ash::mojom::AlarmTimerData::New();
+        ash::mojom::AssistantTimerPtr timer_data_ptr =
+            ash::mojom::AssistantTimer::New();
+        timer_data_ptr->state = GetTimerState(ringing_event.timer_data.state);
+        timer_data_ptr->timer_id = ringing_event.timer_data.timer_id;
+        alarm_timer_event_ptr->data->set_timer_data(std::move(timer_data_ptr));
+      }
+
+      service_->assistant_alarm_timer_controller()->OnAlarmTimerStateChanged(
+          std::move(alarm_timer_event_ptr));
+      break;
+    }
+    case assistant_client::AlarmTimerEvent::ALARM:
+      // TODO(llin): Handle alarm.
+      NOTREACHED();
+      break;
+  }
+}
+
 void AssistantManagerServiceImpl::CacheScreenContext(
     CacheScreenContextCallback callback) {
   if (!IsScreenContextAllowed(service_->assistant_state())) {
@@ -1336,5 +1491,39 @@
       [](auto) {});
 }
 
+void AssistantManagerServiceImpl::UpdateMediaState() {
+  // TODO(llin): MediaSession Integrated providers (include the libassistant
+  // internal media provider) will trigger media state change event. Only
+  // update the external media status if the state changes is triggered by
+  // external providers, after the media session API for identifying the source
+  // is available.
+  MediaStatus media_status;
+
+  // Set media metadata.
+  if (media_metadata_.has_value()) {
+    media_status.metadata.title =
+        base::UTF16ToUTF8(media_metadata_.value().title);
+  }
+
+  // Set playback state.
+  media_status.playback_state = MediaStatus::IDLE;
+  if (media_session_info_ptr_ &&
+      media_session_info_ptr_->state !=
+          media_session::mojom::MediaSessionInfo::SessionState::kInactive) {
+    switch (media_session_info_ptr_->playback_state) {
+      case media_session::mojom::MediaPlaybackState::kPlaying:
+        media_status.playback_state = MediaStatus::PLAYING;
+        break;
+      case media_session::mojom::MediaPlaybackState::kPaused:
+        media_status.playback_state = MediaStatus::PAUSED;
+        break;
+    }
+  }
+
+  auto* media_manager = assistant_manager_->GetMediaManager();
+  if (media_manager)
+    media_manager->SetExternalPlaybackState(media_status);
+}
+
 }  // namespace assistant
 }  // namespace chromeos
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.h b/chromeos/services/assistant/assistant_manager_service_impl.h
index a7255d8..0d36d8a 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.h
+++ b/chromeos/services/assistant/assistant_manager_service_impl.h
@@ -26,7 +26,11 @@
 #include "libassistant/shared/internal_api/assistant_manager_delegate.h"
 #include "libassistant/shared/public/conversation_state_listener.h"
 #include "libassistant/shared/public/device_state_listener.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
 #include "services/device/public/mojom/battery_monitor.mojom.h"
+#include "services/media_session/public/mojom/media_controller.mojom.h"
+#include "services/media_session/public/mojom/media_session.mojom.h"
 #include "ui/accessibility/ax_assistant_structure.h"
 #include "ui/accessibility/mojom/ax_assistant_structure.mojom.h"
 
@@ -83,7 +87,8 @@
       public AssistantEventObserver,
       public assistant_client::ConversationStateListener,
       public assistant_client::AssistantManagerDelegate,
-      public assistant_client::DeviceStateListener {
+      public assistant_client::DeviceStateListener,
+      public media_session::mojom::MediaControllerObserver {
  public:
   // |service| owns this class and must outlive this class.
   AssistantManagerServiceImpl(
@@ -182,6 +187,17 @@
     return assistant_manager_internal_;
   }
 
+  // media_session::mojom::MediaControllerObserver overrides:
+  void MediaSessionInfoChanged(
+      media_session::mojom::MediaSessionInfoPtr info) override;
+  void MediaSessionMetadataChanged(
+      const base::Optional<media_session::MediaMetadata>& metadata) override;
+  void MediaSessionActionsChanged(
+      const std::vector<media_session::mojom::MediaSessionAction>& action)
+      override {}
+  void MediaSessionChanged(
+      const base::Optional<base::UnguessableToken>& request_id) override {}
+
  private:
   void StartAssistantInternal(const base::Optional<std::string>& access_token);
   void PostInitAssistant(base::OnceClosure post_init_callback);
@@ -219,13 +235,18 @@
           recognition_result);
   void OnRespondingStartedOnMainThread(bool is_error_response);
   void OnSpeechLevelUpdatedOnMainThread(const float speech_level);
+  void OnAlarmTimerStateChangedOnMainThread();
   void OnModifySettingsAction(const std::string& modify_setting_args_proto);
   void OnOpenMediaAndroidIntentOnMainThread(
       const std::string play_media_args_proto,
       action::AndroidAppInfo* android_app_info);
   void OnPlayMedia(const std::string play_media_args_proto);
+  void OnMediaControlAction(const std::string& action_name,
+                            const std::string& media_action_args_proto);
 
   void RegisterFallbackMediaHandler();
+  void AddMediaControllerObserver();
+  void RegisterAlarmsTimersListener();
 
   void CacheAssistantStructure(
       base::OnceClosure on_done,
@@ -252,6 +273,8 @@
   // be sent back in the second round (recorded as kDeviceAction).
   void RecordQueryResponseTypeUMA();
 
+  void UpdateMediaState();
+
   State state_ = State::STOPPED;
   std::unique_ptr<AssistantMediaSession> media_session_;
   std::unique_ptr<PlatformApiImpl> platform_api_;
@@ -272,6 +295,7 @@
   mojo::InterfacePtrSet<mojom::AssistantInteractionSubscriber>
       interaction_subscribers_;
   ash::mojom::AshMessageCenterControllerPtr ash_message_center_controller_;
+  media_session::mojom::MediaControllerPtr media_controller_;
 
   Service* service_;  // unowned.
 
@@ -292,6 +316,15 @@
 
   bool is_first_client_discourse_context_query_ = true;
 
+  mojo::Binding<media_session::mojom::MediaControllerObserver>
+      media_controller_observer_binding_;
+
+  // Info associated to the active media session.
+  media_session::mojom::MediaSessionInfoPtr media_session_info_ptr_;
+  // The metadata for the active media session. It can be null to be reset, e.g.
+  // the media that was being played has been stopped.
+  base::Optional<media_session::MediaMetadata> media_metadata_ = base::nullopt;
+
   base::WeakPtrFactory<AssistantManagerServiceImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AssistantManagerServiceImpl);
diff --git a/chromeos/services/assistant/public/features.cc b/chromeos/services/assistant/public/features.cc
index f777951..2992022 100644
--- a/chromeos/services/assistant/public/features.cc
+++ b/chromeos/services/assistant/public/features.cc
@@ -50,6 +50,9 @@
 const base::Feature kTimerTicks{"ChromeOSAssistantTimerTicks",
                                 base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kEnableAssistantAlarmTimerManager{
+    "EnableAssistantAlarmTimerManager", base::FEATURE_ENABLED_BY_DEFAULT};
+
 const base::Feature kEnablePowerManager{"ChromeOSAssistantEnablePowerManager",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -62,6 +65,14 @@
 const base::Feature kScreenContextQuery{"ChromeOSAssistantScreenContextQuery",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kEnableMediaSessionIntegration{
+    "AssistantEnableMediaSessionIntegration",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsAlarmTimerManagerEnabled() {
+  return base::FeatureList::IsEnabled(kEnableAssistantAlarmTimerManager);
+}
+
 bool IsAppSupportEnabled() {
   return base::FeatureList::IsEnabled(
       assistant::features::kAssistantAppSupport);
@@ -91,6 +102,10 @@
   return base::FeatureList::IsEnabled(kAssistantKeyRemapping);
 }
 
+bool IsMediaSessionIntegrationEnabled() {
+  return base::FeatureList::IsEnabled(kEnableMediaSessionIntegration);
+}
+
 bool IsPowerManagerEnabled() {
   return base::FeatureList::IsEnabled(kEnablePowerManager);
 }
diff --git a/chromeos/services/assistant/public/features.h b/chromeos/services/assistant/public/features.h
index abd109c..bdaf6dd3 100644
--- a/chromeos/services/assistant/public/features.h
+++ b/chromeos/services/assistant/public/features.h
@@ -48,6 +48,10 @@
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kEnableDspHotword;
 
+// Enables MediaSession Integration.
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
+extern const base::Feature kEnableMediaSessionIntegration;
+
 // Enables stereo audio input.
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kEnableStereoAudioInput;
@@ -56,6 +60,10 @@
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kTimerNotification;
 
+// Enables Assistant alarm timer manager integration.
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
+extern const base::Feature kEnableAssistantAlarmTimerManager;
+
 // Enables power management features i.e. Wake locks and wake up alarms.
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kEnablePowerManager;
@@ -76,6 +84,8 @@
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kAssistantKeyRemapping;
 
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsAlarmTimerManagerEnabled();
+
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsAppSupportEnabled();
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsAudioEraserEnabled();
@@ -91,6 +101,9 @@
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsKeyRemappingEnabled();
 
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
+bool IsMediaSessionIntegrationEnabled();
+
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsPowerManagerEnabled();
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsRoutinesEnabled();
diff --git a/chromeos/services/ime/public/cpp/shared_lib/interfaces.h b/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
index e1eb5e8..3a75944 100644
--- a/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
+++ b/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
@@ -59,6 +59,71 @@
 namespace chromeos {
 namespace ime {
 
+// Callback upon async completion of DownloadToFile(), passing the originally
+// issued |request_id| (as returned by DownloadToFile()) and an |error_code| (as
+// defined at
+// https://cs.chromium.org/chromium/src/net/base/net_error_list.h?rcl=f9c935b73381772d508eebba1e216c437139d475).
+typedef void (*DownloadCallback)(int request_id, int status_code);
+
+// Based on RequestPriority defined at
+// https://cs.chromium.org/chromium/src/net/base/request_priority.h?rcl=f9c935b73381772d508eebba1e216c437139d475
+enum DownloadPriority {
+  THROTTLED = 0,
+  MINIMUM_PRIORITY = THROTTLED,
+  IDLE = 1,
+  LOWEST = 2,
+  DEFAULT_PRIORITY = LOWEST,
+  LOW = 3,
+  MEDIUM = 4,
+  HIGHEST = 5,
+  MAXIMUM_PRIORITY = HIGHEST,
+};
+
+// Extendable extra options for a download.
+struct DownloadOptions {
+  // Duration (in milliseconds) to wait before giving up on the download and
+  // considering it an error. Negative value means it can take indefinitely.
+  long timeout_ms;
+
+  // Priority level for the download.
+  DownloadPriority priority;
+
+  // Max number of times to retry a download (exclusive of the initial attempt).
+  unsigned int max_retries;
+
+  // Always add more stuff at the end only. Just like protobuf, refrain from
+  // deleting or re-ordering for maximal API stability and backward
+  // compatibility. Simply mark fields as "deprecated" if need be.
+};
+
+// Provides CrOS network download service to the shared library.
+class Downloader {
+ protected:
+  virtual ~Downloader() = default;
+
+ public:
+  // Download data from the given |url| and store into a file located at the
+  // given |file_path|, using the specified download |options|. The method
+  // returns a |request_id| (unique among those issued by the same Downloader),
+  // while actual download operation takes place asynchronously. Upon async
+  // completion of the download (either success or failure), the given
+  // |callback| function will be invoked, passing a matching |request_id| and
+  // the status via an |error_code|. All arguments are const and completely
+  // owned by the caller at all times; they should remain alive till the sync
+  // return of this method.
+  virtual int DownloadToFile(const char* url,
+                             const DownloadOptions& options,
+                             const char* file_path,
+                             DownloadCallback callback) = 0;
+
+  // Cancel the download whose |request_id| is given (|request_id| is issued
+  // in the return value of each DownloadToFile() call). The callback of a
+  // cancelled download will never be invoked. If the |request_id| is invalid
+  // or belongs to an already completed download (either success or failure),
+  // this method will just no-op.
+  virtual void Cancel(int request_id) = 0;
+};
+
 // This defines the `Platform` interface, which is used throughout the shared
 // library to manage platform-specific data/operations.
 //
@@ -86,7 +151,12 @@
   // is only accessible to the user itself.
   virtual const char* GetImeUserHomeDir() = 0;
 
-  // TODO(https://crbug.com/837156): Provide Downloader/Logger for main entry.
+  // Get the Downloader that provides CrOS network download service. Ownership
+  // of the returned Downloader instance is never transferred, i.e. it remains
+  // owned by the IME service / Platform at all times.
+  virtual Downloader* GetDownloader() = 0;
+  
+  // TODO(https://crbug.com/837156): Provide Logger for main entry.
 };
 
 // The wrapper of Mojo InterfacePtr on an IME client.
diff --git a/chromeos/services/secure_channel/device_id_pair.cc b/chromeos/services/secure_channel/device_id_pair.cc
index 482522b..1fc0387 100644
--- a/chromeos/services/secure_channel/device_id_pair.cc
+++ b/chromeos/services/secure_channel/device_id_pair.cc
@@ -6,7 +6,7 @@
 
 #include <functional>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "chromeos/components/multidevice/remote_device_ref.h"
 
 namespace chromeos {
diff --git a/components/account_id/account_id.h b/components/account_id/account_id.h
index d673815..8f56e65 100644
--- a/components/account_id/account_id.h
+++ b/components/account_id/account_id.h
@@ -7,6 +7,7 @@
 
 #include <stddef.h>
 
+#include <functional>
 #include <ostream>
 #include <string>
 
diff --git a/components/arc/common/file_system.mojom b/components/arc/common/file_system.mojom
index 938ddb7..c667839 100644
--- a/components/arc/common/file_system.mojom
+++ b/components/arc/common/file_system.mojom
@@ -159,6 +159,21 @@
   // Directory path to be initially opened when the file selector is launched.
   // Corresponds to DocumentsContract.EXTRA_INITIAL_URI.
   string initial_content_uri;
+
+  // DocumentPath representation for initial URI.
+  // Filled only when DocumentsContract.EXTRA_INITIAL_URI points to a document
+  // served by a DocumentsProvider.
+  DocumentPath? initial_document_path;
+};
+
+// Represents a path to a document served by a DocumentsProvider.
+struct DocumentPath {
+  // Authority of the document provider.
+  string authority;
+
+  // List of document ID from the root document to the child document.
+  // This should at least contain root document ID.
+  array<string> path;
 };
 
 // Result for SelectFilesRequest.
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index ab576415..2d3c17c4 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -12,11 +12,11 @@
 #include <set>
 
 #include "base/guid.h"
+#include "base/hash/sha1.h"
 #include "base/i18n/case_conversion.h"
 #include "base/i18n/char_iterator.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index 3cc21a09..86f17c89 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -206,6 +206,12 @@
 
 AutofillWalletSyncableService::~AutofillWalletSyncableService() {}
 
+void AutofillWalletSyncableService::WaitUntilReadyToSync(
+    base::OnceClosure done) {
+  // Not used in the legacy directory-based architecture.
+  NOTREACHED();
+}
+
 syncer::SyncMergeResult AutofillWalletSyncableService::MergeDataAndStartSyncing(
     syncer::ModelType type,
     const syncer::SyncDataList& initial_sync_data,
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
index e8c130d..9d3ff000 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
+++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
@@ -35,6 +35,7 @@
   ~AutofillWalletSyncableService() override;
 
   // syncer::SyncableService implementation.
+  void WaitUntilReadyToSync(base::OnceClosure done) override;
   syncer::SyncMergeResult MergeDataAndStartSyncing(
       syncer::ModelType type,
       const syncer::SyncDataList& initial_sync_data,
diff --git a/components/autofill/core/common/signatures_util.cc b/components/autofill/core/common/signatures_util.cc
index df549b9..46498ce 100644
--- a/components/autofill/core/common/signatures_util.cc
+++ b/components/autofill/core/common/signatures_util.cc
@@ -6,7 +6,7 @@
 
 #include <cctype>
 
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/common/autofill_util.h"
diff --git a/components/bookmarks/browser/bookmark_codec.h b/components/bookmarks/browser/bookmark_codec.h
index e3fee209..45f9283 100644
--- a/components/bookmarks/browser/bookmark_codec.h
+++ b/components/bookmarks/browser/bookmark_codec.h
@@ -11,8 +11,8 @@
 #include <set>
 #include <string>
 
+#include "base/hash/md5.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/strings/string16.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 
diff --git a/components/consent_auditor/consent_auditor_impl_unittest.cc b/components/consent_auditor/consent_auditor_impl_unittest.cc
index 8a8cc9fe..d8cf416 100644
--- a/components/consent_auditor/consent_auditor_impl_unittest.cc
+++ b/components/consent_auditor/consent_auditor_impl_unittest.cc
@@ -8,8 +8,8 @@
 #include <string>
 #include <utility>
 
+#include "base/hash/sha1.h"
 #include "base/memory/weak_ptr.h"
-#include "base/sha1.h"
 #include "base/test/simple_test_clock.h"
 #include "base/time/default_clock.h"
 #include "components/consent_auditor/pref_names.h"
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index d6b3e50e..94e73a7 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -763,7 +763,7 @@
       "//base:base_java",
       "//base:base_java_test_support",
       "//net/android:net_java_test_support",
-      "//third_party/android_tools:android_test_base_java",
+      "//third_party/android_sdk:android_test_base_java",
       "//third_party/junit",
       "//third_party/netty4:netty_all_java",
     ]
@@ -843,8 +843,8 @@
       ":cronet_api_java",
       ":cronet_impl_all_java",
       ":cronet_urlconnection_impl_java",
+      "//third_party/android_sdk:android_test_base_java",
       "//third_party/android_support_test_runner:runner_java",
-      "//third_party/android_tools:android_test_base_java",
       "//third_party/hamcrest:hamcrest_core_java",
     ]
     deps += cronet_javatests_deps_to_package
@@ -879,9 +879,9 @@
       "//base:base_java_test_support",
       "//net/android:net_java",
       "//net/android:net_java_test_support",
+      "//third_party/android_sdk:android_test_base_java",
+      "//third_party/android_sdk:android_test_mock_java",
       "//third_party/android_support_test_runner:runner_java",
-      "//third_party/android_tools:android_test_base_java",
-      "//third_party/android_tools:android_test_mock_java",
       "//third_party/hamcrest:hamcrest_core_java",
       "//third_party/junit",
       "//third_party/netty-tcnative:netty-tcnative-so",
@@ -925,9 +925,9 @@
       ":cronet_impl_platform_base_java",
       ":cronet_smoketests_platform_only_apk_resources",
       "//base:base_java_test_support",
+      "//third_party/android_sdk:android_test_base_java",
+      "//third_party/android_sdk:android_test_mock_java",
       "//third_party/android_support_test_runner:runner_java",
-      "//third_party/android_tools:android_test_base_java",
-      "//third_party/android_tools:android_test_mock_java",
       "//third_party/junit",
       "//third_party/netty4:netty_all_java",
     ]
@@ -956,9 +956,9 @@
       ":cronet_test_apk_resources",
       "//base:base_java",
       "//base:base_java_test_support",
+      "//third_party/android_sdk:android_test_base_java",
+      "//third_party/android_sdk:android_test_mock_java",
       "//third_party/android_support_test_runner:runner_java",
-      "//third_party/android_tools:android_test_base_java",
-      "//third_party/android_tools:android_test_mock_java",
       "//third_party/junit",
       "//third_party/netty4:netty_all_java",
     ]
@@ -992,7 +992,7 @@
       ":cronet_javatests",
       ":cronet_test_apk_java",
       "//base:base_java",
-      "//third_party/android_tools:android_test_mock_java",
+      "//third_party/android_sdk:android_test_mock_java",
       "//third_party/junit",
     ]
 
diff --git a/components/crx_file/id_util.cc b/components/crx_file/id_util.cc
index d896ab4..a6250c1 100644
--- a/components/crx_file/id_util.cc
+++ b/components/crx_file/id_util.cc
@@ -7,7 +7,7 @@
 #include <stdint.h>
 
 #include "base/files/file_path.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index 02725fd..752d719 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -1605,7 +1605,8 @@
       base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
                  weak_ptr_factory_.GetWeakPtr());
 #if defined(OS_ANDROID)
-  if (DownloadCollectionBridge::ShouldPublishDownload(GetTargetFilePath())) {
+  if (download_type_ == TYPE_ACTIVE_DOWNLOAD &&
+      DownloadCollectionBridge::ShouldPublishDownload(GetTargetFilePath())) {
     GetDownloadTaskRunner()->PostTask(
         FROM_HERE,
         base::BindOnce(&DownloadFile::CreateIntermediateUriForPublish,
diff --git a/components/drive/chromeos/file_cache_unittest.cc b/components/drive/chromeos/file_cache_unittest.cc
index 888b23b..77dc28b 100644
--- a/components/drive/chromeos/file_cache_unittest.cc
+++ b/components/drive/chromeos/file_cache_unittest.cc
@@ -19,7 +19,7 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
diff --git a/components/drive/drive_api_util.cc b/components/drive/drive_api_util.cc
index 7de3d7e4..59fb1a0 100644
--- a/components/drive/drive_api_util.cc
+++ b/components/drive/drive_api_util.cc
@@ -10,8 +10,8 @@
 #include <string>
 
 #include "base/files/file.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
diff --git a/components/drive/drive_api_util_unittest.cc b/components/drive/drive_api_util_unittest.cc
index a9f1741fc..f49153d 100644
--- a/components/drive/drive_api_util_unittest.cc
+++ b/components/drive/drive_api_util_unittest.cc
@@ -5,7 +5,7 @@
 #include "components/drive/drive_api_util.h"
 
 #include "base/files/scoped_temp_dir.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "google_apis/drive/test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/drive/service/fake_drive_service.cc b/components/drive/service/fake_drive_service.cc
index 527856f51..6c4ebeb 100644
--- a/components/drive/service/fake_drive_service.cc
+++ b/components/drive/service/fake_drive_service.cc
@@ -13,9 +13,9 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
diff --git a/components/drive/service/fake_drive_service_unittest.cc b/components/drive/service/fake_drive_service_unittest.cc
index 2941379..49b3c63 100644
--- a/components/drive/service/fake_drive_service_unittest.cc
+++ b/components/drive/service/fake_drive_service_unittest.cc
@@ -13,7 +13,7 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/components/favicon/core/favicon_service_impl.cc b/components/favicon/core/favicon_service_impl.cc
index a95898c..ed2d4c87 100644
--- a/components/favicon/core/favicon_service_impl.cc
+++ b/components/favicon/core/favicon_service_impl.cc
@@ -9,7 +9,7 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
diff --git a/components/feed/content/feed_offline_host.cc b/components/feed/content/feed_offline_host.cc
index d1b0dfd..98b39cc 100644
--- a/components/feed/content/feed_offline_host.cc
+++ b/components/feed/content/feed_offline_host.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/feed/core/feed_scheduler_host.h"
diff --git a/components/gcm_driver/android/BUILD.gn b/components/gcm_driver/android/BUILD.gn
index ee733919..9617228b 100644
--- a/components/gcm_driver/android/BUILD.gn
+++ b/components/gcm_driver/android/BUILD.gn
@@ -15,7 +15,7 @@
   deps = [
     "//base:base_java",
     "//content/public/android:content_java",
-    "//third_party/android_tools:android_gcm_java",
+    "//third_party/android_sdk:android_gcm_java",
     "//third_party/jsr-305:jsr_305_javalib",
   ]
 
diff --git a/components/history/core/browser/BUILD.gn b/components/history/core/browser/BUILD.gn
index 347fbd3..93eda9b 100644
--- a/components/history/core/browser/BUILD.gn
+++ b/components/history/core/browser/BUILD.gn
@@ -209,6 +209,7 @@
     "history_querying_unittest.cc",
     "history_service_unittest.cc",
     "history_types_unittest.cc",
+    "sync/delete_directive_handler_unittest.cc",
     "sync/history_model_worker_unittest.cc",
     "sync/typed_url_sync_bridge_unittest.cc",
     "sync/typed_url_sync_metadata_database_unittest.cc",
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index 5d0faea..b057bbd 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -45,6 +45,7 @@
 #include "components/history/core/browser/in_memory_database.h"
 #include "components/history/core/browser/in_memory_history_backend.h"
 #include "components/history/core/browser/keyword_search_term.h"
+#include "components/history/core/browser/sync/delete_directive_handler.h"
 #include "components/history/core/browser/visit_database.h"
 #include "components/history/core/browser/visit_delegate.h"
 #include "components/history/core/browser/web_history_service.h"
@@ -943,6 +944,10 @@
                base::BindOnce(&HistoryBackend::Init, history_backend_, no_db,
                               history_database_params));
 
+  delete_directive_handler_ = std::make_unique<DeleteDirectiveHandler>(
+      base::BindRepeating(base::IgnoreResult(&HistoryService::ScheduleDBTask),
+                          base::Unretained(this)));
+
   if (visit_delegate_ && !visit_delegate_->Init(this))
     return false;
 
@@ -978,37 +983,11 @@
   return weak_ptr_factory_.GetWeakPtr();
 }
 
-syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing(
-    syncer::ModelType type,
-    const syncer::SyncDataList& initial_sync_data,
-    std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
-    std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
+base::WeakPtr<syncer::SyncableService>
+HistoryService::GetDeleteDirectivesSyncableService() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
-  delete_directive_handler_.Start(this, initial_sync_data,
-                                  std::move(sync_processor));
-  return syncer::SyncMergeResult(type);
-}
-
-void HistoryService::StopSyncing(syncer::ModelType type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
-  delete_directive_handler_.Stop();
-}
-
-syncer::SyncDataList HistoryService::GetAllSyncData(
-    syncer::ModelType type) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
-  // TODO(akalin): Keep track of existing delete directives.
-  return syncer::SyncDataList();
-}
-
-syncer::SyncError HistoryService::ProcessSyncChanges(
-    const base::Location& from_here,
-    const syncer::SyncChangeList& change_list) {
-  delete_directive_handler_.ProcessSyncChanges(this, change_list);
-  return syncer::SyncError();
+  DCHECK(delete_directive_handler_);
+  return delete_directive_handler_->AsWeakPtr();
 }
 
 std::unique_ptr<syncer::ModelTypeControllerDelegate>
@@ -1023,11 +1002,10 @@
                           base::Unretained(history_backend_.get())));
 }
 
-syncer::SyncError HistoryService::ProcessLocalDeleteDirective(
+void HistoryService::ProcessLocalDeleteDirective(
     const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return delete_directive_handler_.ProcessLocalDeleteDirective(
-      delete_directive);
+  delete_directive_handler_->ProcessLocalDeleteDirective(delete_directive);
 }
 
 void HistoryService::SetInMemoryBackend(
@@ -1114,8 +1092,8 @@
   // TODO(crbug.com/929111): This should be factored out into a separate class
   // that dispatches deletions to the proper places.
   if (web_history) {
-    delete_directive_handler_.CreateDeleteDirectives(std::set<int64_t>(),
-                                                     begin_time, end_time);
+    delete_directive_handler_->CreateDeleteDirectives(std::set<int64_t>(),
+                                                      begin_time, end_time);
 
     // Attempt online deletion from the history server, but ignore the result.
     // Deletion directives ensure that the results will eventually be deleted.
@@ -1160,7 +1138,7 @@
   // TODO(crbug.com/929111): This should be factored out into a separate class
   // that dispatches deletions to the proper places.
   if (web_history) {
-    delete_directive_handler_.CreateUrlDeleteDirective(url);
+    delete_directive_handler_->CreateUrlDeleteDirective(url);
 
     // Attempt online deletion from the history server, but ignore the result.
     // Deletion directives ensure that the results will eventually be deleted.
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index b751f28..c5c79155 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -35,9 +35,7 @@
 #include "components/favicon_base/favicon_usage_data.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/keyword_id.h"
-#include "components/history/core/browser/sync/delete_directive_handler.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "components/sync/model/syncable_service.h"
 #include "sql/init_status.h"
 #include "ui/base/page_transition_types.h"
 
@@ -60,10 +58,16 @@
 
 namespace syncer {
 class ModelTypeControllerDelegate;
+class SyncableService;
+}  // namespace syncer
+
+namespace sync_pb {
+class HistoryDeleteDirectiveSpecifics;
 }
 
 namespace history {
 
+class DeleteDirectiveHandler;
 struct DownloadRow;
 struct HistoryAddPageArgs;
 class HistoryBackend;
@@ -78,12 +82,9 @@
 class VisitDelegate;
 class WebHistoryService;
 
-// The history service records page titles, and visit times, as well as
-// (eventually) information about autocomplete.
-//
-// This service is thread safe. Each request callback is invoked in the
-// thread that made the request.
-class HistoryService : public syncer::SyncableService, public KeyedService {
+// The history service records page titles, visit times, and favicons, as well
+// as information about downloads.
+class HistoryService : public KeyedService {
  public:
   // Must call Init after construction. The empty constructor provided only for
   // unit tests. When using the full constructor, |history_client| may only be
@@ -371,9 +372,8 @@
   void DeleteLocalAndRemoteUrl(WebHistoryService* web_history, const GURL& url);
 
   // Processes the given |delete_directive| and sends it to the
-  // SyncChangeProcessor (if it exists).  Returns any error resulting
-  // from sending the delete directive to sync.
-  syncer::SyncError ProcessLocalDeleteDirective(
+  // SyncChangeProcessor (if it exists).
+  void ProcessLocalDeleteDirective(
       const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive);
 
   // Downloads -----------------------------------------------------------------
@@ -512,17 +512,9 @@
 
   base::WeakPtr<HistoryService> AsWeakPtr();
 
-  // syncer::SyncableService implementation.
-  syncer::SyncMergeResult MergeDataAndStartSyncing(
-      syncer::ModelType type,
-      const syncer::SyncDataList& initial_sync_data,
-      std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
-      std::unique_ptr<syncer::SyncErrorFactory> error_handler) override;
-  void StopSyncing(syncer::ModelType type) override;
-  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
-  syncer::SyncError ProcessSyncChanges(
-      const base::Location& from_here,
-      const syncer::SyncChangeList& change_list) override;
+  // For sync codebase only: returns the SyncableService API that implements
+  // sync datatype HISTORY_DELETE_DIRECTIVES.
+  base::WeakPtr<syncer::SyncableService> GetDeleteDirectivesSyncableService();
 
   // For sync codebase only: instantiates a controller delegate to interact with
   // TypedURLSyncBridge. Must be called from the UI thread.
@@ -872,7 +864,7 @@
   base::CallbackList<void(const std::set<GURL>&, const GURL&)>
       favicon_changed_callback_list_;
 
-  DeleteDirectiveHandler delete_directive_handler_;
+  std::unique_ptr<DeleteDirectiveHandler> delete_directive_handler_;
 
   // All vended weak pointers are invalidated in Cleanup().
   base::WeakPtrFactory<HistoryService> weak_ptr_factory_;
diff --git a/components/history/core/browser/history_service_unittest.cc b/components/history/core/browser/history_service_unittest.cc
index b98a76d..d6ed7f4 100644
--- a/components/history/core/browser/history_service_unittest.cc
+++ b/components/history/core/browser/history_service_unittest.cc
@@ -617,10 +617,6 @@
 // static
 const int HistoryDBTaskImpl::kWantInvokeCount = 2;
 
-base::Time UnixUsecToTime(int64_t usec) {
-  return base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(usec);
-}
-
 }  // namespace
 
 TEST_F(HistoryServiceTest, HistoryDBTask) {
@@ -661,277 +657,6 @@
   ASSERT_FALSE(done_invoked);
 }
 
-// Create a local delete directive and process it while sync is
-// online, and then when offline. The delete directive should be sent to sync,
-// no error should be returned for the first time, and an error should be
-// returned for the second time.
-TEST_F(HistoryServiceTest, ProcessLocalDeleteDirectiveSyncOnline) {
-  ASSERT_TRUE(history_service_.get());
-
-  const GURL test_url("http://www.google.com/");
-  for (int64_t i = 1; i <= 10; ++i) {
-    base::Time t = UnixUsecToTime(i);
-    history_service_->AddPage(test_url, t, nullptr, 0, GURL(),
-                              history::RedirectList(), ui::PAGE_TRANSITION_LINK,
-                              history::SOURCE_BROWSED, false);
-  }
-
-  sync_pb::HistoryDeleteDirectiveSpecifics delete_directive;
-  sync_pb::GlobalIdDirective* global_id_directive =
-      delete_directive.mutable_global_id_directive();
-  global_id_directive->add_global_id(
-      (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1))
-          .ToInternalValue());
-
-  syncer::FakeSyncChangeProcessor change_processor;
-
-  EXPECT_FALSE(history_service_
-                   ->MergeDataAndStartSyncing(
-                       syncer::HISTORY_DELETE_DIRECTIVES,
-                       syncer::SyncDataList(),
-                       std::unique_ptr<syncer::SyncChangeProcessor>(
-                           new syncer::SyncChangeProcessorWrapperForTest(
-                               &change_processor)),
-                       std::unique_ptr<syncer::SyncErrorFactory>())
-                   .error()
-                   .IsSet());
-
-  syncer::SyncError err =
-      history_service_->ProcessLocalDeleteDirective(delete_directive);
-  EXPECT_FALSE(err.IsSet());
-  EXPECT_EQ(1u, change_processor.changes().size());
-
-  history_service_->StopSyncing(syncer::HISTORY_DELETE_DIRECTIVES);
-  err = history_service_->ProcessLocalDeleteDirective(delete_directive);
-  EXPECT_TRUE(err.IsSet());
-  EXPECT_EQ(1u, change_processor.changes().size());
-}
-
-// Closure function that runs periodically to check result of delete directive
-// processing. Stop when timeout or processing ends indicated by the creation
-// of sync changes.
-void CheckDirectiveProcessingResult(
-    base::Time timeout,
-    const syncer::FakeSyncChangeProcessor* change_processor,
-    uint32_t num_changes) {
-  if (base::Time::Now() > timeout ||
-      change_processor->changes().size() >= num_changes) {
-    return;
-  }
-
-  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&CheckDirectiveProcessingResult, timeout,
-                                change_processor, num_changes));
-}
-
-// Create a delete directive for a few specific history entries,
-// including ones that don't exist. The expected entries should be
-// deleted.
-TEST_F(HistoryServiceTest, ProcessGlobalIdDeleteDirective) {
-  ASSERT_TRUE(history_service_.get());
-  const GURL test_url("http://www.google.com/");
-  for (int64_t i = 1; i <= 20; i++) {
-    base::Time t = UnixUsecToTime(i);
-    history_service_->AddPage(test_url, t, nullptr, 0, GURL(),
-                              history::RedirectList(), ui::PAGE_TRANSITION_LINK,
-                              history::SOURCE_BROWSED, false);
-  }
-
-  EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
-  EXPECT_EQ(20, query_url_row_.visit_count());
-
-  syncer::SyncDataList directives;
-  // 1st directive.
-  sync_pb::EntitySpecifics entity_specs;
-  sync_pb::GlobalIdDirective* global_id_directive =
-      entity_specs.mutable_history_delete_directive()
-          ->mutable_global_id_directive();
-  global_id_directive->add_global_id(
-      (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(6))
-          .ToInternalValue());
-  global_id_directive->set_start_time_usec(3);
-  global_id_directive->set_end_time_usec(10);
-  directives.push_back(syncer::SyncData::CreateRemoteData(1, entity_specs));
-
-  // 2nd directive.
-  global_id_directive->Clear();
-  global_id_directive->add_global_id(
-      (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(17))
-          .ToInternalValue());
-  global_id_directive->set_start_time_usec(13);
-  global_id_directive->set_end_time_usec(19);
-  directives.push_back(syncer::SyncData::CreateRemoteData(2, entity_specs));
-
-  syncer::FakeSyncChangeProcessor change_processor;
-  EXPECT_FALSE(history_service_
-                   ->MergeDataAndStartSyncing(
-                       syncer::HISTORY_DELETE_DIRECTIVES, directives,
-                       std::unique_ptr<syncer::SyncChangeProcessor>(
-                           new syncer::SyncChangeProcessorWrapperForTest(
-                               &change_processor)),
-                       std::unique_ptr<syncer::SyncErrorFactory>())
-                   .error()
-                   .IsSet());
-
-  // Inject a task to check status and keep message loop filled before directive
-  // processing finishes.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CheckDirectiveProcessingResult,
-                     base::Time::Now() + base::TimeDelta::FromSeconds(10),
-                     &change_processor, 2));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
-  ASSERT_EQ(5, query_url_row_.visit_count());
-  EXPECT_EQ(UnixUsecToTime(1), query_url_visits_[0].visit_time);
-  EXPECT_EQ(UnixUsecToTime(2), query_url_visits_[1].visit_time);
-  EXPECT_EQ(UnixUsecToTime(11), query_url_visits_[2].visit_time);
-  EXPECT_EQ(UnixUsecToTime(12), query_url_visits_[3].visit_time);
-  EXPECT_EQ(UnixUsecToTime(20), query_url_visits_[4].visit_time);
-
-  // Expect two sync changes for deleting processed directives.
-  const syncer::SyncChangeList& sync_changes = change_processor.changes();
-  ASSERT_EQ(2u, sync_changes.size());
-  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
-  EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
-  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
-  EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
-}
-
-// Create delete directives for time ranges.  The expected entries should be
-// deleted.
-TEST_F(HistoryServiceTest, ProcessTimeRangeDeleteDirective) {
-  ASSERT_TRUE(history_service_.get());
-  const GURL test_url("http://www.google.com/");
-  for (int64_t i = 1; i <= 10; ++i) {
-    base::Time t = UnixUsecToTime(i);
-    history_service_->AddPage(test_url, t, nullptr, 0, GURL(),
-                              history::RedirectList(), ui::PAGE_TRANSITION_LINK,
-                              history::SOURCE_BROWSED, false);
-  }
-
-  EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
-  EXPECT_EQ(10, query_url_row_.visit_count());
-
-  syncer::SyncDataList directives;
-  // 1st directive.
-  sync_pb::EntitySpecifics entity_specs;
-  sync_pb::TimeRangeDirective* time_range_directive =
-      entity_specs.mutable_history_delete_directive()
-          ->mutable_time_range_directive();
-  time_range_directive->set_start_time_usec(2);
-  time_range_directive->set_end_time_usec(5);
-  directives.push_back(syncer::SyncData::CreateRemoteData(1, entity_specs));
-
-  // 2nd directive.
-  time_range_directive->Clear();
-  time_range_directive->set_start_time_usec(8);
-  time_range_directive->set_end_time_usec(10);
-  directives.push_back(syncer::SyncData::CreateRemoteData(2, entity_specs));
-
-  syncer::FakeSyncChangeProcessor change_processor;
-  EXPECT_FALSE(history_service_
-                   ->MergeDataAndStartSyncing(
-                       syncer::HISTORY_DELETE_DIRECTIVES, directives,
-                       std::unique_ptr<syncer::SyncChangeProcessor>(
-                           new syncer::SyncChangeProcessorWrapperForTest(
-                               &change_processor)),
-                       std::unique_ptr<syncer::SyncErrorFactory>())
-                   .error()
-                   .IsSet());
-
-  // Inject a task to check status and keep message loop filled before
-  // directive processing finishes.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CheckDirectiveProcessingResult,
-                     base::Time::Now() + base::TimeDelta::FromSeconds(10),
-                     &change_processor, 2));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
-  ASSERT_EQ(3, query_url_row_.visit_count());
-  EXPECT_EQ(UnixUsecToTime(1), query_url_visits_[0].visit_time);
-  EXPECT_EQ(UnixUsecToTime(6), query_url_visits_[1].visit_time);
-  EXPECT_EQ(UnixUsecToTime(7), query_url_visits_[2].visit_time);
-
-  // Expect two sync changes for deleting processed directives.
-  const syncer::SyncChangeList& sync_changes = change_processor.changes();
-  ASSERT_EQ(2u, sync_changes.size());
-  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
-  EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
-  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
-  EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
-}
-
-// Create a delete directive for urls.  The expected entries should be
-// deleted.
-TEST_F(HistoryServiceTest, ProcessUrlDeleteDirective) {
-  ASSERT_TRUE(history_service_.get());
-  const GURL test_url1("http://www.google.com/");
-  const GURL test_url2("http://maps.google.com/");
-
-  history_service_->AddPage(test_url1, UnixUsecToTime(3), nullptr, 0, GURL(),
-                            history::RedirectList(), ui::PAGE_TRANSITION_LINK,
-                            history::SOURCE_BROWSED, false);
-  history_service_->AddPage(test_url2, UnixUsecToTime(6), nullptr, 0, GURL(),
-                            history::RedirectList(), ui::PAGE_TRANSITION_LINK,
-                            history::SOURCE_BROWSED, false);
-  history_service_->AddPage(test_url1, UnixUsecToTime(10), nullptr, 0, GURL(),
-                            history::RedirectList(), ui::PAGE_TRANSITION_LINK,
-                            history::SOURCE_BROWSED, false);
-
-  EXPECT_TRUE(QueryURL(history_service_.get(), test_url1));
-  ASSERT_EQ(2, query_url_row_.visit_count());
-  EXPECT_TRUE(QueryURL(history_service_.get(), test_url2));
-
-  // Delete the first visit of url1 and all visits of url2.
-  syncer::SyncDataList directives;
-  sync_pb::EntitySpecifics entity_specs1;
-  sync_pb::UrlDirective* url_directive =
-      entity_specs1.mutable_history_delete_directive()->mutable_url_directive();
-  url_directive->set_url(test_url1.spec());
-  url_directive->set_end_time_usec(8);
-  directives.push_back(syncer::SyncData::CreateRemoteData(1, entity_specs1));
-  sync_pb::EntitySpecifics entity_specs2;
-  url_directive =
-      entity_specs2.mutable_history_delete_directive()->mutable_url_directive();
-  url_directive->set_url(test_url2.spec());
-  url_directive->set_end_time_usec(8);
-  directives.push_back(syncer::SyncData::CreateRemoteData(2, entity_specs2));
-
-  syncer::FakeSyncChangeProcessor change_processor;
-  EXPECT_FALSE(history_service_
-                   ->MergeDataAndStartSyncing(
-                       syncer::HISTORY_DELETE_DIRECTIVES, directives,
-                       std::unique_ptr<syncer::SyncChangeProcessor>(
-                           new syncer::SyncChangeProcessorWrapperForTest(
-                               &change_processor)),
-                       std::unique_ptr<syncer::SyncErrorFactory>())
-                   .error()
-                   .IsSet());
-
-  // Inject a task to check status and keep message loop filled before
-  // directive processing finishes.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CheckDirectiveProcessingResult,
-                     base::Time::Now() + base::TimeDelta::FromSeconds(10),
-                     &change_processor, 2));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(QueryURL(history_service_.get(), test_url1));
-  EXPECT_EQ(UnixUsecToTime(10), query_url_visits_[0].visit_time);
-  EXPECT_FALSE(QueryURL(history_service_.get(), test_url2));
-
-  // Expect a sync change for deleting processed directives.
-  const syncer::SyncChangeList& sync_changes = change_processor.changes();
-  ASSERT_EQ(2u, sync_changes.size());
-  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
-  EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
-  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
-  EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
-}
-
 // Helper to add a page with specified days back in the past.
 void AddPageInThePast(HistoryService* history,
                       const std::string& url_spec,
diff --git a/components/history/core/browser/history_types.cc b/components/history/core/browser/history_types.cc
index 9c853028..1c04cfd 100644
--- a/components/history/core/browser/history_types.cc
+++ b/components/history/core/browser/history_types.cc
@@ -67,7 +67,7 @@
 
   // Recreate the map for the results_ has been replaced.
   url_to_results_.clear();
-  for(size_t i = 0; i < results_.size(); ++i)
+  for (size_t i = 0; i < results_.size(); ++i)
     AddURLUsageAtIndex(results_[i].url(), i);
 }
 
@@ -168,10 +168,13 @@
 
 // QueryURLResult -------------------------------------------------------------
 
-QueryURLResult::QueryURLResult() {}
+QueryURLResult::QueryURLResult() = default;
 
-QueryURLResult::~QueryURLResult() {
-}
+QueryURLResult::~QueryURLResult() = default;
+
+QueryURLResult::QueryURLResult(const QueryURLResult&) = default;
+
+QueryURLResult::QueryURLResult(QueryURLResult&&) = default;
 
 // MostVisitedURL --------------------------------------------------------------
 
diff --git a/components/history/core/browser/history_types.h b/components/history/core/browser/history_types.h
index 325dee1..ce166111 100644
--- a/components/history/core/browser/history_types.h
+++ b/components/history/core/browser/history_types.h
@@ -272,6 +272,8 @@
 // QueryURLResult encapsulates the result of a call to HistoryBackend::QueryURL.
 struct QueryURLResult {
   QueryURLResult();
+  QueryURLResult(const QueryURLResult&);
+  QueryURLResult(QueryURLResult&&);
   ~QueryURLResult();
 
   // Indicates whether the call to HistoryBackend::QueryURL was successfull
diff --git a/components/history/core/browser/sync/delete_directive_handler.cc b/components/history/core/browser/sync/delete_directive_handler.cc
index 25b087c..c3032bf4 100644
--- a/components/history/core/browser/sync/delete_directive_handler.cc
+++ b/components/history/core/browser/sync/delete_directive_handler.cc
@@ -18,8 +18,8 @@
 #include "base/values.h"
 #include "components/history/core/browser/history_backend.h"
 #include "components/history/core/browser/history_db_task.h"
-#include "components/history/core/browser/history_service.h"
 #include "components/sync/model/sync_change.h"
+#include "components/sync/model/sync_error_factory.h"
 #include "components/sync/protocol/history_delete_directive_specifics.pb.h"
 #include "components/sync/protocol/proto_value_conversions.h"
 #include "components/sync/protocol/sync.pb.h"
@@ -335,33 +335,12 @@
     history_backend->DeleteURLsUntil(deletions);
 }
 
-DeleteDirectiveHandler::DeleteDirectiveHandler() : weak_ptr_factory_(this) {}
+DeleteDirectiveHandler::DeleteDirectiveHandler(
+    BackendTaskScheduler backend_task_scheduler)
+    : backend_task_scheduler_(std::move(backend_task_scheduler)),
+      weak_ptr_factory_(this) {}
 
-DeleteDirectiveHandler::~DeleteDirectiveHandler() {
-  weak_ptr_factory_.InvalidateWeakPtrs();
-}
-
-void DeleteDirectiveHandler::Start(
-    HistoryService* history_service,
-    const syncer::SyncDataList& initial_sync_data,
-    std::unique_ptr<syncer::SyncChangeProcessor> sync_processor) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  sync_processor_ = std::move(sync_processor);
-  if (!initial_sync_data.empty()) {
-    // Drop processed delete directives during startup.
-    history_service->ScheduleDBTask(
-        FROM_HERE,
-        std::make_unique<DeleteDirectiveTask>(weak_ptr_factory_.GetWeakPtr(),
-                                              initial_sync_data,
-                                              DROP_AFTER_PROCESSING),
-        &internal_tracker_);
-  }
-}
-
-void DeleteDirectiveHandler::Stop() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  sync_processor_.reset();
-}
+DeleteDirectiveHandler::~DeleteDirectiveHandler() {}
 
 bool DeleteDirectiveHandler::CreateDeleteDirectives(
     const std::set<int64_t>& global_ids,
@@ -437,10 +416,46 @@
   return sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
 }
 
+syncer::SyncMergeResult DeleteDirectiveHandler::MergeDataAndStartSyncing(
+    syncer::ModelType type,
+    const syncer::SyncDataList& initial_sync_data,
+    std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
+    std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
+  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  sync_processor_ = std::move(sync_processor);
+  if (!initial_sync_data.empty()) {
+    // Drop processed delete directives during startup.
+    backend_task_scheduler_.Run(FROM_HERE,
+                                std::make_unique<DeleteDirectiveTask>(
+                                    weak_ptr_factory_.GetWeakPtr(),
+                                    initial_sync_data, DROP_AFTER_PROCESSING),
+                                &internal_tracker_);
+  }
+
+  return syncer::SyncMergeResult(type);
+}
+
+void DeleteDirectiveHandler::StopSyncing(syncer::ModelType type) {
+  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
+  DCHECK(thread_checker_.CalledOnValidThread());
+  sync_processor_.reset();
+}
+
+syncer::SyncDataList DeleteDirectiveHandler::GetAllSyncData(
+    syncer::ModelType type) const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES);
+  // TODO(akalin): Keep track of existing delete directives.
+  return syncer::SyncDataList();
+}
+
 syncer::SyncError DeleteDirectiveHandler::ProcessSyncChanges(
-    HistoryService* history_service,
+    const base::Location& from_here,
     const syncer::SyncChangeList& change_list) {
   DCHECK(thread_checker_.CalledOnValidThread());
+
   if (!sync_processor_) {
     return syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
                              "Sync is disabled.",
@@ -466,13 +481,13 @@
     // Don't drop real-time delete directive so that sync engine can detect
     // redelivered delete directives to avoid processing them again and again
     // in one chrome session.
-    history_service->ScheduleDBTask(
-        FROM_HERE,
-        std::make_unique<DeleteDirectiveTask>(weak_ptr_factory_.GetWeakPtr(),
-                                              delete_directives,
-                                              KEEP_AFTER_PROCESSING),
-        &internal_tracker_);
+    backend_task_scheduler_.Run(FROM_HERE,
+                                std::make_unique<DeleteDirectiveTask>(
+                                    weak_ptr_factory_.GetWeakPtr(),
+                                    delete_directives, KEEP_AFTER_PROCESSING),
+                                &internal_tracker_);
   }
+
   return syncer::SyncError();
 }
 
diff --git a/components/history/core/browser/sync/delete_directive_handler.h b/components/history/core/browser/sync/delete_directive_handler.h
index 84e0581..e48a91a 100644
--- a/components/history/core/browser/sync/delete_directive_handler.h
+++ b/components/history/core/browser/sync/delete_directive_handler.h
@@ -10,12 +10,14 @@
 #include <memory>
 #include <set>
 
+#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/threading/thread_checker.h"
 #include "components/sync/model/sync_change_processor.h"
 #include "components/sync/model/sync_data.h"
+#include "components/sync/model/syncable_service.h"
 
 class GURL;
 
@@ -25,21 +27,21 @@
 
 namespace history {
 
-class HistoryService;
+class HistoryDBTask;
 
 // DeleteDirectiveHandler sends delete directives created locally to sync
 // engine to propagate to other clients. It also expires local history entries
 // according to given delete directives from server.
-class DeleteDirectiveHandler {
+class DeleteDirectiveHandler : public syncer::SyncableService {
  public:
-  DeleteDirectiveHandler();
-  ~DeleteDirectiveHandler();
+  // This allows injecting HistoryService::ScheduleDBTask().
+  using BackendTaskScheduler =
+      base::RepeatingCallback<void(const base::Location& location,
+                                   std::unique_ptr<HistoryDBTask> task,
+                                   base::CancelableTaskTracker* tracker)>;
 
-  // Start/stop processing delete directives when sync is enabled/disabled.
-  void Start(HistoryService* history_service,
-             const syncer::SyncDataList& initial_sync_data,
-             std::unique_ptr<syncer::SyncChangeProcessor> sync_processor);
-  void Stop();
+  explicit DeleteDirectiveHandler(BackendTaskScheduler backend_task_scheduler);
+  ~DeleteDirectiveHandler() override;
 
   // Create delete directives for the deletion of visits identified by
   // |global_ids| (which may be empty), in the time range specified by
@@ -59,10 +61,17 @@
   syncer::SyncError ProcessLocalDeleteDirective(
       const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive);
 
-  // Expires local history entries according to delete directives from server.
+  // syncer::SyncableService implementation.
+  syncer::SyncMergeResult MergeDataAndStartSyncing(
+      syncer::ModelType type,
+      const syncer::SyncDataList& initial_sync_data,
+      std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
+      std::unique_ptr<syncer::SyncErrorFactory> error_handler) override;
+  void StopSyncing(syncer::ModelType type) override;
+  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
   syncer::SyncError ProcessSyncChanges(
-      HistoryService* history_service,
-      const syncer::SyncChangeList& change_list);
+      const base::Location& from_here,
+      const syncer::SyncChangeList& change_list) override;
 
  private:
   class DeleteDirectiveTask;
@@ -76,6 +85,7 @@
   void FinishProcessing(PostProcessingAction post_processing_action,
                         const syncer::SyncDataList& delete_directives);
 
+  const BackendTaskScheduler backend_task_scheduler_;
   base::CancelableTaskTracker internal_tracker_;
   std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
   base::ThreadChecker thread_checker_;
diff --git a/components/history/core/browser/sync/delete_directive_handler_unittest.cc b/components/history/core/browser/sync/delete_directive_handler_unittest.cc
new file mode 100644
index 0000000..8748efd
--- /dev/null
+++ b/components/history/core/browser/sync/delete_directive_handler_unittest.cc
@@ -0,0 +1,383 @@
+// 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 "components/history/core/browser/sync/delete_directive_handler.h"
+
+#include <string>
+#include <utility>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/history/core/browser/history_backend.h"
+#include "components/history/core/browser/history_backend_client.h"
+#include "components/history/core/browser/history_database_params.h"
+#include "components/history/core/browser/history_db_task.h"
+#include "components/history/core/browser/history_types.h"
+#include "components/history/core/browser/in_memory_history_backend.h"
+#include "components/history/core/test/test_history_database.h"
+#include "components/sync/model/fake_sync_change_processor.h"
+#include "components/sync/model/sync_change_processor_wrapper_for_test.h"
+#include "components/sync/model/sync_error_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace history {
+
+namespace {
+
+base::Time UnixUsecToTime(int64_t usec) {
+  return base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(usec);
+}
+
+class TestHistoryBackendDelegate : public HistoryBackend::Delegate {
+ public:
+  TestHistoryBackendDelegate() {}
+
+  void NotifyProfileError(sql::InitStatus init_status,
+                          const std::string& diagnostics) override {}
+  void SetInMemoryBackend(
+      std::unique_ptr<InMemoryHistoryBackend> backend) override {}
+  void NotifyFaviconsChanged(const std::set<GURL>& page_urls,
+                             const GURL& icon_url) override {}
+  void NotifyURLVisited(ui::PageTransition transition,
+                        const URLRow& row,
+                        const RedirectList& redirects,
+                        base::Time visit_time) override {}
+  void NotifyURLsModified(const URLRows& changed_urls) override {}
+  void NotifyURLsDeleted(DeletionInfo deletion_info) override {}
+  void NotifyKeywordSearchTermUpdated(const URLRow& row,
+                                      KeywordID keyword_id,
+                                      const base::string16& term) override {}
+  void NotifyKeywordSearchTermDeleted(URLID url_id) override {}
+  void DBLoaded() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestHistoryBackendDelegate);
+};
+
+void ScheduleDBTask(scoped_refptr<HistoryBackend> history_backend,
+                    const base::Location& location,
+                    std::unique_ptr<HistoryDBTask> task,
+                    base::CancelableTaskTracker* tracker) {
+  base::CancelableTaskTracker::IsCanceledCallback is_canceled;
+  tracker->NewTrackedTaskId(&is_canceled);
+  history_backend->ProcessDBTask(
+      std::move(task), base::ThreadTaskRunnerHandle::Get(), is_canceled);
+}
+
+// Closure function that runs periodically to check result of delete directive
+// processing. Stop when timeout or processing ends indicated by the creation
+// of sync changes.
+void CheckDirectiveProcessingResult(
+    base::Time timeout,
+    const syncer::FakeSyncChangeProcessor* change_processor,
+    uint32_t num_changes) {
+  if (base::Time::Now() > timeout ||
+      change_processor->changes().size() >= num_changes) {
+    return;
+  }
+
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&CheckDirectiveProcessingResult, timeout,
+                                change_processor, num_changes));
+}
+
+class HistoryDeleteDirectiveHandlerTest : public testing::Test {
+ public:
+  HistoryDeleteDirectiveHandlerTest()
+      : history_backend_(base::MakeRefCounted<HistoryBackend>(
+            std::make_unique<TestHistoryBackendDelegate>(),
+            /*backend_client=*/nullptr,
+            base::ThreadTaskRunnerHandle::Get())) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
+    history_backend_->Init(
+        false, TestHistoryDatabaseParamsForPath(test_dir_.GetPath()));
+
+    delete_directive_handler_ = std::make_unique<DeleteDirectiveHandler>(
+        base::BindRepeating(&ScheduleDBTask, history_backend_));
+  }
+
+  void AddPage(const GURL& url, base::Time t) {
+    history::HistoryAddPageArgs args;
+    args.url = url;
+    args.time = t;
+    history_backend_->AddPage(args);
+  }
+
+  QueryURLResult QueryURL(const GURL& url) {
+    QueryURLResult query_url_result;
+    history_backend_->QueryURL(url, /*want_visits=*/true, &query_url_result);
+    return query_url_result;
+  }
+
+  ~HistoryDeleteDirectiveHandlerTest() override { history_backend_->Closing(); }
+
+  scoped_refptr<HistoryBackend> history_backend() { return history_backend_; }
+
+  DeleteDirectiveHandler* handler() { return delete_directive_handler_.get(); }
+
+ private:
+  base::test::ScopedTaskEnvironment task_environment_;
+  base::ScopedTempDir test_dir_;
+  scoped_refptr<HistoryBackend> history_backend_;
+  std::unique_ptr<DeleteDirectiveHandler> delete_directive_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistoryDeleteDirectiveHandlerTest);
+};
+
+// Create a local delete directive and process it while sync is
+// online, and then when offline. The delete directive should be sent to sync,
+// no error should be returned for the first time, and an error should be
+// returned for the second time.
+TEST_F(HistoryDeleteDirectiveHandlerTest,
+       ProcessLocalDeleteDirectiveSyncOnline) {
+  const GURL test_url("http://www.google.com/");
+  for (int64_t i = 1; i <= 10; ++i) {
+    AddPage(test_url, UnixUsecToTime(i));
+  }
+
+  sync_pb::HistoryDeleteDirectiveSpecifics delete_directive;
+  sync_pb::GlobalIdDirective* global_id_directive =
+      delete_directive.mutable_global_id_directive();
+  global_id_directive->add_global_id(
+      (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1))
+          .ToInternalValue());
+
+  syncer::FakeSyncChangeProcessor change_processor;
+
+  EXPECT_FALSE(
+      handler()
+          ->MergeDataAndStartSyncing(
+              syncer::HISTORY_DELETE_DIRECTIVES, syncer::SyncDataList(),
+              std::make_unique<syncer::SyncChangeProcessorWrapperForTest>(
+                  &change_processor),
+              std::unique_ptr<syncer::SyncErrorFactory>())
+          .error()
+          .IsSet());
+
+  syncer::SyncError err =
+      handler()->ProcessLocalDeleteDirective(delete_directive);
+  EXPECT_FALSE(err.IsSet());
+  EXPECT_EQ(1u, change_processor.changes().size());
+
+  handler()->StopSyncing(syncer::HISTORY_DELETE_DIRECTIVES);
+  err = handler()->ProcessLocalDeleteDirective(delete_directive);
+  EXPECT_TRUE(err.IsSet());
+  EXPECT_EQ(1u, change_processor.changes().size());
+}
+
+// Create a delete directive for a few specific history entries,
+// including ones that don't exist. The expected entries should be
+// deleted.
+TEST_F(HistoryDeleteDirectiveHandlerTest, ProcessGlobalIdDeleteDirective) {
+  const GURL test_url("http://www.google.com/");
+  for (int64_t i = 1; i <= 20; i++) {
+    AddPage(test_url, UnixUsecToTime(i));
+  }
+
+  {
+    QueryURLResult query = QueryURL(test_url);
+    EXPECT_TRUE(query.success);
+    EXPECT_EQ(20, query.row.visit_count());
+  }
+
+  syncer::SyncDataList directives;
+  // 1st directive.
+  sync_pb::EntitySpecifics entity_specs;
+  sync_pb::GlobalIdDirective* global_id_directive =
+      entity_specs.mutable_history_delete_directive()
+          ->mutable_global_id_directive();
+  global_id_directive->add_global_id(
+      (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(6))
+          .ToInternalValue());
+  global_id_directive->set_start_time_usec(3);
+  global_id_directive->set_end_time_usec(10);
+  directives.push_back(syncer::SyncData::CreateRemoteData(1, entity_specs));
+
+  // 2nd directive.
+  global_id_directive->Clear();
+  global_id_directive->add_global_id(
+      (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(17))
+          .ToInternalValue());
+  global_id_directive->set_start_time_usec(13);
+  global_id_directive->set_end_time_usec(19);
+  directives.push_back(syncer::SyncData::CreateRemoteData(2, entity_specs));
+
+  syncer::FakeSyncChangeProcessor change_processor;
+  EXPECT_FALSE(handler()
+                   ->MergeDataAndStartSyncing(
+                       syncer::HISTORY_DELETE_DIRECTIVES, directives,
+                       std::unique_ptr<syncer::SyncChangeProcessor>(
+                           new syncer::SyncChangeProcessorWrapperForTest(
+                               &change_processor)),
+                       std::unique_ptr<syncer::SyncErrorFactory>())
+                   .error()
+                   .IsSet());
+
+  // Inject a task to check status and keep message loop filled before directive
+  // processing finishes.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CheckDirectiveProcessingResult,
+                     base::Time::Now() + base::TimeDelta::FromSeconds(10),
+                     &change_processor, 2));
+  base::RunLoop().RunUntilIdle();
+
+  QueryURLResult query = QueryURL(test_url);
+  EXPECT_TRUE(query.success);
+  ASSERT_EQ(5, query.row.visit_count());
+  EXPECT_EQ(UnixUsecToTime(1), query.visits[0].visit_time);
+  EXPECT_EQ(UnixUsecToTime(2), query.visits[1].visit_time);
+  EXPECT_EQ(UnixUsecToTime(11), query.visits[2].visit_time);
+  EXPECT_EQ(UnixUsecToTime(12), query.visits[3].visit_time);
+  EXPECT_EQ(UnixUsecToTime(20), query.visits[4].visit_time);
+
+  // Expect two sync changes for deleting processed directives.
+  const syncer::SyncChangeList& sync_changes = change_processor.changes();
+  ASSERT_EQ(2u, sync_changes.size());
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
+  EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
+  EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
+}
+
+// Create delete directives for time ranges.  The expected entries should be
+// deleted.
+TEST_F(HistoryDeleteDirectiveHandlerTest, ProcessTimeRangeDeleteDirective) {
+  const GURL test_url("http://www.google.com/");
+  for (int64_t i = 1; i <= 10; ++i) {
+    AddPage(test_url, UnixUsecToTime(i));
+  }
+
+  {
+    QueryURLResult query = QueryURL(test_url);
+    EXPECT_TRUE(query.success);
+    EXPECT_EQ(10, query.row.visit_count());
+  }
+
+  syncer::SyncDataList directives;
+  // 1st directive.
+  sync_pb::EntitySpecifics entity_specs;
+  sync_pb::TimeRangeDirective* time_range_directive =
+      entity_specs.mutable_history_delete_directive()
+          ->mutable_time_range_directive();
+  time_range_directive->set_start_time_usec(2);
+  time_range_directive->set_end_time_usec(5);
+  directives.push_back(syncer::SyncData::CreateRemoteData(1, entity_specs));
+
+  // 2nd directive.
+  time_range_directive->Clear();
+  time_range_directive->set_start_time_usec(8);
+  time_range_directive->set_end_time_usec(10);
+  directives.push_back(syncer::SyncData::CreateRemoteData(2, entity_specs));
+
+  syncer::FakeSyncChangeProcessor change_processor;
+  EXPECT_FALSE(handler()
+                   ->MergeDataAndStartSyncing(
+                       syncer::HISTORY_DELETE_DIRECTIVES, directives,
+                       std::unique_ptr<syncer::SyncChangeProcessor>(
+                           new syncer::SyncChangeProcessorWrapperForTest(
+                               &change_processor)),
+                       std::unique_ptr<syncer::SyncErrorFactory>())
+                   .error()
+                   .IsSet());
+
+  // Inject a task to check status and keep message loop filled before
+  // directive processing finishes.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CheckDirectiveProcessingResult,
+                     base::Time::Now() + base::TimeDelta::FromSeconds(10),
+                     &change_processor, 2));
+  base::RunLoop().RunUntilIdle();
+
+  QueryURLResult query = QueryURL(test_url);
+  EXPECT_TRUE(query.success);
+  ASSERT_EQ(3, query.row.visit_count());
+  EXPECT_EQ(UnixUsecToTime(1), query.visits[0].visit_time);
+  EXPECT_EQ(UnixUsecToTime(6), query.visits[1].visit_time);
+  EXPECT_EQ(UnixUsecToTime(7), query.visits[2].visit_time);
+
+  // Expect two sync changes for deleting processed directives.
+  const syncer::SyncChangeList& sync_changes = change_processor.changes();
+  ASSERT_EQ(2u, sync_changes.size());
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
+  EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
+  EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
+}
+
+// Create a delete directive for urls.  The expected entries should be
+// deleted.
+TEST_F(HistoryDeleteDirectiveHandlerTest, ProcessUrlDeleteDirective) {
+  const GURL test_url1("http://www.google.com/");
+  const GURL test_url2("http://maps.google.com/");
+
+  AddPage(test_url1, UnixUsecToTime(3));
+  AddPage(test_url2, UnixUsecToTime(6));
+  AddPage(test_url1, UnixUsecToTime(10));
+
+  {
+    QueryURLResult query = QueryURL(test_url1);
+    EXPECT_TRUE(query.success);
+    ASSERT_EQ(2, query.row.visit_count());
+    EXPECT_TRUE(QueryURL(test_url2).success);
+  }
+
+  // Delete the first visit of url1 and all visits of url2.
+  syncer::SyncDataList directives;
+  sync_pb::EntitySpecifics entity_specs1;
+  sync_pb::UrlDirective* url_directive =
+      entity_specs1.mutable_history_delete_directive()->mutable_url_directive();
+  url_directive->set_url(test_url1.spec());
+  url_directive->set_end_time_usec(8);
+  directives.push_back(syncer::SyncData::CreateRemoteData(1, entity_specs1));
+  sync_pb::EntitySpecifics entity_specs2;
+  url_directive =
+      entity_specs2.mutable_history_delete_directive()->mutable_url_directive();
+  url_directive->set_url(test_url2.spec());
+  url_directive->set_end_time_usec(8);
+  directives.push_back(syncer::SyncData::CreateRemoteData(2, entity_specs2));
+
+  syncer::FakeSyncChangeProcessor change_processor;
+  EXPECT_FALSE(handler()
+                   ->MergeDataAndStartSyncing(
+                       syncer::HISTORY_DELETE_DIRECTIVES, directives,
+                       std::unique_ptr<syncer::SyncChangeProcessor>(
+                           new syncer::SyncChangeProcessorWrapperForTest(
+                               &change_processor)),
+                       std::unique_ptr<syncer::SyncErrorFactory>())
+                   .error()
+                   .IsSet());
+
+  // Inject a task to check status and keep message loop filled before
+  // directive processing finishes.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CheckDirectiveProcessingResult,
+                     base::Time::Now() + base::TimeDelta::FromSeconds(10),
+                     &change_processor, 2));
+  base::RunLoop().RunUntilIdle();
+
+  QueryURLResult query = QueryURL(test_url1);
+  EXPECT_TRUE(query.success);
+  EXPECT_EQ(UnixUsecToTime(10), query.visits[0].visit_time);
+  EXPECT_FALSE(QueryURL(test_url2).success);
+
+  // Expect a sync change for deleting processed directives.
+  const syncer::SyncChangeList& sync_changes = change_processor.changes();
+  ASSERT_EQ(2u, sync_changes.size());
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
+  EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
+  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
+  EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
+}
+
+}  // namespace
+
+}  // namespace history
diff --git a/components/history/core/browser/top_sites_impl.cc b/components/history/core/browser/top_sites_impl.cc
index 610bdb9..e34c3827 100644
--- a/components/history/core/browser/top_sites_impl.cc
+++ b/components/history/core/browser/top_sites_impl.cc
@@ -12,9 +12,9 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/hash/md5.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
diff --git a/components/image_fetcher/core/cache/image_cache.cc b/components/image_fetcher/core/cache/image_cache.cc
index 14c5babb..e15db42 100644
--- a/components/image_fetcher/core/cache/image_cache.cc
+++ b/components/image_fetcher/core/cache/image_cache.cc
@@ -9,7 +9,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/task_runner_util.h"
diff --git a/components/invalidation/impl/BUILD.gn b/components/invalidation/impl/BUILD.gn
index a9e14730..c7a2de5 100644
--- a/components/invalidation/impl/BUILD.gn
+++ b/components/invalidation/impl/BUILD.gn
@@ -291,9 +291,9 @@
       "//base:base_java_test_support",
       "//components/signin/core/browser/android:java",
       "//components/sync/android:sync_java",
+      "//third_party/android_sdk:android_test_base_java",
+      "//third_party/android_sdk:android_test_runner_java",
       "//third_party/android_support_test_runner:runner_java",
-      "//third_party/android_tools:android_test_base_java",
-      "//third_party/android_tools:android_test_runner_java",
       "//third_party/cacheinvalidation:cacheinvalidation_javalib",
       "//third_party/cacheinvalidation:cacheinvalidation_proto_java",
       "//third_party/junit",
diff --git a/components/invalidation/impl/gcm_network_channel.cc b/components/invalidation/impl/gcm_network_channel.cc
index 0b97e71..6b48ba5 100644
--- a/components/invalidation/impl/gcm_network_channel.cc
+++ b/components/invalidation/impl/gcm_network_channel.cc
@@ -8,10 +8,10 @@
 
 #include "base/base64url.h"
 #include "base/bind.h"
+#include "base/hash/sha1.h"
 #include "base/i18n/time_formatting.h"
 #include "base/location.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/sha1.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/components/keyed_service/OWNERS b/components/keyed_service/OWNERS
index 10af5a5b..39557cd 100644
--- a/components/keyed_service/OWNERS
+++ b/components/keyed_service/OWNERS
@@ -1,2 +1 @@
 blundell@chromium.org
-sdefresne@chromium.org
diff --git a/components/leveldb_proto/internal/proto_database_impl.h b/components/leveldb_proto/internal/proto_database_impl.h
index 747c697..7759022 100644
--- a/components/leveldb_proto/internal/proto_database_impl.h
+++ b/components/leveldb_proto/internal/proto_database_impl.h
@@ -195,35 +195,34 @@
 }
 
 template <typename P>
-std::unique_ptr<P> ParseToProto(const std::string& serialized_entry) {
-  auto proto = std::make_unique<P>();
+bool ParseToProto(const std::string& serialized_entry, P* proto) {
   if (!proto->ParseFromString(serialized_entry)) {
     DLOG(WARNING) << "Unable to parse leveldb_proto entry";
-    proto.reset(new P);
+    *proto = P();
+    return false;
   }
-  return proto;
+  return true;
 }
 
 template <typename P,
           typename T,
           std::enable_if_t<std::is_base_of<google::protobuf::MessageLite,
                                            T>::value>* = nullptr>
-std::unique_ptr<T> ParseToClientType(const std::string& serialized_entry) {
-  return ParseToProto<T>(serialized_entry);
+bool ParseToClientType(const std::string& serialized_entry, T* output) {
+  return ParseToProto<T>(serialized_entry, output);
 }
 
 template <typename P,
           typename T,
           std::enable_if_t<!std::is_base_of<google::protobuf::MessageLite,
                                             T>::value>* = nullptr>
-std::unique_ptr<T> ParseToClientType(const std::string& serialized_entry) {
-  auto entry = std::make_unique<T>();
-  auto proto = ParseToProto<P>(serialized_entry);
-  if (!proto)
-    return entry;
+bool ParseToClientType(const std::string& serialized_entry, T* entry) {
+  P proto;
+  if (!ParseToProto<P>(serialized_entry, &proto))
+    return false;
 
-  ProtoToData(*proto, entry.get());
-  return entry;
+  ProtoToData(proto, entry);
+  return true;
 }
 
 // Update transactions need to serialize the entries to be updated on background
@@ -283,8 +282,8 @@
     entries.reset();
   } else {
     for (const auto& serialized_entry : *loaded_entries) {
-      auto entry = ParseToClientType<P, T>(serialized_entry);
-      entries->push_back(*entry);
+      entries->emplace_back(T());
+      ParseToClientType<P, T>(serialized_entry, &entries->back());
     }
   }
 
@@ -307,8 +306,8 @@
     keys_entries.reset();
   } else {
     for (const auto& pair : *loaded_entries) {
-      auto entry = ParseToClientType<P, T>(pair.second);
-      keys_entries->emplace(pair.first, *entry);
+      auto it = keys_entries->emplace(pair.first, T());
+      ParseToClientType<P, T>(pair.second, &(it.first->second));
     }
   }
 
@@ -330,10 +329,8 @@
 
   if (!success || !serialized_entry) {
     entry.reset();
-  } else {
-    entry = ParseToClientType<P, T>(*serialized_entry);
-    if (!entry)
-      success = false;
+  } else if (!ParseToClientType<P, T>(*serialized_entry, entry.get())) {
+    success = false;
   }
   callback_task_runner->PostTask(
       FROM_HERE,
diff --git a/components/leveldb_proto/internal/proto_database_impl_unittest.cc b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
index a23e195..8c026233 100644
--- a/components/leveldb_proto/internal/proto_database_impl_unittest.cc
+++ b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
@@ -27,6 +27,11 @@
 // Example struct defined by clients that can be used instead of protos.
 struct ClientStruct {
  public:
+  ClientStruct() {}
+  ClientStruct(ClientStruct&& other) {
+    id_ = std::move(other.id_);
+    data_ = std::move(other.data_);
+  }
   ~ClientStruct() = default;
 
   // The methods below are convenience methods to have a similar API as protocol
@@ -39,6 +44,9 @@
 
   std::string id_;
   std::string data_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ClientStruct);
 };
 
 void CreateData(const std::string& key,
@@ -296,7 +304,7 @@
     for (const auto& key : *entry_keys) {
       T data;
       CreateData(key, key, &data);
-      data_set->emplace_back(std::make_pair(key, data));
+      data_set->emplace_back(key, std::move(data));
     }
 
     base::RunLoop data_loop;
diff --git a/components/leveldb_proto/testing/fake_db.h b/components/leveldb_proto/testing/fake_db.h
index 8d7cba1f..0eb4340 100644
--- a/components/leveldb_proto/testing/fake_db.h
+++ b/components/leveldb_proto/testing/fake_db.h
@@ -172,8 +172,8 @@
     std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
     std::unique_ptr<std::vector<std::string>> keys_to_remove,
     Callbacks::UpdateCallback callback) {
-  for (const auto& pair : *entries_to_save)
-    (*db_)[pair.first] = pair.second;
+  for (auto& pair : *entries_to_save)
+    (*db_)[pair.first] = std::move(pair.second);
 
   for (const auto& key : *keys_to_remove)
     db_->erase(key);
diff --git a/components/metrics/environment_recorder.cc b/components/metrics/environment_recorder.cc
index 6391f61..7b6d926 100644
--- a/components/metrics/environment_recorder.cc
+++ b/components/metrics/environment_recorder.cc
@@ -5,7 +5,7 @@
 #include "components/metrics/environment_recorder.h"
 
 #include "base/base64.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
diff --git a/components/metrics/persisted_logs.cc b/components/metrics/persisted_logs.cc
index 15ef46b..f23969ec 100644
--- a/components/metrics/persisted_logs.cc
+++ b/components/metrics/persisted_logs.cc
@@ -9,8 +9,8 @@
 #include <utility>
 
 #include "base/base64.h"
+#include "base/hash/sha1.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/timer/elapsed_timer.h"
diff --git a/components/metrics/persisted_logs_unittest.cc b/components/metrics/persisted_logs_unittest.cc
index df5f365..4dce0b1 100644
--- a/components/metrics/persisted_logs_unittest.cc
+++ b/components/metrics/persisted_logs_unittest.cc
@@ -7,9 +7,9 @@
 #include <stddef.h>
 
 #include "base/base64.h"
+#include "base/hash/sha1.h"
 #include "base/macros.h"
 #include "base/rand_util.h"
-#include "base/sha1.h"
 #include "base/values.h"
 #include "components/metrics/persisted_logs_metrics_impl.h"
 #include "components/prefs/pref_registry_simple.h"
diff --git a/components/metrics/reporting_service_unittest.cc b/components/metrics/reporting_service_unittest.cc
index 31c6f88a..12c61328 100644
--- a/components/metrics/reporting_service_unittest.cc
+++ b/components/metrics/reporting_service_unittest.cc
@@ -11,8 +11,8 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/hash/sha1.h"
 #include "base/macros.h"
-#include "base/sha1.h"
 #include "base/strings/string_util.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/components/offline_pages/core/BUILD.gn b/components/offline_pages/core/BUILD.gn
index 5d19b7a..1dfd358f 100644
--- a/components/offline_pages/core/BUILD.gn
+++ b/components/offline_pages/core/BUILD.gn
@@ -32,8 +32,6 @@
     "model/clear_digest_task.h",
     "model/clear_storage_task.cc",
     "model/clear_storage_task.h",
-    "model/complete_offline_page_upgrade_task.cc",
-    "model/complete_offline_page_upgrade_task.h",
     "model/delete_page_task.cc",
     "model/delete_page_task.h",
     "model/get_pages_task.cc",
@@ -52,8 +50,6 @@
     "model/offline_page_upgrade_types.h",
     "model/persistent_page_consistency_check_task.cc",
     "model/persistent_page_consistency_check_task.h",
-    "model/start_offline_page_upgrade_task.cc",
-    "model/start_offline_page_upgrade_task.h",
     "model/startup_maintenance_task.cc",
     "model/startup_maintenance_task.h",
     "model/store_thumbnail_task.cc",
@@ -162,7 +158,6 @@
     "model/cleanup_thumbnails_task_unittest.cc",
     "model/clear_digest_task_unittest.cc",
     "model/clear_storage_task_unittest.cc",
-    "model/complete_offline_page_upgrade_task_unittest.cc",
     "model/delete_page_task_unittest.cc",
     "model/get_pages_task_unittest.cc",
     "model/get_thumbnail_task_unittest.cc",
@@ -171,7 +166,6 @@
     "model/offline_page_model_taskified_unittest.cc",
     "model/offline_page_model_utils_unittest.cc",
     "model/persistent_page_consistency_check_task_unittest.cc",
-    "model/start_offline_page_upgrade_task_unittest.cc",
     "model/startup_maintenance_task_unittest.cc",
     "model/store_thumbnail_task_unittest.cc",
     "model/update_file_path_task_unittest.cc",
diff --git a/components/offline_pages/core/model/add_page_task.cc b/components/offline_pages/core/model/add_page_task.cc
index cd4e73e..4dff380 100644
--- a/components/offline_pages/core/model/add_page_task.cc
+++ b/components/offline_pages/core/model/add_page_task.cc
@@ -39,12 +39,12 @@
                                     sql::Database* db) {
   static const char kSql[] =
       "INSERT OR IGNORE INTO offlinepages_v1"
-      " (offline_id, online_url, client_namespace, client_id, file_path,"
-      " file_size, creation_time, last_access_time, access_count,"
-      " title, original_url, request_origin, system_download_id,"
-      " file_missing_time, upgrade_attempt, digest)"
+      " (offline_id,online_url,client_namespace,client_id,file_path,"
+      "file_size,creation_time,last_access_time,access_count,"
+      "title,original_url,request_origin,system_download_id,"
+      "file_missing_time,digest)"
       " VALUES "
-      " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+      "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
 
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
   statement.BindInt64(0, item.offline_id);
@@ -61,8 +61,7 @@
   statement.BindString(11, item.request_origin);
   statement.BindInt64(12, item.system_download_id);
   statement.BindInt64(13, store_utils::ToDatabaseTime(item.file_missing_time));
-  statement.BindInt(14, item.upgrade_attempt);
-  statement.BindString(15, item.digest);
+  statement.BindString(14, item.digest);
 
   if (!statement.Run())
     return ItemActionStatus::STORE_ERROR;
diff --git a/components/offline_pages/core/model/complete_offline_page_upgrade_task.cc b/components/offline_pages/core/model/complete_offline_page_upgrade_task.cc
deleted file mode 100644
index d189bf2..0000000
--- a/components/offline_pages/core/model/complete_offline_page_upgrade_task.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/offline_pages/core/model/complete_offline_page_upgrade_task.h"
-
-#include "base/bind.h"
-#include "base/files/file_util.h"
-#include "base/system/sys_info.h"
-#include "components/offline_pages/core/offline_page_metadata_store.h"
-#include "components/offline_pages/core/offline_store_utils.h"
-#include "sql/database.h"
-#include "sql/statement.h"
-#include "sql/transaction.h"
-
-namespace offline_pages {
-
-namespace {
-
-CompleteUpgradeStatus CompleteOfflinePageUpgradeSync(
-    int64_t offline_id,
-    const base::FilePath& temporary_file_path,
-    const base::FilePath& target_file_path,
-    const std::string& digest,
-    int64_t file_size,
-    sql::Database* db) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin())
-    return CompleteUpgradeStatus::DB_ERROR;
-
-  // We need to remember the old file path, so that we can remove that file
-  // later on.
-  static const char kSql[] =
-      "SELECT file_path FROM offlinepages_v1 WHERE offline_id = ?";
-  sql::Statement select_statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  select_statement.BindInt64(0, offline_id);
-  if (!select_statement.Step()) {
-    return select_statement.Succeeded() ? CompleteUpgradeStatus::ITEM_MISSING
-                                        : CompleteUpgradeStatus::DB_ERROR;
-  }
-
-  base::FilePath old_file_path =
-      store_utils::FromDatabaseFilePath(select_statement.ColumnString(0));
-
-  // TODO(fgorski): Verify the digest and size of the temporary file.
-  // That requires moving ComputeDigest function to component and this is
-  // already in progress.
-
-  // Verify that the temporary file is there.
-  if (!base::PathExists(temporary_file_path))
-    return CompleteUpgradeStatus::TEMPORARY_FILE_MISSING;
-
-  // Verify that the target file name is not in use.
-  if (base::PathExists(target_file_path))
-    return CompleteUpgradeStatus::TARGET_FILE_NAME_IN_USE;
-
-  if (!base::Move(temporary_file_path, target_file_path))
-    return CompleteUpgradeStatus::RENAMING_FAILED;
-
-  // Conditions for upgrade are met here.
-  // Update remaining attempts in DB and complete task.
-  static const char kUpdateSql[] =
-      "UPDATE offlinepages_v1"
-      " SET upgrade_attempt = 0, file_path = ?, file_size = ?, digest = ?"
-      " WHERE offline_id = ?";
-  sql::Statement update_statement(
-      db->GetCachedStatement(SQL_FROM_HERE, kUpdateSql));
-  update_statement.BindString(
-      0, store_utils::ToDatabaseFilePath(target_file_path));
-  update_statement.BindInt64(1, file_size);
-  update_statement.BindString(2, digest);
-  update_statement.BindInt64(3, offline_id);
-
-  // This status might require special handling/reporting as the new file was
-  // renamed to its final name, but store item was not updated accordingly.
-  if (!update_statement.Run() || !transaction.Commit())
-    return CompleteUpgradeStatus::DB_ERROR_POST_FILE_RENAME;
-
-  // Make a best effort to delete the old file (will be cleaned up by
-  // consistency check otherwise).
-  base::DeleteFile(old_file_path, false /* recursive */);
-
-  return CompleteUpgradeStatus::SUCCESS;
-}
-
-}  // namespace
-
-CompleteOfflinePageUpgradeTask::CompleteOfflinePageUpgradeTask(
-    OfflinePageMetadataStore* store,
-    int64_t offline_id,
-    const base::FilePath& temporary_file_path,
-    const base::FilePath& target_file_path,
-    const std::string& digest,
-    int64_t file_size,
-    CompleteUpgradeCallback callback)
-    : store_(store),
-      offline_id_(offline_id),
-      temporary_file_path_(temporary_file_path),
-      target_file_path_(target_file_path),
-      digest_(digest),
-      file_size_(file_size),
-      callback_(std::move(callback)),
-      weak_ptr_factory_(this) {
-  DCHECK(store_);
-  DCHECK(!callback_.is_null());
-}
-
-CompleteOfflinePageUpgradeTask::~CompleteOfflinePageUpgradeTask() {}
-
-void CompleteOfflinePageUpgradeTask::Run() {
-  store_->Execute(
-      base::BindOnce(&CompleteOfflinePageUpgradeSync, offline_id_,
-                     temporary_file_path_, target_file_path_, digest_,
-                     file_size_),
-      base::BindOnce(&CompleteOfflinePageUpgradeTask::InformUpgradeAttemptDone,
-                     weak_ptr_factory_.GetWeakPtr()),
-      CompleteUpgradeStatus::DB_ERROR);
-}
-
-void CompleteOfflinePageUpgradeTask::InformUpgradeAttemptDone(
-    CompleteUpgradeStatus result) {
-  std::move(callback_).Run(result);
-  TaskComplete();
-}
-
-}  // namespace offline_pages
diff --git a/components/offline_pages/core/model/complete_offline_page_upgrade_task.h b/components/offline_pages/core/model/complete_offline_page_upgrade_task.h
deleted file mode 100644
index 3d8889b..0000000
--- a/components/offline_pages/core/model/complete_offline_page_upgrade_task.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_OFFLINE_PAGES_CORE_MODEL_COMPLETE_OFFLINE_PAGE_UPRGRADE_TASK_H_
-#define COMPONENTS_OFFLINE_PAGES_CORE_MODEL_COMPLETE_OFFLINE_PAGE_UPRGRADE_TASK_H_
-
-#include <stdint.h>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/offline_pages/core/model/offline_page_upgrade_types.h"
-#include "components/offline_pages/task/task.h"
-
-namespace offline_pages {
-
-class OfflinePageMetadataStore;
-
-// This task is responsible for completing the upgrade process for an offline
-// page.
-class CompleteOfflinePageUpgradeTask : public Task {
- public:
-  CompleteOfflinePageUpgradeTask(OfflinePageMetadataStore* store,
-                                 int64_t offline_id,
-                                 const base::FilePath& temporary_file_path,
-                                 const base::FilePath& target_file_path,
-                                 const std::string& digest,
-                                 int64_t file_size,
-                                 CompleteUpgradeCallback callback);
-  ~CompleteOfflinePageUpgradeTask() override;
-
-  // Task implementation.
-  void Run() override;
-
- private:
-  void InformUpgradeAttemptDone(CompleteUpgradeStatus result);
-
-  // The store containing the pages to be cleared. Not owned.
-  OfflinePageMetadataStore* store_;
-
-  // ID of the item that needs to be updated.
-  int64_t offline_id_;
-
-  // Name of the temporary file. This file is already upgraded and needs to
-  // replace the old file in the DB.
-  base::FilePath temporary_file_path_;
-
-  // Final name that the archive should have in the public location.
-  base::FilePath target_file_path_;
-
-  // Digest of the temporary file.
-  std::string digest_;
-
-  // Expected file size of the temporary file, which is double checked in
-  // archive verification step.
-  int64_t file_size_;
-
-  // Callback to return the result of starting the upgrade process.
-  CompleteUpgradeCallback callback_;
-
-  base::WeakPtrFactory<CompleteOfflinePageUpgradeTask> weak_ptr_factory_;
-  DISALLOW_COPY_AND_ASSIGN(CompleteOfflinePageUpgradeTask);
-};
-
-}  // namespace offline_pages
-
-#endif  // COMPONENTS_OFFLINE_PAGES_CORE_MODEL_COMPLETE_OFFLINE_PAGE_UPRGRADE_TASK_H_
diff --git a/components/offline_pages/core/model/complete_offline_page_upgrade_task_unittest.cc b/components/offline_pages/core/model/complete_offline_page_upgrade_task_unittest.cc
deleted file mode 100644
index 78678f6..0000000
--- a/components/offline_pages/core/model/complete_offline_page_upgrade_task_unittest.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/offline_pages/core/model/complete_offline_page_upgrade_task.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/files/file_util.h"
-#include "components/offline_pages/core/model/model_task_test_base.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace offline_pages {
-
-namespace {
-const char kContentsOfTempFile[] = "Sample content of temp file.";
-const char kTargetFileName[] = "target_file_name.mhtml";
-// TODO(fgorski): Replace test with actually computed digest.
-const char kDummyDigest[] = "TestDigest==";
-
-base::FilePath PrepareTemporaryFile(const base::FilePath& temp_dir) {
-  base::FilePath temporary_file_path;
-  EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir, &temporary_file_path));
-  EXPECT_TRUE(
-      base::AppendToFile(temporary_file_path,
-                         reinterpret_cast<const char*>(&kContentsOfTempFile[0]),
-                         sizeof(kContentsOfTempFile)));
-  return temporary_file_path;
-}
-
-}  // namespace
-
-class CompleteOfflinePageUpgradeTaskTest : public ModelTaskTestBase {
- public:
-  CompleteOfflinePageUpgradeTaskTest();
-  ~CompleteOfflinePageUpgradeTaskTest() override;
-
-  void SetUp() override;
-  OfflinePageItem CreateOfflinePage();
-
-  void CompleteUpgradeDone(CompleteUpgradeStatus result);
-
-  CompleteUpgradeCallback callback() {
-    return base::BindOnce(
-        &CompleteOfflinePageUpgradeTaskTest::CompleteUpgradeDone,
-        base::Unretained(this));
-  }
-
-  const base::FilePath& temporary_file_path() const {
-    return temporary_file_path_;
-  }
-  const base::FilePath& target_file_path() const { return target_file_path_; }
-
-  CompleteUpgradeStatus last_status() const { return last_status_; }
-
- private:
-  CompleteUpgradeStatus last_status_;
-  base::FilePath temporary_file_path_;
-  base::FilePath target_file_path_;
-};
-
-CompleteOfflinePageUpgradeTaskTest::CompleteOfflinePageUpgradeTaskTest()
-    : last_status_(CompleteUpgradeStatus::DB_ERROR) {}
-
-CompleteOfflinePageUpgradeTaskTest::~CompleteOfflinePageUpgradeTaskTest() {}
-
-void CompleteOfflinePageUpgradeTaskTest::SetUp() {
-  ModelTaskTestBase::SetUp();
-
-  temporary_file_path_ = PrepareTemporaryFile(TemporaryDir());
-  target_file_path_ = TemporaryDir().AppendASCII(kTargetFileName);
-}
-
-OfflinePageItem CompleteOfflinePageUpgradeTaskTest::CreateOfflinePage() {
-  OfflinePageItem page = generator()->CreateItemWithTempFile();
-  page.upgrade_attempt = 3;
-  store_test_util()->InsertItem(page);
-  return page;
-}
-
-void CompleteOfflinePageUpgradeTaskTest::CompleteUpgradeDone(
-    CompleteUpgradeStatus result) {
-  last_status_ = result;
-}
-
-TEST_F(CompleteOfflinePageUpgradeTaskTest, Success) {
-  OfflinePageItem original_page = CreateOfflinePage();
-
-  auto task = std::make_unique<CompleteOfflinePageUpgradeTask>(
-      store(), original_page.offline_id, temporary_file_path(),
-      target_file_path(), kDummyDigest, sizeof(kContentsOfTempFile),
-      callback());
-  RunTask(std::move(task));
-
-  EXPECT_EQ(CompleteUpgradeStatus::SUCCESS, last_status());
-
-  auto upgraded_page =
-      store_test_util()->GetPageByOfflineId(original_page.offline_id);
-  ASSERT_TRUE(upgraded_page);
-  EXPECT_EQ(0, upgraded_page->upgrade_attempt);
-  EXPECT_EQ(target_file_path(), upgraded_page->file_path);
-  EXPECT_EQ(static_cast<int64_t>(sizeof(kContentsOfTempFile)),
-            upgraded_page->file_size);
-  EXPECT_EQ(kDummyDigest, upgraded_page->digest);
-
-  EXPECT_FALSE(base::PathExists(temporary_file_path()));
-  EXPECT_TRUE(base::PathExists(target_file_path()));
-  EXPECT_FALSE(base::PathExists(original_page.file_path));
-}
-
-TEST_F(CompleteOfflinePageUpgradeTaskTest, ItemMissing) {
-  auto task = std::make_unique<CompleteOfflinePageUpgradeTask>(
-      store(), 42, temporary_file_path(), target_file_path(), kDummyDigest,
-      sizeof(kContentsOfTempFile), callback());
-  RunTask(std::move(task));
-
-  EXPECT_EQ(CompleteUpgradeStatus::ITEM_MISSING, last_status());
-
-  EXPECT_TRUE(base::PathExists(temporary_file_path()));
-  EXPECT_FALSE(base::PathExists(target_file_path()));
-}
-
-TEST_F(CompleteOfflinePageUpgradeTaskTest, TemporaryFileMissing) {
-  OfflinePageItem original_page = CreateOfflinePage();
-
-  // This ensures the temporary file won't be there.
-  EXPECT_TRUE(base::DeleteFile(temporary_file_path(), false));
-
-  auto task = std::make_unique<CompleteOfflinePageUpgradeTask>(
-      store(), original_page.offline_id, temporary_file_path(),
-      target_file_path(), kDummyDigest, sizeof(kContentsOfTempFile),
-      callback());
-  RunTask(std::move(task));
-
-  EXPECT_EQ(CompleteUpgradeStatus::TEMPORARY_FILE_MISSING, last_status());
-
-  auto upgraded_page =
-      store_test_util()->GetPageByOfflineId(original_page.offline_id);
-  ASSERT_TRUE(upgraded_page);
-  EXPECT_EQ(original_page, *upgraded_page);
-
-  EXPECT_FALSE(base::PathExists(temporary_file_path()));
-  EXPECT_FALSE(base::PathExists(target_file_path()));
-  EXPECT_TRUE(base::PathExists(original_page.file_path));
-}
-
-TEST_F(CompleteOfflinePageUpgradeTaskTest, TargetFileNameInUse) {
-  OfflinePageItem original_page = CreateOfflinePage();
-
-  // This ensures target name is taken.
-  EXPECT_TRUE(base::CopyFile(temporary_file_path(), target_file_path()));
-
-  auto task = std::make_unique<CompleteOfflinePageUpgradeTask>(
-      store(), original_page.offline_id, temporary_file_path(),
-      target_file_path(), kDummyDigest, sizeof(kContentsOfTempFile),
-      callback());
-  RunTask(std::move(task));
-
-  EXPECT_EQ(CompleteUpgradeStatus::TARGET_FILE_NAME_IN_USE, last_status());
-
-  auto upgraded_page =
-      store_test_util()->GetPageByOfflineId(original_page.offline_id);
-  ASSERT_TRUE(upgraded_page);
-  EXPECT_EQ(original_page, *upgraded_page);
-
-  EXPECT_TRUE(base::PathExists(temporary_file_path()));
-  EXPECT_TRUE(base::PathExists(target_file_path()));
-  EXPECT_TRUE(base::PathExists(original_page.file_path));
-}
-
-}  // namespace offline_pages
diff --git a/components/offline_pages/core/model/get_pages_task.cc b/components/offline_pages/core/model/get_pages_task.cc
index 61325c5..000af333 100644
--- a/components/offline_pages/core/model/get_pages_task.cc
+++ b/components/offline_pages/core/model/get_pages_task.cc
@@ -21,11 +21,11 @@
 
 using ReadResult = GetPagesTask::ReadResult;
 
-#define OFFLINE_PAGE_PROJECTION                                \
-  " offline_id, creation_time, file_size, last_access_time,"   \
-  " access_count, system_download_id, file_missing_time,"      \
-  " upgrade_attempt, client_namespace, client_id, online_url," \
-  " file_path, title, original_url, request_origin, digest"
+#define OFFLINE_PAGE_PROJECTION                           \
+  " offline_id,creation_time,file_size,last_access_time," \
+  "access_count,system_download_id,file_missing_time,"    \
+  "client_namespace,client_id,online_url,"                \
+  "file_path,title,original_url,request_origin,digest"
 
 // Create an offline page item from a SQL result.
 // Expects the order of columns as defined by OFFLINE_PAGE_PROJECTION macro.
@@ -40,15 +40,14 @@
   int64_t system_download_id = statement->ColumnInt64(5);
   base::Time file_missing_time =
       store_utils::FromDatabaseTime(statement->ColumnInt64(6));
-  int upgrade_attempt = statement->ColumnInt(7);
-  ClientId client_id(statement->ColumnString(8), statement->ColumnString(9));
-  GURL url(statement->ColumnString(10));
+  ClientId client_id(statement->ColumnString(7), statement->ColumnString(8));
+  GURL url(statement->ColumnString(9));
   base::FilePath path(
-      store_utils::FromDatabaseFilePath(statement->ColumnString(11)));
-  base::string16 title = statement->ColumnString16(12);
-  GURL original_url(statement->ColumnString(13));
-  std::string request_origin = statement->ColumnString(14);
-  std::string digest = statement->ColumnString(15);
+      store_utils::FromDatabaseFilePath(statement->ColumnString(10)));
+  base::string16 title = statement->ColumnString16(11);
+  GURL original_url(statement->ColumnString(12));
+  std::string request_origin = statement->ColumnString(13);
+  std::string digest = statement->ColumnString(14);
 
   OfflinePageItem item(url, id, client_id, path, file_size, creation_time);
   item.last_access_time = last_access_time;
@@ -58,7 +57,6 @@
   item.request_origin = request_origin;
   item.system_download_id = system_download_id;
   item.file_missing_time = file_missing_time;
-  item.upgrade_attempt = upgrade_attempt;
   item.digest = digest;
   return item;
 }
@@ -253,23 +251,6 @@
     std::move(callback).Run(&pages[0]);
 }
 
-ReadResult SelectItemsForUpgrade(sql::Database* db) {
-  ReadResult result;
-
-  static const char kSql[] =
-      "SELECT " OFFLINE_PAGE_PROJECTION
-      " FROM offlinepages_v1"
-      " WHERE upgrade_attempt > 0"
-      " ORDER BY upgrade_attempt DESC, creation_time DESC";
-  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-
-  while (statement.Step())
-    result.pages.emplace_back(MakeOfflinePageItem(&statement));
-
-  result.success = true;
-  return result;
-}
-
 }  // namespace
 
 GetPagesTask::ReadResult::ReadResult() {}
@@ -385,15 +366,6 @@
       base::BindOnce(&WrapInMultipleItemsCallback, std::move(callback))));
 }
 
-// static
-std::unique_ptr<GetPagesTask>
-GetPagesTask::CreateTaskSelectingItemsMarkedForUpgrade(
-    OfflinePageMetadataStore* store,
-    MultipleOfflinePageItemCallback callback) {
-  return base::WrapUnique(new GetPagesTask(
-      store, base::BindOnce(&SelectItemsForUpgrade), std::move(callback)));
-}
-
 GetPagesTask::GetPagesTask(OfflinePageMetadataStore* store,
                            DbWorkCallback db_work_callback,
                            MultipleOfflinePageItemCallback callback)
diff --git a/components/offline_pages/core/model/get_pages_task.h b/components/offline_pages/core/model/get_pages_task.h
index 0b56afe..d89c7ea 100644
--- a/components/offline_pages/core/model/get_pages_task.h
+++ b/components/offline_pages/core/model/get_pages_task.h
@@ -107,14 +107,6 @@
       int64_t file_size,
       const std::string& digest);
 
-  // Creates |GetPagesTask| selecting persistent items having a non-zero
-  // remaining upgrade attempts.
-  // Order of items is determined by number of remaining attempts (descending)
-  // and creation time (descending).
-  static std::unique_ptr<GetPagesTask> CreateTaskSelectingItemsMarkedForUpgrade(
-      OfflinePageMetadataStore* store,
-      MultipleOfflinePageItemCallback callback);
-
   ~GetPagesTask() override;
 
   // Task implementation:
diff --git a/components/offline_pages/core/model/get_pages_task_unittest.cc b/components/offline_pages/core/model/get_pages_task_unittest.cc
index d5c2a97..915f4e56e 100644
--- a/components/offline_pages/core/model/get_pages_task_unittest.cc
+++ b/components/offline_pages/core/model/get_pages_task_unittest.cc
@@ -301,37 +301,4 @@
   EXPECT_EQ(1UL, result_set.count(cct_item));
 }
 
-TEST_F(GetPagesTaskTest, SelectItemsForUpgrade) {
-  base::Time now = base::Time::Now();
-  std::vector<int> remaining_attempts = {3, 2, 2, 1};
-  std::vector<base::Time> creation_times = {
-      now, now, now - base::TimeDelta::FromDays(1), now};
-
-  // |expected_items| are items expected to be selected by the task.
-  std::vector<OfflinePageItem> expected_items;
-
-  generator()->SetNamespace(kDownloadNamespace);
-  for (size_t i = 0; i < remaining_attempts.size(); ++i) {
-    OfflinePageItem selected_item = generator()->CreateItem();
-    selected_item.upgrade_attempt = remaining_attempts[i];
-    selected_item.creation_time = creation_times[i];
-    store_test_util()->InsertItem(selected_item);
-    // This selected_item is expected in return and in this position.
-    expected_items.push_back(selected_item);
-
-    // Should be skipped (no more upgrade attempts available).
-    OfflinePageItem non_selected_item = generator()->CreateItem();
-    non_selected_item.upgrade_attempt = 0;
-    non_selected_item.creation_time = creation_times[i];
-    store_test_util()->InsertItem(non_selected_item);
-  }
-
-  RunTask(GetPagesTask::CreateTaskSelectingItemsMarkedForUpgrade(
-      store(), get_pages_callback()));
-
-  ASSERT_TRUE(expected_items.size() == read_result().size());
-  for (size_t i = 0; i < expected_items.size(); ++i)
-    EXPECT_EQ(expected_items[i], read_result()[i]);
-}
-
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index 9e04bba3..f7a421cf 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -170,10 +170,6 @@
 }  // namespace
 
 // static
-constexpr base::TimeDelta
-    OfflinePageModelTaskified::kInitialUpgradeSelectionDelay;
-
-// static
 constexpr base::TimeDelta OfflinePageModelTaskified::kMaintenanceTasksDelay;
 
 // static
@@ -195,8 +191,6 @@
       weak_ptr_factory_(this) {
   DCHECK_LT(kMaintenanceTasksDelay, OfflinePageMetadataStore::kClosingDelay);
   CreateArchivesDirectoryIfNeeded();
-  // TODO(fgorski): Call from here, when upgrade task is available:
-  // PostSelectItemsMarkedForUpgrade();
 }
 
 OfflinePageModelTaskified::~OfflinePageModelTaskified() {}
@@ -768,33 +762,6 @@
   }
 }
 
-void OfflinePageModelTaskified::PostSelectItemsMarkedForUpgrade() {
-  // TODO(fgorski): Make storage permission check. Here or later?
-  // TODO(fgorski): Check disk space here.
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      base::BindRepeating(
-          &OfflinePageModelTaskified::SelectItemsMarkedForUpgrade,
-          weak_ptr_factory_.GetWeakPtr()),
-      kInitialUpgradeSelectionDelay);
-}
-
-void OfflinePageModelTaskified::SelectItemsMarkedForUpgrade() {
-  // TODO(fgorski): Add legacy Persistent path in archive manager to know which
-  // files still need upgrade.
-  auto task = GetPagesTask::CreateTaskSelectingItemsMarkedForUpgrade(
-      store_.get(),
-      base::BindRepeating(
-          &OfflinePageModelTaskified::OnSelectItemsMarkedForUpgradeDone,
-          weak_ptr_factory_.GetWeakPtr()));
-  task_queue_.AddTask(std::move(task));
-}
-
-void OfflinePageModelTaskified::OnSelectItemsMarkedForUpgradeDone(
-    const MultipleOfflinePageItemResult& pages_for_upgrade) {
-  // TODO(fgorski): Save the list of ID to feed them into the upgrade task.
-}
-
 void OfflinePageModelTaskified::RemovePagesMatchingUrlAndNamespace(
     const OfflinePageItem& page) {
   auto task = DeletePageTask::CreateTaskDeletingForPageLimit(
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.h b/components/offline_pages/core/model/offline_page_model_taskified.h
index e44bfc4..090812d 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.h
+++ b/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -52,10 +52,6 @@
 class OfflinePageModelTaskified : public OfflinePageModel,
                                   public TaskQueue::Delegate {
  public:
-  // Initial delay after which a list of items for upgrade will be generated.
-  static constexpr base::TimeDelta kInitialUpgradeSelectionDelay =
-      base::TimeDelta::FromSeconds(45);
-
   // Delay between the scheduling and actual running of maintenance tasks. To
   // not cause the re-opening of the metadata store this delay should be kept
   // smaller than OfflinePageMetadataStore::kClosingDelay.
@@ -196,12 +192,6 @@
       bool success,
       const std::vector<int64_t>& pages_deleted);
 
-  // Method for upgrade to public storage.
-  void PostSelectItemsMarkedForUpgrade();
-  void SelectItemsMarkedForUpgrade();
-  void OnSelectItemsMarkedForUpgradeDone(
-      const MultipleOfflinePageItemResult& pages_for_upgrade);
-
   // Callback for when PublishArchive has completd.
   void PublishArchiveDone(std::unique_ptr<OfflinePageArchiver> archiver,
                           SavePageCallback save_page_callback,
diff --git a/components/offline_pages/core/model/start_offline_page_upgrade_task.cc b/components/offline_pages/core/model/start_offline_page_upgrade_task.cc
deleted file mode 100644
index 28cdaf6..0000000
--- a/components/offline_pages/core/model/start_offline_page_upgrade_task.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/offline_pages/core/model/start_offline_page_upgrade_task.h"
-
-#include "base/bind.h"
-#include "base/files/file_util.h"
-#include "base/system/sys_info.h"
-#include "components/offline_pages/core/offline_page_metadata_store.h"
-#include "components/offline_pages/core/offline_store_utils.h"
-#include "sql/database.h"
-#include "sql/statement.h"
-#include "sql/transaction.h"
-
-namespace offline_pages {
-
-namespace {
-
-StartUpgradeResult StartOfflinePageUpgradeSync(
-    int64_t offline_id,
-    const base::FilePath& target_directory,
-    sql::Database* db) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin())
-    return StartUpgradeResult(StartUpgradeStatus::DB_ERROR);
-
-  static const char kSql[] =
-      "SELECT file_path, file_size, digest"
-      " FROM offlinepages_v1 WHERE offline_id = ?";
-  sql::Statement select_statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  select_statement.BindInt64(0, offline_id);
-  if (!select_statement.Step()) {
-    return StartUpgradeResult(select_statement.Succeeded()
-                                  ? StartUpgradeStatus::ITEM_MISSING
-                                  : StartUpgradeStatus::DB_ERROR);
-  }
-
-  base::FilePath file_path =
-      store_utils::FromDatabaseFilePath(select_statement.ColumnString(0));
-  if (!base::PathExists(file_path))
-    return StartUpgradeResult(StartUpgradeStatus::FILE_MISSING);
-
-  int64_t free_disk_space_on_target =
-      base::SysInfo::AmountOfFreeDiskSpace(target_directory);
-
-  int64_t file_size = select_statement.ColumnInt64(1);
-  if (free_disk_space_on_target < 2 * file_size)
-    return StartUpgradeResult(StartUpgradeStatus::NOT_ENOUGH_STORAGE);
-
-  // Digest will be consumed when returning.
-  std::string digest = select_statement.ColumnString(2);
-
-  // Conditions for upgrade are met here.
-  // Update remaining attempts in DB and complete task.
-  static const char kUpdateSql[] =
-      "UPDATE offlinepages_v1 SET upgrade_attempt = upgrade_attempt - 1 "
-      " WHERE offline_id = ?";
-  sql::Statement update_statement(
-      db->GetCachedStatement(SQL_FROM_HERE, kUpdateSql));
-  update_statement.BindInt64(0, offline_id);
-
-  if (!update_statement.Run() || !transaction.Commit())
-    return StartUpgradeResult(StartUpgradeStatus::DB_ERROR);
-
-  return StartUpgradeResult(StartUpgradeStatus::SUCCESS, std::move(digest),
-                            std::move(file_path));
-}
-
-}  // namespace
-
-StartOfflinePageUpgradeTask::StartOfflinePageUpgradeTask(
-    OfflinePageMetadataStore* store,
-    int64_t offline_id,
-    const base::FilePath& target_directory,
-    StartUpgradeCallback callback)
-    : store_(store),
-      offline_id_(offline_id),
-      target_directory_(target_directory),
-      callback_(std::move(callback)),
-      weak_ptr_factory_(this) {
-  DCHECK(store_);
-  DCHECK(!callback_.is_null());
-}
-
-StartOfflinePageUpgradeTask::~StartOfflinePageUpgradeTask() {}
-
-void StartOfflinePageUpgradeTask::Run() {
-  store_->Execute(
-      base::BindOnce(&StartOfflinePageUpgradeSync, offline_id_,
-                     target_directory_),
-      base::BindOnce(&StartOfflinePageUpgradeTask::InformUpgradeAttemptDone,
-                     weak_ptr_factory_.GetWeakPtr()),
-      StartUpgradeResult(StartUpgradeStatus::DB_ERROR));
-}
-
-void StartOfflinePageUpgradeTask::InformUpgradeAttemptDone(
-    StartUpgradeResult result) {
-  std::move(callback_).Run(std::move(result));
-  TaskComplete();
-}
-
-}  // namespace offline_pages
diff --git a/components/offline_pages/core/model/start_offline_page_upgrade_task.h b/components/offline_pages/core/model/start_offline_page_upgrade_task.h
deleted file mode 100644
index 88459b4e..0000000
--- a/components/offline_pages/core/model/start_offline_page_upgrade_task.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_OFFLINE_PAGES_CORE_MODEL_START_OFFLINE_PAGE_UPRGRADE_TASK_H_
-#define COMPONENTS_OFFLINE_PAGES_CORE_MODEL_START_OFFLINE_PAGE_UPRGRADE_TASK_H_
-
-#include <stdint.h>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/offline_pages/core/model/offline_page_upgrade_types.h"
-#include "components/offline_pages/task/task.h"
-
-namespace offline_pages {
-
-class OfflinePageMetadataStore;
-
-// This task is responsible for starting the upgrade process for an offline
-// page.
-class StartOfflinePageUpgradeTask : public Task {
- public:
-  StartOfflinePageUpgradeTask(OfflinePageMetadataStore* store,
-                              int64_t offline_id,
-                              const base::FilePath& target_directory,
-                              StartUpgradeCallback callback);
-  ~StartOfflinePageUpgradeTask() override;
-
-  // Task implementation.
-  void Run() override;
-
- private:
-  void InformUpgradeAttemptDone(StartUpgradeResult result);
-
-  // The store containing the pages to be cleared. Not owned.
-  OfflinePageMetadataStore* store_;
-
-  // ID of the item that needs to be updated.
-  int64_t offline_id_;
-
-  // Directory where the file is expected after upgrade.
-  base::FilePath target_directory_;
-
-  // Callback to return the result of starting the upgrade process.
-  StartUpgradeCallback callback_;
-
-  base::WeakPtrFactory<StartOfflinePageUpgradeTask> weak_ptr_factory_;
-  DISALLOW_COPY_AND_ASSIGN(StartOfflinePageUpgradeTask);
-};
-
-}  // namespace offline_pages
-
-#endif  // COMPONENTS_OFFLINE_PAGES_CORE_MODEL_START_OFFLINE_PAGE_UPRGRADE_TASK_H_
diff --git a/components/offline_pages/core/model/start_offline_page_upgrade_task_unittest.cc b/components/offline_pages/core/model/start_offline_page_upgrade_task_unittest.cc
deleted file mode 100644
index 667d5956..0000000
--- a/components/offline_pages/core/model/start_offline_page_upgrade_task_unittest.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/offline_pages/core/model/start_offline_page_upgrade_task.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "components/offline_pages/core/model/model_task_test_base.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace offline_pages {
-
-namespace {
-const char kTestDigest[] = "TestDigest==";
-}  // namespace
-
-class StartOfflinePageUpgradeTaskTest : public ModelTaskTestBase {
- public:
-  StartOfflinePageUpgradeTaskTest();
-  ~StartOfflinePageUpgradeTaskTest() override;
-
-  void StartUpgradeDone(StartUpgradeResult result);
-
-  StartUpgradeCallback callback() {
-    return base::BindOnce(&StartOfflinePageUpgradeTaskTest::StartUpgradeDone,
-                          base::Unretained(this));
-  }
-
-  StartUpgradeResult* last_result() { return &last_result_; }
-
- private:
-  StartUpgradeResult last_result_;
-};
-
-StartOfflinePageUpgradeTaskTest::StartOfflinePageUpgradeTaskTest()
-    : last_result_(StartUpgradeStatus::DB_ERROR) {}
-
-StartOfflinePageUpgradeTaskTest::~StartOfflinePageUpgradeTaskTest() {}
-
-void StartOfflinePageUpgradeTaskTest::StartUpgradeDone(
-    StartUpgradeResult result) {
-  last_result_ = std::move(result);
-}
-
-TEST_F(StartOfflinePageUpgradeTaskTest, StartUpgradeSuccess) {
-  OfflinePageItem original_page = generator()->CreateItemWithTempFile();
-  original_page.upgrade_attempt = 3;
-  original_page.digest = kTestDigest;
-  store_test_util()->InsertItem(original_page);
-
-  auto task = std::make_unique<StartOfflinePageUpgradeTask>(
-      store(), original_page.offline_id, TemporaryDir(), callback());
-  RunTask(std::move(task));
-
-  EXPECT_EQ(StartUpgradeStatus::SUCCESS, last_result()->status);
-  EXPECT_EQ(kTestDigest, last_result()->digest);
-  EXPECT_EQ(original_page.file_path, last_result()->file_path);
-
-  auto upgraded_page =
-      store_test_util()->GetPageByOfflineId(original_page.offline_id);
-  ASSERT_TRUE(upgraded_page);
-  EXPECT_EQ(2, upgraded_page->upgrade_attempt);
-}
-
-TEST_F(StartOfflinePageUpgradeTaskTest, StartUpgradeItemMissing) {
-  auto task = std::make_unique<StartOfflinePageUpgradeTask>(
-      store(), 42, base::FilePath(), callback());
-  RunTask(std::move(task));
-
-  EXPECT_EQ(StartUpgradeStatus::ITEM_MISSING, last_result()->status);
-  EXPECT_TRUE(last_result()->digest.empty());
-  EXPECT_TRUE(last_result()->file_path.empty());
-}
-
-TEST_F(StartOfflinePageUpgradeTaskTest, StartUpgradeFileMissing) {
-  OfflinePageItem original_page = generator()->CreateItem();
-  original_page.upgrade_attempt = 3;
-  store_test_util()->InsertItem(original_page);
-
-  auto task = std::make_unique<StartOfflinePageUpgradeTask>(
-      store(), original_page.offline_id, base::FilePath(), callback());
-  RunTask(std::move(task));
-
-  EXPECT_EQ(StartUpgradeStatus::FILE_MISSING, last_result()->status);
-  EXPECT_TRUE(last_result()->digest.empty());
-  EXPECT_TRUE(last_result()->file_path.empty());
-
-  auto upgraded_page =
-      store_test_util()->GetPageByOfflineId(original_page.offline_id);
-  ASSERT_TRUE(upgraded_page);
-  EXPECT_EQ(original_page, *upgraded_page);
-}
-
-TEST_F(StartOfflinePageUpgradeTaskTest, StartUpgradeNotEnoughSpace) {
-  OfflinePageItem original_page = generator()->CreateItemWithTempFile();
-  original_page.upgrade_attempt = 3;
-  store_test_util()->InsertItem(original_page);
-
-  auto task = std::make_unique<StartOfflinePageUpgradeTask>(
-      store(), original_page.offline_id, base::FilePath(), callback());
-  RunTask(std::move(task));
-
-  EXPECT_EQ(StartUpgradeStatus::NOT_ENOUGH_STORAGE, last_result()->status);
-  EXPECT_TRUE(last_result()->digest.empty());
-  EXPECT_TRUE(last_result()->file_path.empty());
-
-  auto upgraded_page =
-      store_test_util()->GetPageByOfflineId(original_page.offline_id);
-  ASSERT_TRUE(upgraded_page);
-  EXPECT_EQ(original_page, *upgraded_page);
-}
-
-}  // namespace offline_pages
diff --git a/components/offline_pages/core/offline_page_item.cc b/components/offline_pages/core/offline_page_item.cc
index 743e129f..7cf0d966 100644
--- a/components/offline_pages/core/offline_page_item.cc
+++ b/components/offline_pages/core/offline_page_item.cc
@@ -49,8 +49,7 @@
          original_url_if_different == other.original_url_if_different &&
          request_origin == other.request_origin &&
          system_download_id == other.system_download_id &&
-         file_missing_time == other.file_missing_time &&
-         upgrade_attempt == other.upgrade_attempt && digest == other.digest;
+         file_missing_time == other.file_missing_time && digest == other.digest;
 }
 
 bool OfflinePageItem::operator<(const OfflinePageItem& other) const {
diff --git a/components/offline_pages/core/offline_page_item.h b/components/offline_pages/core/offline_page_item.h
index 0f31162..578fce40 100644
--- a/components/offline_pages/core/offline_page_item.h
+++ b/components/offline_pages/core/offline_page_item.h
@@ -88,8 +88,6 @@
   // The most recent time when the file was discovered missing.
   // NULL time implies the file is not missing.
   base::Time file_missing_time;
-  // Number of attemps for upgrading the MHTML page into new format.
-  int upgrade_attempt = 0;
   // Digest of the page calculated when page is saved, in order to tell if the
   // page can be trusted. This field will always be an empty string for
   // temporary and shared pages.
diff --git a/components/offline_pages/core/offline_page_metadata_store.cc b/components/offline_pages/core/offline_page_metadata_store.cc
index 94b3720..75c36878 100644
--- a/components/offline_pages/core/offline_page_metadata_store.cc
+++ b/components/offline_pages/core/offline_page_metadata_store.cc
@@ -50,6 +50,8 @@
       " access_count INTEGER NOT NULL,"
       " system_download_id INTEGER NOT NULL DEFAULT 0,"
       " file_missing_time INTEGER NOT NULL DEFAULT 0,"
+      // upgrade_attempt is deprecated, and should be removed next time the
+      // schema needs to be updated.
       " upgrade_attempt INTEGER NOT NULL DEFAULT 0,"
       " client_namespace VARCHAR NOT NULL,"
       " client_id VARCHAR NOT NULL,"
@@ -246,23 +248,9 @@
 
 bool UpgradeFromVersion1ToVersion2(sql::Database* db,
                                    sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin())
-    return false;
-
-  static const char kSql[] = "UPDATE " OFFLINE_PAGES_TABLE_NAME
-                             " SET upgrade_attempt = 5 "
-                             " WHERE client_namespace = 'async_loading'"
-                             " OR client_namespace = 'download'"
-                             " OR client_namespace = 'ntp_suggestions'"
-                             " OR client_namespace = 'browser_actions'";
-
-  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  if (!statement.Run())
-    return false;
-
   meta_table->SetVersionNumber(2);
-  return transaction.Commit();
+  // No actual changes necessary, because upgrade_attempt was deprecated.
+  return true;
 }
 
 bool UpgradeFromVersion2ToVersion3(sql::Database* db,
diff --git a/components/offline_pages/core/offline_page_metadata_store_unittest.cc b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
index fa0cda3..3b696dd 100644
--- a/components/offline_pages/core/offline_page_metadata_store_unittest.cc
+++ b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
@@ -379,8 +379,8 @@
       "last_access_time, access_count, client_namespace, "
       "client_id, online_url, file_path, title, original_url, "
       "request_origin, system_download_id, file_missing_time, "
-      "upgrade_attempt, digest) "
-      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+      "digest) "
+      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
   statement.BindInt64(0, item.offline_id);
   statement.BindInt(1, store_utils::ToDatabaseTime(item.creation_time));
   statement.BindInt64(2, item.file_size);
@@ -395,8 +395,7 @@
   statement.BindString(11, item.request_origin);
   statement.BindInt64(12, item.system_download_id);
   statement.BindInt(13, store_utils::ToDatabaseTime(item.file_missing_time));
-  statement.BindInt(14, item.upgrade_attempt);
-  statement.BindString(15, item.digest);
+  statement.BindString(14, item.digest);
   ASSERT_TRUE(statement.Run());
   ASSERT_TRUE(db->CommitTransaction());
 }
@@ -495,7 +494,7 @@
   int64_t system_download_id = statement->ColumnInt64(5);
   base::Time file_missing_time =
       store_utils::FromDatabaseTime(statement->ColumnInt64(6));
-  int upgrade_attempt = statement->ColumnInt(7);
+  // Column 7 is deprecated 'upgrade_attempt'.
   ClientId client_id(statement->ColumnString(8), statement->ColumnString(9));
   GURL url(statement->ColumnString(10));
   base::FilePath path(
@@ -513,7 +512,6 @@
   item.request_origin = request_origin;
   item.system_download_id = system_download_id;
   item.file_missing_time = file_missing_time;
-  item.upgrade_attempt = upgrade_attempt;
   item.digest = digest;
   return item;
 }
@@ -645,12 +643,6 @@
         kAsyncNamespace, kDownloadNamespace, kBrowserActionsNamespace,
         kNTPSuggestionsNamespace};
 
-    for (const OfflinePageItem& page : pages) {
-      if (upgradeable_namespaces.count(page.client_id.name_space) > 0)
-        EXPECT_EQ(5, page.upgrade_attempt);
-      else
-        EXPECT_EQ(0, page.upgrade_attempt);
-    }
     CheckThatPageThumbnailCanBeSaved((OfflinePageMetadataStore*)store.get());
     CheckThatOfflinePageCanBeSaved(std::move(store));
     VerifyMetaVersions();
@@ -693,13 +685,13 @@
       // causes debug builds to DLOG.
       static const char kSql[] =
           "INSERT OR IGNORE INTO " OFFLINE_PAGES_TABLE_V1
-          " (offline_id, online_url, client_namespace, client_id, "
-          "file_path, "
-          "file_size, creation_time, last_access_time, access_count, "
-          "title, original_url, request_origin, system_download_id, "
-          "file_missing_time, upgrade_attempt, digest)"
+          " (offline_id,online_url,client_namespace,client_id,"
+          "file_path,"
+          "file_size,creation_time,last_access_time,access_count,"
+          "title,original_url,request_origin,system_download_id,"
+          "file_missing_time,digest)"
           " VALUES "
-          " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+          "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
 
       sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
       statement.BindInt64(0, item.offline_id);
@@ -718,8 +710,7 @@
       statement.BindInt64(12, item.system_download_id);
       statement.BindInt64(13,
                           store_utils::ToDatabaseTime(item.file_missing_time));
-      statement.BindInt(14, item.upgrade_attempt);
-      statement.BindString(15, item.digest);
+      statement.BindString(14, item.digest);
 
       if (!statement.Run())
         return ItemActionStatus::STORE_ERROR;
@@ -915,6 +906,7 @@
   pages = GetOfflinePages(store.get());
   ASSERT_EQ(2U, pages.size());
   EXPECT_EQ(offline_page_2, pages[0]);
+  EXPECT_EQ(offline_page_2.offline_id, pages[0].offline_id);
 }
 
 TEST_F(OfflinePageMetadataStoreTest, StoreCloses) {
diff --git a/components/pairing/bluetooth_host_pairing_controller.cc b/components/pairing/bluetooth_host_pairing_controller.cc
index 12e76ad6..75a39a6 100644
--- a/components/pairing/bluetooth_host_pairing_controller.cc
+++ b/components/pairing/bluetooth_host_pairing_controller.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
diff --git a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
index 069d91d..6cbb55b 100644
--- a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
+++ b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
@@ -5,8 +5,8 @@
 #include "components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.h"
 
 #include "base/bind.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.cc b/components/password_manager/core/browser/sync/password_sync_bridge.cc
index 5f217bf..29d0b28 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -8,6 +8,7 @@
 
 #include "base/auto_reset.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/common/password_form.h"
@@ -241,6 +242,19 @@
 base::Optional<syncer::ModelError> PasswordSyncBridge::MergeSyncData(
     std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
     syncer::EntityChangeList entity_data) {
+  base::Optional<syncer::ModelError> error =
+      MergeSyncDataInternal(std::move(metadata_change_list), entity_data);
+  if (error) {
+    base::UmaHistogramCounts10000(
+        "Sync.DownloadedPasswordsCountWhenInitialMergeFails",
+        entity_data.size());
+  }
+  return error;
+}
+
+base::Optional<syncer::ModelError> PasswordSyncBridge::MergeSyncDataInternal(
+    std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+    syncer::EntityChangeList entity_data) {
   // This method merges the local and remote passwords based on their client
   // tags. For a form |F|, there are three cases to handle:
   // 1. |F| exists only in the local model --> |F| should be Put() in the change
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.h b/components/password_manager/core/browser/sync/password_sync_bridge.h
index bc7def1..dd9846e 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge.h
+++ b/components/password_manager/core/browser/sync/password_sync_bridge.h
@@ -66,6 +66,10 @@
   // MergeSyncData().
   base::Optional<syncer::ModelError> CleanupPasswordStore();
 
+  base::Optional<syncer::ModelError> MergeSyncDataInternal(
+      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+      syncer::EntityChangeList entity_data);
+
   // Password store responsible for persistence.
   PasswordStoreSync* const password_store_sync_;
 
diff --git a/components/policy/proto/chrome_device_policy.proto b/components/policy/proto/chrome_device_policy.proto
index d47708fb..4db3e21b2 100644
--- a/components/policy/proto/chrome_device_policy.proto
+++ b/components/policy/proto/chrome_device_policy.proto
@@ -1104,7 +1104,7 @@
 
 // Setting to control if running virtual machines on Chrome OS is allowed.
 message VirtualMachinesAllowedProto {
-  optional bool virtual_machines_allowed = 1 [default = true];
+  optional bool virtual_machines_allowed = 1;
 }
 
 // Specifies if and how often Active Directory machine (computer) account
diff --git a/components/prefs/pref_value_store.h b/components/prefs/pref_value_store.h
index 3d5676eb..70a92bc 100644
--- a/components/prefs/pref_value_store.h
+++ b/components/prefs/pref_value_store.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_PREFS_PREF_VALUE_STORE_H_
 #define COMPONENTS_PREFS_PREF_VALUE_STORE_H_
 
+#include <functional>
 #include <map>
 #include <memory>
 #include <string>
diff --git a/components/pwg_encoder/pwg_encoder_unittest.cc b/components/pwg_encoder/pwg_encoder_unittest.cc
index 96e822b..de9802d 100644
--- a/components/pwg_encoder/pwg_encoder_unittest.cc
+++ b/components/pwg_encoder/pwg_encoder_unittest.cc
@@ -8,7 +8,7 @@
 
 #include <memory>
 
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/pwg_encoder/bitmap_image.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/reading_list/core/offline_url_utils.cc b/components/reading_list/core/offline_url_utils.cc
index 1542922..65d6b03 100644
--- a/components/reading_list/core/offline_url_utils.cc
+++ b/components/reading_list/core/offline_url_utils.cc
@@ -4,8 +4,8 @@
 
 #include "components/reading_list/core/offline_url_utils.h"
 
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/strings/stringprintf.h"
 
 namespace {
diff --git a/components/safe_browsing/browser/threat_details_cache.cc b/components/safe_browsing/browser/threat_details_cache.cc
index 8ad043b..43a9d4e 100644
--- a/components/safe_browsing/browser/threat_details_cache.cc
+++ b/components/safe_browsing/browser/threat_details_cache.cc
@@ -9,8 +9,8 @@
 #include <stdint.h>
 
 #include "base/bind.h"
+#include "base/hash/md5.h"
 #include "base/lazy_instance.h"
-#include "base/md5.h"
 #include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
diff --git a/components/safe_browsing/db/v4_protocol_manager_util.cc b/components/safe_browsing/db/v4_protocol_manager_util.cc
index e6be4718..dcc86e9 100644
--- a/components/safe_browsing/db/v4_protocol_manager_util.cc
+++ b/components/safe_browsing/db/v4_protocol_manager_util.cc
@@ -5,10 +5,10 @@
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
 
 #include "base/base64.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
+#include "base/hash/sha1.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/rand_util.h"
-#include "base/sha1.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "components/version_info/version_info.h"
diff --git a/components/safe_browsing/db/v4_protocol_manager_util.h b/components/safe_browsing/db/v4_protocol_manager_util.h
index d2b74ad..207ed7f 100644
--- a/components/safe_browsing/db/v4_protocol_manager_util.h
+++ b/components/safe_browsing/db/v4_protocol_manager_util.h
@@ -8,6 +8,7 @@
 // A class that implements the stateless methods used by the GetHashUpdate and
 // GetFullHash stubby calls made by Chrome using the SafeBrowsing V4 protocol.
 
+#include <functional>
 #include <initializer_list>
 #include <memory>
 #include <ostream>
diff --git a/components/services/heap_profiling/address.h b/components/services/heap_profiling/address.h
index 621dd61c..9cf53462 100644
--- a/components/services/heap_profiling/address.h
+++ b/components/services/heap_profiling/address.h
@@ -10,7 +10,7 @@
 #include <functional>
 #include <iosfwd>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 
 namespace heap_profiling {
 
diff --git a/components/services/heap_profiling/backtrace.cc b/components/services/heap_profiling/backtrace.cc
index 5889b18..53e114b 100644
--- a/components/services/heap_profiling/backtrace.cc
+++ b/components/services/heap_profiling/backtrace.cc
@@ -8,7 +8,7 @@
 
 #include <algorithm>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "components/services/heap_profiling/backtrace_storage.h"
 
 namespace heap_profiling {
diff --git a/components/services/heap_profiling/public/cpp/settings.cc b/components/services/heap_profiling/public/cpp/settings.cc
index bd22f17..96b3a3ce 100644
--- a/components/services/heap_profiling/public/cpp/settings.cc
+++ b/components/services/heap_profiling/public/cpp/settings.cc
@@ -23,11 +23,9 @@
 const char kOOPHeapProfilingFeatureStackMode[] = "stack-mode";
 const char kOOPHeapProfilingFeatureSampling[] = "sampling";
 const char kOOPHeapProfilingFeatureSamplingRate[] = "sampling-rate";
-const char kOOPHeapProfilingFeatureInProcess[] = "in-process";
 
 const uint32_t kDefaultSamplingRate = 100000;
 const bool kDefaultShouldSample = true;
-const bool kDefaultInProcessMode = false;
 
 bool RecordAllAllocationsForStartup() {
   return !base::GetFieldTrialParamByFeatureAsBool(
@@ -47,12 +45,12 @@
     return Mode::kNone;
   }
 
-  if (cmdline->HasSwitch(kMemlog) ||
+  if (cmdline->HasSwitch(kMemlogMode) ||
       base::FeatureList::IsEnabled(kOOPHeapProfilingFeature)) {
     std::string mode;
     // Respect the commandline switch above the field trial.
-    if (cmdline->HasSwitch(kMemlog)) {
-      mode = cmdline->GetSwitchValueASCII(kMemlog);
+    if (cmdline->HasSwitch(kMemlogMode)) {
+      mode = cmdline->GetSwitchValueASCII(kMemlogMode);
     } else {
       mode = base::GetFieldTrialParamValueByFeature(
           kOOPHeapProfilingFeature, kOOPHeapProfilingFeatureMode);
@@ -62,8 +60,8 @@
   }
   return Mode::kNone;
 #else
-  LOG_IF(ERROR, cmdline->HasSwitch(kMemlog))
-      << "--" << kMemlog
+  LOG_IF(ERROR, cmdline->HasSwitch(kMemlogMode))
+      << "--" << kMemlogMode
       << " specified but it will have no effect because the use_allocator_shim "
       << "is not available in this build.";
   return Mode::kNone;
@@ -90,7 +88,7 @@
   if (mode == kMemlogModeUtilityAndBrowser)
     return Mode::kUtilityAndBrowser;
   DLOG(ERROR) << "Unsupported value: \"" << mode << "\" passed to --"
-              << kMemlog;
+              << kMemlogMode;
   return Mode::kNone;
 }
 
@@ -148,10 +146,8 @@
 }
 
 bool IsInProcessModeEnabled() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(kMemlogInProcess) ||
-         base::GetFieldTrialParamByFeatureAsBool(
-             kOOPHeapProfilingFeature, kOOPHeapProfilingFeatureInProcess,
-             kDefaultInProcessMode);
+  return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+             kMemlogInProcess) != kMemlogInProcessDisabled;
 }
 
 bool IsBackgroundHeapProfilingEnabled() {
diff --git a/components/services/heap_profiling/public/cpp/switches.cc b/components/services/heap_profiling/public/cpp/switches.cc
index 6d7025ac..8f4a317 100644
--- a/components/services/heap_profiling/public/cpp/switches.cc
+++ b/components/services/heap_profiling/public/cpp/switches.cc
@@ -6,8 +6,11 @@
 
 namespace heap_profiling {
 
-const char kMemlog[] = "memlog";
 const char kMemlogInProcess[] = "memlog-in-process";
+const char kMemlogInProcessEnabled[] = "on";
+const char kMemlogInProcessDisabled[] = "off";
+
+const char kMemlogMode[] = "memlog";
 const char kMemlogModeAll[] = "all";
 const char kMemlogModeAllRenderers[] = "all-renderers";
 const char kMemlogModeBrowser[] = "browser";
@@ -17,7 +20,15 @@
 const char kMemlogModeRendererSampling[] = "renderer-sampling";
 const char kMemlogModeUtilityAndBrowser[] = "utility-and-browser";
 const char kMemlogModeUtilitySampling[] = "utility-sampling";
+
 const char kMemlogSamplingRate[] = "memlog-sampling-rate";
+const char kMemlogSamplingRate10KB[] = "10000";
+const char kMemlogSamplingRate50KB[] = "50000";
+const char kMemlogSamplingRate100KB[] = "100000";
+const char kMemlogSamplingRate500KB[] = "500000";
+const char kMemlogSamplingRate1MB[] = "1000000";
+const char kMemlogSamplingRate5MB[] = "5000000";
+
 const char kMemlogStackMode[] = "memlog-stack-mode";
 const char kMemlogStackModeMixed[] = "mixed";
 const char kMemlogStackModeNative[] = "native";
diff --git a/components/services/heap_profiling/public/cpp/switches.h b/components/services/heap_profiling/public/cpp/switches.h
index 22022c0..12d5326 100644
--- a/components/services/heap_profiling/public/cpp/switches.h
+++ b/components/services/heap_profiling/public/cpp/switches.h
@@ -7,8 +7,7 @@
 
 namespace heap_profiling {
 
-extern const char kMemlog[];
-extern const char kMemlogInProcess[];
+extern const char kMemlogMode[];
 extern const char kMemlogModeAll[];
 extern const char kMemlogModeAllRenderers[];
 extern const char kMemlogModeBrowser[];
@@ -18,7 +17,19 @@
 extern const char kMemlogModeRendererSampling[];
 extern const char kMemlogModeUtilityAndBrowser[];
 extern const char kMemlogModeUtilitySampling[];
+
+extern const char kMemlogInProcess[];
+extern const char kMemlogInProcessEnabled[];
+extern const char kMemlogInProcessDisabled[];
+
 extern const char kMemlogSamplingRate[];
+extern const char kMemlogSamplingRate10KB[];
+extern const char kMemlogSamplingRate50KB[];
+extern const char kMemlogSamplingRate100KB[];
+extern const char kMemlogSamplingRate500KB[];
+extern const char kMemlogSamplingRate1MB[];
+extern const char kMemlogSamplingRate5MB[];
+
 extern const char kMemlogStackMode[];
 extern const char kMemlogStackModeMixed[];
 extern const char kMemlogStackModeNative[];
diff --git a/components/services/heap_profiling/public/cpp/switches_unittest.cc b/components/services/heap_profiling/public/cpp/switches_unittest.cc
index d26a5060d..22c6769 100644
--- a/components/services/heap_profiling/public/cpp/switches_unittest.cc
+++ b/components/services/heap_profiling/public/cpp/switches_unittest.cc
@@ -21,20 +21,20 @@
 TEST(HeapProfilingSwitches, GetModeForStartup_Commandline) {
   {
     base::test::ScopedCommandLine scoped_command_line;
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlog, "");
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlogMode, "");
     EXPECT_EQ(Mode::kNone, GetModeForStartup());
   }
 
   {
     base::test::ScopedCommandLine scoped_command_line;
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlog,
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlogMode,
                                                               "invalid");
     EXPECT_EQ(Mode::kNone, GetModeForStartup());
   }
 
   {
     base::test::ScopedCommandLine scoped_command_line;
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlog,
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlogMode,
                                                               kMemlogModeAll);
     EXPECT_EQ(Mode::kAll, GetModeForStartup());
   }
@@ -42,20 +42,20 @@
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        kMemlog, kMemlogModeBrowser);
+        kMemlogMode, kMemlogModeBrowser);
     EXPECT_EQ(Mode::kBrowser, GetModeForStartup());
   }
 
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        kMemlog, kMemlogModeMinimal);
+        kMemlogMode, kMemlogModeMinimal);
     EXPECT_EQ(Mode::kMinimal, GetModeForStartup());
   }
 
   {
     base::test::ScopedCommandLine scoped_command_line;
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlog,
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlogMode,
                                                               kMemlogModeGpu);
     EXPECT_EQ(Mode::kGpu, GetModeForStartup());
   }
@@ -63,7 +63,7 @@
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        kMemlog, kMemlogModeRendererSampling);
+        kMemlogMode, kMemlogModeRendererSampling);
     EXPECT_EQ(Mode::kRendererSampling, GetModeForStartup());
   }
 }
@@ -133,7 +133,7 @@
 // Ensure the commandline overrides any given field trial.
 TEST(HeapProfilingSwitches, GetModeForStartup_CommandLinePrecedence) {
   base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlog,
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlogMode,
                                                             kMemlogModeAll);
 
   base::test::ScopedFeatureList scoped_feature_list;
@@ -150,7 +150,7 @@
 TEST(HeapProfilingSwitches, GetModeForStartup_NoModeWithoutShim) {
   {
     base::test::ScopedCommandLine scoped_command_line;
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlog,
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kMemlogMode,
                                                               kMemlogModeAll);
     EXPECT_EQ(Mode::kNone, GetModeForStartup());
   }
diff --git a/components/signin/core/browser/about_signin_internals.cc b/components/signin/core/browser/about_signin_internals.cc
index b3965c08..6210b15 100644
--- a/components/signin/core/browser/about_signin_internals.cc
+++ b/components/signin/core/browser/about_signin_internals.cc
@@ -10,7 +10,7 @@
 #include <tuple>
 
 #include "base/command_line.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/i18n/time_formatting.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
diff --git a/components/signin/core/browser/account_investigator.cc b/components/signin/core/browser/account_investigator.cc
index 3389166..eaa7f06 100644
--- a/components/signin/core/browser/account_investigator.cc
+++ b/components/signin/core/browser/account_investigator.cc
@@ -8,8 +8,8 @@
 #include <iterator>
 
 #include "base/base64.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
-#include "base/sha1.h"
 #include "base/time/time.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
diff --git a/components/spellcheck/browser/spellcheck_host_metrics.cc b/components/spellcheck/browser/spellcheck_host_metrics.cc
index 1565b64..1daa2556 100644
--- a/components/spellcheck/browser/spellcheck_host_metrics.cc
+++ b/components/spellcheck/browser/spellcheck_host_metrics.cc
@@ -6,7 +6,7 @@
 
 #include <stdint.h>
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
 
diff --git a/components/sync/android/BUILD.gn b/components/sync/android/BUILD.gn
index d38c580..158f5b4 100644
--- a/components/sync/android/BUILD.gn
+++ b/components/sync/android/BUILD.gn
@@ -11,7 +11,7 @@
     "//components/signin/core/browser/android:java",
     "//net/android:net_java",
     "//third_party/android_deps:com_android_support_support_annotations_java",
-    "//third_party/android_tools:android_gcm_java",
+    "//third_party/android_sdk:android_gcm_java",
     "//third_party/cacheinvalidation:cacheinvalidation_javalib",
     "//third_party/cacheinvalidation:cacheinvalidation_proto_java",
     "//third_party/jsr-305:jsr_305_javalib",
diff --git a/components/sync/base/hash_util.cc b/components/sync/base/hash_util.cc
index 58924ff..e5e7a0f1 100644
--- a/components/sync/base/hash_util.cc
+++ b/components/sync/base/hash_util.cc
@@ -5,7 +5,7 @@
 #include "components/sync/base/hash_util.h"
 
 #include "base/base64.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "components/sync/protocol/sync.pb.h"
 
 namespace syncer {
diff --git a/components/sync/base/unique_position_unittest.cc b/components/sync/base/unique_position_unittest.cc
index be691b02..a7ac2f1 100644
--- a/components/sync/base/unique_position_unittest.cc
+++ b/components/sync/base/unique_position_unittest.cc
@@ -10,8 +10,8 @@
 #include <vector>
 
 #include "base/base64.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/sync/protocol/unique_position.pb.h"
diff --git a/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc b/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
index da378b1..a65a1a6d 100644
--- a/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
+++ b/components/sync/engine_impl/non_blocking_type_commit_contribution_unittest.cc
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "base/base64.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "components/sync/base/cryptographer.h"
 #include "components/sync/base/fake_encryptor.h"
 #include "components/sync/base/hash_util.h"
diff --git a/components/sync/model_impl/processor_entity.cc b/components/sync/model_impl/processor_entity.cc
index 81c3a48c..f497dc4 100644
--- a/components/sync/model_impl/processor_entity.cc
+++ b/components/sync/model_impl/processor_entity.cc
@@ -5,10 +5,10 @@
 #include "components/sync/model_impl/processor_entity.h"
 
 #include "base/base64.h"
+#include "base/hash/sha1.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/sha1.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/memory_usage_estimator.h"
 #include "components/sync/base/sync_base_switches.h"
diff --git a/components/sync/test/engine/mock_model_type_processor.cc b/components/sync/test/engine/mock_model_type_processor.cc
index f379d5f7..4c244ce 100644
--- a/components/sync/test/engine/mock_model_type_processor.cc
+++ b/components/sync/test/engine/mock_model_type_processor.cc
@@ -8,7 +8,7 @@
 
 #include "base/base64.h"
 #include "base/bind.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "components/sync/engine/commit_queue.h"
 
 namespace syncer {
diff --git a/components/sync/test/fake_server/fake_server.cc b/components/sync/test/fake_server/fake_server.cc
index 9f59b2d..8959f362 100644
--- a/components/sync/test/fake_server/fake_server.cc
+++ b/components/sync/test/fake_server/fake_server.cc
@@ -10,7 +10,7 @@
 #include <utility>
 
 #include "base/guid.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/components/sync_bookmarks/bookmark_model_associator.h b/components/sync_bookmarks/bookmark_model_associator.h
index 70873dc..1f4388a 100644
--- a/components/sync_bookmarks/bookmark_model_associator.h
+++ b/components/sync_bookmarks/bookmark_model_associator.h
@@ -17,7 +17,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/containers/stack.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.cc b/components/sync_bookmarks/synced_bookmark_tracker.cc
index f29f3bc5..9ab1747 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -9,8 +9,8 @@
 #include <utility>
 
 #include "base/base64.h"
+#include "base/hash/sha1.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/trace_event/memory_usage_estimator.h"
 #include "components/bookmarks/browser/bookmark_model.h"
diff --git a/components/sync_preferences/pref_model_associator.cc b/components/sync_preferences/pref_model_associator.cc
index 960f62e..1acf64c 100644
--- a/components/sync_preferences/pref_model_associator.cc
+++ b/components/sync_preferences/pref_model_associator.cc
@@ -177,6 +177,13 @@
     callback.Run();
 }
 
+void PrefModelAssociator::WaitUntilReadyToSync(base::OnceClosure done) {
+  // Prefs are loaded very early during profile initialization.
+  DCHECK_NE(pref_service_->GetAllPrefStoresInitializationStatus(),
+            PrefService::INITIALIZATION_STATUS_WAITING);
+  std::move(done).Run();
+}
+
 syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
     syncer::ModelType type,
     const syncer::SyncDataList& initial_sync_data,
diff --git a/components/sync_preferences/pref_model_associator.h b/components/sync_preferences/pref_model_associator.h
index 49413dd..ebf59e4 100644
--- a/components/sync_preferences/pref_model_associator.h
+++ b/components/sync_preferences/pref_model_associator.h
@@ -52,21 +52,21 @@
   bool models_associated() const { return models_associated_; }
 
   // syncer::SyncableService implementation.
-
-  // Note for GetAllSyncData: This will build a model of all preferences
-  // registered as syncable with user controlled data. We do not track any
-  // information for preferences not registered locally as syncable and do not
-  // inform the syncer of non-user controlled preferences.
-  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
-  syncer::SyncError ProcessSyncChanges(
-      const base::Location& from_here,
-      const syncer::SyncChangeList& change_list) override;
+  void WaitUntilReadyToSync(base::OnceClosure done) override;
   syncer::SyncMergeResult MergeDataAndStartSyncing(
       syncer::ModelType type,
       const syncer::SyncDataList& initial_sync_data,
       std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
       std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) override;
   void StopSyncing(syncer::ModelType type) override;
+  syncer::SyncError ProcessSyncChanges(
+      const base::Location& from_here,
+      const syncer::SyncChangeList& change_list) override;
+  // Note for GetAllSyncData: This will build a model of all preferences
+  // registered as syncable with user controlled data. We do not track any
+  // information for preferences not registered locally as syncable and do not
+  // inform the syncer of non-user controlled preferences.
+  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
 
   // TODO(tschumann): Replace the RegisterPref() call with a
   // VerifyPersistedPrefType() method. All pref registration checks are now
diff --git a/components/sync_sessions/favicon_cache.cc b/components/sync_sessions/favicon_cache.cc
index bae2883e..ca58d61f 100644
--- a/components/sync_sessions/favicon_cache.cc
+++ b/components/sync_sessions/favicon_cache.cc
@@ -12,6 +12,7 @@
 #include "base/stl_util.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/history/core/browser/history_service.h"
+#include "components/sync/model/sync_change_processor.h"
 #include "components/sync/model/time.h"
 #include "components/sync/protocol/favicon_image_specifics.pb.h"
 #include "components/sync/protocol/favicon_tracking_specifics.pb.h"
diff --git a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-25.png.sha1
new file mode 100644
index 0000000..5714e3f9
--- /dev/null
+++ b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-25.png.sha1
@@ -0,0 +1 @@
+9d6c493f9dfe09fce6eaca19349a88d149cb2898
\ No newline at end of file
diff --git a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-26.png.sha1
new file mode 100644
index 0000000..609f6d8
--- /dev/null
+++ b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-26.png.sha1
@@ -0,0 +1 @@
+6076800c2aa6ed0cd77881abfe553230a2529cd1
\ No newline at end of file
diff --git a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_ui.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_ui.Pixel_XL-25.png.sha1
new file mode 100644
index 0000000..2ffac7c
--- /dev/null
+++ b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_ui.Pixel_XL-25.png.sha1
@@ -0,0 +1 @@
+5b059a444e3784dbb88f752ebb71e8de67bc4b47
\ No newline at end of file
diff --git a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_ui.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_ui.Pixel_XL-26.png.sha1
new file mode 100644
index 0000000..54421d80
--- /dev/null
+++ b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_ui.Pixel_XL-26.png.sha1
@@ -0,0 +1 @@
+efede7a3778abeec24a1f1bb84fde8ee6f323f6f
\ No newline at end of file
diff --git a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_playing_not_hovered_browser_content.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_playing_not_hovered_browser_content.Pixel_XL-25.png.sha1
new file mode 100644
index 0000000..78b04d5
--- /dev/null
+++ b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_playing_not_hovered_browser_content.Pixel_XL-25.png.sha1
@@ -0,0 +1 @@
+5002005fafd691aed78c84e564654c74c619cc69
\ No newline at end of file
diff --git a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_playing_not_hovered_browser_content.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_playing_not_hovered_browser_content.Pixel_XL-26.png.sha1
new file mode 100644
index 0000000..e1eed6cb
--- /dev/null
+++ b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_playing_not_hovered_browser_content.Pixel_XL-26.png.sha1
@@ -0,0 +1 @@
+164972933d239fd6dda084f51d61dd39affe501d
\ No newline at end of file
diff --git a/components/ukm/ukm_service_unittest.cc b/components/ukm/ukm_service_unittest.cc
index ead2550..459282f 100644
--- a/components/ukm/ukm_service_unittest.cc
+++ b/components/ukm/ukm_service_unittest.cc
@@ -10,7 +10,7 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/metrics/metrics_hashes.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
diff --git a/components/variations/entropy_provider.cc b/components/variations/entropy_provider.cc
index d7eb868..23e040d 100644
--- a/components/variations/entropy_provider.cc
+++ b/components/variations/entropy_provider.cc
@@ -8,9 +8,9 @@
 #include <limits>
 #include <vector>
 
+#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/rand_util.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_byteorder.h"
 #include "components/variations/hashing.h"
diff --git a/components/variations/hashing.cc b/components/variations/hashing.cc
index 3383201f..8c82a82 100644
--- a/components/variations/hashing.cc
+++ b/components/variations/hashing.cc
@@ -6,7 +6,7 @@
 
 #include <string.h>
 
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/sys_byteorder.h"
 
 namespace variations {
diff --git a/components/visitedlink/common/visitedlink_common.cc b/components/visitedlink/common/visitedlink_common.cc
index 9d4fb7b..24cea0d 100644
--- a/components/visitedlink/common/visitedlink_common.cc
+++ b/components/visitedlink/common/visitedlink_common.cc
@@ -7,8 +7,8 @@
 #include <string.h>  // for memset()
 
 #include "base/bit_cast.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "url/gurl.h"
 
 namespace visitedlink {
diff --git a/components/viz/common/quads/render_pass.h b/components/viz/common/quads/render_pass.h
index a967fb9..ced1e18 100644
--- a/components/viz/common/quads/render_pass.h
+++ b/components/viz/common/quads/render_pass.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "cc/base/list_container.h"
 #include "cc/paint/filter_operations.h"
diff --git a/components/viz/common/resources/shared_bitmap.h b/components/viz/common/resources/shared_bitmap.h
index ed34c4f2..9f54695 100644
--- a/components/viz/common/resources/shared_bitmap.h
+++ b/components/viz/common/resources/shared_bitmap.h
@@ -8,7 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "components/viz/common/resources/resource_format.h"
diff --git a/components/viz/common/surfaces/frame_sink_id.h b/components/viz/common/surfaces/frame_sink_id.h
index 33687022..8d651b24e 100644
--- a/components/viz/common/surfaces/frame_sink_id.h
+++ b/components/viz/common/surfaces/frame_sink_id.h
@@ -11,7 +11,7 @@
 #include <string>
 #include <tuple>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/strings/string_piece.h"
 #include "components/viz/common/viz_common_export.h"
 
diff --git a/components/viz/common/surfaces/local_surface_id.h b/components/viz/common/surfaces/local_surface_id.h
index 7a832c0..5dfedf3 100644
--- a/components/viz/common/surfaces/local_surface_id.h
+++ b/components/viz/common/surfaces/local_surface_id.h
@@ -11,7 +11,7 @@
 #include <string>
 #include <tuple>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/unguessable_token.h"
 #include "components/viz/common/viz_common_export.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
diff --git a/components/viz/common/surfaces/surface_id.h b/components/viz/common/surfaces/surface_id.h
index e927a67..eb0345d 100644
--- a/components/viz/common/surfaces/surface_id.h
+++ b/components/viz/common/surfaces/surface_id.h
@@ -11,7 +11,7 @@
 #include <string>
 
 #include "base/format_macros.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
 #include "components/viz/common/viz_common_export.h"
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 46c62f8..8392dc6 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -311,6 +311,8 @@
   sources = [
     "display_embedder/skia_output_device.cc",
     "display_embedder/skia_output_device.h",
+    "display_embedder/skia_output_device_gl.cc",
+    "display_embedder/skia_output_device_gl.h",
     "display_embedder/skia_output_device_offscreen.cc",
     "display_embedder/skia_output_device_offscreen.h",
     "display_embedder/skia_output_surface_impl.cc",
diff --git a/components/viz/service/display_embedder/skia_output_device.cc b/components/viz/service/display_embedder/skia_output_device.cc
index 06aa1ede..2a3c81ee 100644
--- a/components/viz/service/display_embedder/skia_output_device.cc
+++ b/components/viz/service/display_embedder/skia_output_device.cc
@@ -4,9 +4,16 @@
 
 #include "components/viz/service/display_embedder/skia_output_device.h"
 
+#include <utility>
+
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/presentation_feedback.h"
+
 namespace viz {
 
-SkiaOutputDevice::SkiaOutputDevice() = default;
+SkiaOutputDevice::SkiaOutputDevice(
+    DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
+    : did_swap_buffer_complete_callback_(did_swap_buffer_complete_callback) {}
 
 SkiaOutputDevice::~SkiaOutputDevice() = default;
 
@@ -14,9 +21,45 @@
   return false;
 }
 
-gfx::SwapResult SkiaOutputDevice::PostSubBuffer(const gfx::Rect& rect) {
+gfx::SwapResponse SkiaOutputDevice::PostSubBuffer(
+    const gfx::Rect& rect,
+    BufferPresentedCallback feedback) {
   NOTREACHED();
-  return gfx::SwapResult::SWAP_FAILED;
+  StartSwapBuffers(std::move(feedback));
+  return FinishSwapBuffers(gfx::SwapResult::SWAP_FAILED);
+}
+
+void SkiaOutputDevice::StartSwapBuffers(
+    base::Optional<BufferPresentedCallback> feedback) {
+  DCHECK(!feedback_);
+  DCHECK(!params_);
+
+  feedback_ = std::move(feedback);
+  params_.emplace();
+  params_->swap_response.swap_id = ++swap_id_;
+  params_->swap_response.swap_start = base::TimeTicks::Now();
+}
+
+gfx::SwapResponse SkiaOutputDevice::FinishSwapBuffers(gfx::SwapResult result) {
+  DCHECK(params_);
+
+  params_->swap_response.result = result;
+  params_->swap_response.swap_end = base::TimeTicks::Now();
+  if (feedback_) {
+    std::move(*feedback_)
+        .Run(gfx::PresentationFeedback(
+            params_->swap_response.swap_start, base::TimeDelta() /* interval */,
+            params_->swap_response.result == gfx::SwapResult::SWAP_ACK
+                ? 0
+                : gfx::PresentationFeedback::Flags::kFailure));
+  }
+  did_swap_buffer_complete_callback_.Run(
+      *params_, gfx::Size(draw_surface_->width(), draw_surface_->height()));
+
+  feedback_.reset();
+  auto response = params_->swap_response;
+  params_.reset();
+  return response;
 }
 
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_device.h b/components/viz/service/display_embedder/skia_output_device.h
index feb6467e..c6c63cfa 100644
--- a/components/viz/service/display_embedder/skia_output_device.h
+++ b/components/viz/service/display_embedder/skia_output_device.h
@@ -5,35 +5,66 @@
 #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_H_
 #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_H_
 
+#include "base/callback.h"
 #include "base/macros.h"
+#include "base/optional.h"
+#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/swap_result.h"
 
 class SkSurface;
 
+namespace gfx {
+class ColorSpace;
+class Rect;
+class Size;
+struct PresentationFeedback;
+}  // namespace gfx
+
 namespace viz {
 
 class SkiaOutputDevice {
  public:
-  SkiaOutputDevice();
+  using BufferPresentedCallback =
+      base::OnceCallback<void(const gfx::PresentationFeedback& feedback)>;
+  using DidSwapBufferCompleteCallback =
+      base::RepeatingCallback<void(gpu::SwapBuffersCompleteParams,
+                                   const gfx::Size& pixel_size)>;
+  explicit SkiaOutputDevice(
+      DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
   virtual ~SkiaOutputDevice();
 
   // SkSurface that can be drawn to.
-  virtual sk_sp<SkSurface> DrawSurface() = 0;
+  sk_sp<SkSurface> DrawSurface() { return draw_surface_; }
 
   // Changes the size of draw surface and invalidates it's contents.
-  virtual void Reshape(const gfx::Size& size) = 0;
+  virtual void Reshape(const gfx::Size& size,
+                       float device_scale_factor,
+                       const gfx::ColorSpace& color_space,
+                       bool has_alpha) = 0;
 
   // Presents DrawSurface.
-  virtual gfx::SwapResult SwapBuffers() = 0;
+  virtual gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) = 0;
 
   virtual bool SupportPostSubBuffer();
 
-  virtual gfx::SwapResult PostSubBuffer(const gfx::Rect& rect);
+  virtual gfx::SwapResponse PostSubBuffer(const gfx::Rect& rect,
+                                          BufferPresentedCallback feedback);
+
+ protected:
+  void StartSwapBuffers(base::Optional<BufferPresentedCallback> feedback);
+  gfx::SwapResponse FinishSwapBuffers(gfx::SwapResult result);
+
+  sk_sp<SkSurface> draw_surface_;
 
  private:
+  uint64_t swap_id_ = 0;
+  DidSwapBufferCompleteCallback did_swap_buffer_complete_callback_;
+
+  // Only valid between StartSwapBuffers and FinishSwapBuffers.
+  base::Optional<BufferPresentedCallback> feedback_;
+  base::Optional<gpu::SwapBuffersCompleteParams> params_;
+
   DISALLOW_COPY_AND_ASSIGN(SkiaOutputDevice);
 };
 
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.cc b/components/viz/service/display_embedder/skia_output_device_gl.cc
new file mode 100644
index 0000000..17e151c
--- /dev/null
+++ b/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -0,0 +1,131 @@
+// 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 "components/viz/service/display_embedder/skia_output_device_gl.h"
+
+#include <utility>
+
+#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/ipc/service/image_transport_surface.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/core/SkSurfaceProps.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_version_info.h"
+
+namespace viz {
+
+SkiaOutputDeviceGL::SkiaOutputDeviceGL(
+    gpu::SurfaceHandle surface_handle,
+    scoped_refptr<gpu::gles2::FeatureInfo> feature_info,
+    const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback)
+    : SkiaOutputDevice(did_swap_buffer_complete_callback),
+      surface_handle_(surface_handle),
+      feature_info_(feature_info) {
+  DCHECK(surface_handle_);
+  gl_surface_ = gpu::ImageTransportSurface::CreateNativeSurface(
+      nullptr, surface_handle_, gl::GLSurfaceFormat());
+}
+
+void SkiaOutputDeviceGL::Initialize(GrContext* gr_context,
+                                    gl::GLContext* gl_context) {
+  DCHECK(gr_context);
+  DCHECK(gl_context);
+  gr_context_ = gr_context;
+
+  gl::CurrentGL* current_gl = gl_context->GetCurrentGL();
+  DCHECK(current_gl);
+
+  // Get alpha and stencil bits from the default frame buffer.
+  glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+  gr_context_->resetContext(kRenderTarget_GrGLBackendState);
+  const auto* version = current_gl->Version;
+  GLint stencil_bits = 0;
+  GLint alpha_bits = 0;
+  if (version->is_desktop_core_profile) {
+    glGetFramebufferAttachmentParameterivEXT(
+        GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
+        &stencil_bits);
+    glGetFramebufferAttachmentParameterivEXT(
+        GL_FRAMEBUFFER, GL_BACK_LEFT, GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
+        &alpha_bits);
+  } else {
+    glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
+    glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
+  }
+  CHECK_GL_ERROR();
+  supports_stencil_ = stencil_bits > 0;
+  supports_alpha_ = alpha_bits > 0;
+
+  supports_post_sub_buffer_ = gl_surface_->SupportsPostSubBuffer();
+  if (feature_info_->workarounds()
+          .disable_post_sub_buffers_for_onscreen_surfaces)
+    supports_post_sub_buffer_ = false;
+}
+
+SkiaOutputDeviceGL::~SkiaOutputDeviceGL() {}
+
+scoped_refptr<gl::GLSurface> SkiaOutputDeviceGL::gl_surface() {
+  return gl_surface_;
+}
+
+void SkiaOutputDeviceGL::Reshape(const gfx::Size& size,
+                                 float device_scale_factor,
+                                 const gfx::ColorSpace& color_space,
+                                 bool has_alpha) {
+  // Conversion to GLSurface's color space follows the same logic as in
+  // gl::GetGLColorSpace().
+  gl::GLSurface::ColorSpace surface_color_space =
+      color_space.IsHDR() ? gl::GLSurface::ColorSpace::SCRGB_LINEAR
+                          : gl::GLSurface::ColorSpace::UNSPECIFIED;
+  if (!gl_surface_->Resize(size, device_scale_factor, surface_color_space,
+                           has_alpha)) {
+    LOG(FATAL) << "Failed to resize.";
+    // TODO(penghuang): Handle the failure.
+  }
+  SkSurfaceProps surface_props =
+      SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
+
+  GrGLFramebufferInfo framebuffer_info;
+  framebuffer_info.fFBOID = gl_surface_->GetBackingFramebufferObject();
+  framebuffer_info.fFormat = supports_alpha_ ? GL_RGBA8 : GL_RGB8_OES;
+  GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8,
+                                      framebuffer_info);
+  auto origin = gl_surface_->FlipsVertically() ? kTopLeft_GrSurfaceOrigin
+                                               : kBottomLeft_GrSurfaceOrigin;
+  auto color_type =
+      supports_alpha_ ? kRGBA_8888_SkColorType : kRGB_888x_SkColorType;
+  draw_surface_ = SkSurface::MakeFromBackendRenderTarget(
+      gr_context_, render_target, origin, color_type,
+      color_space.ToSkColorSpace(), &surface_props);
+  DCHECK(draw_surface_);
+}
+
+gfx::SwapResponse SkiaOutputDeviceGL::SwapBuffers(
+    BufferPresentedCallback feedback) {
+  // TODO(backer): Support SwapBuffersAsync
+  StartSwapBuffers({});
+  return FinishSwapBuffers(gl_surface_->SwapBuffers(std::move(feedback)));
+}
+
+bool SkiaOutputDeviceGL::SupportPostSubBuffer() {
+  return supports_post_sub_buffer_;
+}
+
+gfx::SwapResponse SkiaOutputDeviceGL::PostSubBuffer(
+    const gfx::Rect& rect,
+    BufferPresentedCallback feedback) {
+  // TODO(backer): Support PostSubBufferAsync
+  StartSwapBuffers({});
+  return FinishSwapBuffers(gl_surface_->PostSubBuffer(
+      rect.x(), rect.y(), rect.width(), rect.height(), std::move(feedback)));
+}
+
+}  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.h b/components/viz/service/display_embedder/skia_output_device_gl.h
new file mode 100644
index 0000000..7740f31
--- /dev/null
+++ b/components/viz/service/display_embedder/skia_output_device_gl.h
@@ -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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_GL_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_GL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/viz/service/display_embedder/skia_output_device.h"
+#include "gpu/config/gpu_preferences.h"
+#include "gpu/ipc/common/surface_handle.h"
+
+class GrContext;
+
+namespace gl {
+class GLContext;
+class GLSurface;
+}  // namespace gl
+
+namespace gpu {
+namespace gles2 {
+class FeatureInfo;
+}  // namespace gles2
+}  // namespace gpu
+
+namespace viz {
+
+class SkiaOutputDeviceGL final : public SkiaOutputDevice {
+ public:
+  SkiaOutputDeviceGL(
+      gpu::SurfaceHandle surface_handle,
+      scoped_refptr<gpu::gles2::FeatureInfo> feature_info,
+      const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback);
+  ~SkiaOutputDeviceGL() override;
+
+  scoped_refptr<gl::GLSurface> gl_surface();
+  void Initialize(GrContext* gr_context, gl::GLContext* gl_context);
+  bool supports_alpha() {
+    DCHECK(gr_context_);
+    return supports_alpha_;
+  }
+  bool supports_stencil() {
+    DCHECK(gr_context_);
+    return supports_stencil_;
+  }
+
+  // SkiaOutputDevice implementation:
+  void Reshape(const gfx::Size& size,
+               float device_scale_factor,
+               const gfx::ColorSpace& color_space,
+               bool has_alpha) override;
+  gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) override;
+  bool SupportPostSubBuffer() override;
+  gfx::SwapResponse PostSubBuffer(const gfx::Rect& rect,
+                                  BufferPresentedCallback feedback) override;
+
+ private:
+  const gpu::SurfaceHandle surface_handle_;
+  scoped_refptr<gpu::gles2::FeatureInfo> feature_info_;
+  gpu::GpuPreferences gpu_preferences_;
+
+  GrContext* gr_context_ = nullptr;
+  scoped_refptr<gl::GLSurface> gl_surface_;
+  sk_sp<SkSurface> sk_surface_;
+
+  bool supports_alpha_ = false;
+  bool supports_stencil_ = false;
+  bool supports_post_sub_buffer_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(SkiaOutputDeviceGL);
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_GL_H_
diff --git a/components/viz/service/display_embedder/skia_output_device_offscreen.cc b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
index 0dc8cca..db50ec3 100644
--- a/components/viz/service/display_embedder/skia_output_device_offscreen.cc
+++ b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
@@ -4,22 +4,28 @@
 
 #include "components/viz/service/display_embedder/skia_output_device_offscreen.h"
 
+#include <utility>
+
 #include "third_party/skia/include/core/SkSurface.h"
 
 namespace viz {
 
-SkiaOutputDeviceOffscreen::SkiaOutputDeviceOffscreen(GrContext* gr_context,
-                                                     bool flipped,
-                                                     bool has_alpha)
-    : gr_context_(gr_context), flipped_(flipped), has_alpha_(has_alpha) {}
+SkiaOutputDeviceOffscreen::SkiaOutputDeviceOffscreen(
+    GrContext* gr_context,
+    bool flipped,
+    bool has_alpha,
+    DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
+    : SkiaOutputDevice(did_swap_buffer_complete_callback),
+      gr_context_(gr_context),
+      flipped_(flipped),
+      has_alpha_(has_alpha) {}
 
 SkiaOutputDeviceOffscreen::~SkiaOutputDeviceOffscreen() = default;
 
-sk_sp<SkSurface> SkiaOutputDeviceOffscreen::DrawSurface() {
-  return draw_surface_;
-}
-
-void SkiaOutputDeviceOffscreen::Reshape(const gfx::Size& size) {
+void SkiaOutputDeviceOffscreen::Reshape(const gfx::Size& size,
+                                        float device_scale_factor,
+                                        const gfx::ColorSpace& color_space,
+                                        bool has_alpha) {
   auto image_info = SkImageInfo::Make(
       size.width(), size.height(),
       has_alpha_ ? kRGBA_8888_SkColorType : kRGB_888x_SkColorType,
@@ -30,10 +36,13 @@
       nullptr /* surfaceProps */);
 }
 
-gfx::SwapResult SkiaOutputDeviceOffscreen::SwapBuffers() {
+gfx::SwapResponse SkiaOutputDeviceOffscreen::SwapBuffers(
+    BufferPresentedCallback feedback) {
   // Reshape should have been called first.
   DCHECK(draw_surface_);
-  return gfx::SwapResult::SWAP_ACK;
+
+  StartSwapBuffers(std::move(feedback));
+  return FinishSwapBuffers(gfx::SwapResult::SWAP_ACK);
 }
 
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_device_offscreen.h b/components/viz/service/display_embedder/skia_output_device_offscreen.h
index e870e46c..e3e77671 100644
--- a/components/viz/service/display_embedder/skia_output_device_offscreen.h
+++ b/components/viz/service/display_embedder/skia_output_device_offscreen.h
@@ -14,18 +14,22 @@
 
 class SkiaOutputDeviceOffscreen : public SkiaOutputDevice {
  public:
-  SkiaOutputDeviceOffscreen(GrContext* gr_context,
-                            bool flipped,
-                            bool has_alpha);
+  SkiaOutputDeviceOffscreen(
+      GrContext* gr_context,
+      bool flipped,
+      bool has_alpha,
+      DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
   ~SkiaOutputDeviceOffscreen() override;
 
-  sk_sp<SkSurface> DrawSurface() override;
-  void Reshape(const gfx::Size& size) override;
-  gfx::SwapResult SwapBuffers() override;
+  // SkiaOutputDevice implementation:
+  void Reshape(const gfx::Size& size,
+               float device_scale_factor,
+               const gfx::ColorSpace& color_space,
+               bool has_alpha) override;
+  gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) override;
 
  protected:
   GrContext* const gr_context_;
-  sk_sp<SkSurface> draw_surface_;
   const bool flipped_;
   const bool has_alpha_;
 
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
index dd07330e..bbb8be8 100644
--- a/components/viz/service/display_embedder/skia_output_device_vulkan.cc
+++ b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -4,6 +4,8 @@
 
 #include "components/viz/service/display_embedder/skia_output_device_vulkan.h"
 
+#include <utility>
+
 #include "build/build_config.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
 #include "gpu/ipc/common/gpu_surface_lookup.h"
@@ -17,19 +19,21 @@
 
 SkiaOutputDeviceVulkan::SkiaOutputDeviceVulkan(
     VulkanContextProvider* context_provider,
-    gpu::SurfaceHandle surface_handle)
-    : context_provider_(context_provider), surface_handle_(surface_handle) {}
+    gpu::SurfaceHandle surface_handle,
+    DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
+    : SkiaOutputDevice(did_swap_buffer_complete_callback),
+      context_provider_(context_provider),
+      surface_handle_(surface_handle) {}
 
 SkiaOutputDeviceVulkan::~SkiaOutputDeviceVulkan() {
   if (vulkan_surface_)
     vulkan_surface_->Destroy();
 }
 
-sk_sp<SkSurface> SkiaOutputDeviceVulkan::DrawSurface() {
-  return draw_surface_;
-}
-
-void SkiaOutputDeviceVulkan::Reshape(const gfx::Size& size) {
+void SkiaOutputDeviceVulkan::Reshape(const gfx::Size& size,
+                                     float device_scale_factor,
+                                     const gfx::ColorSpace& color_space,
+                                     bool has_alpha) {
   if (!vulkan_surface_)
     CreateVulkanSurface();
 
@@ -45,11 +49,13 @@
   UpdateDrawSurface();
 }
 
-gfx::SwapResult SkiaOutputDeviceVulkan::SwapBuffers() {
+gfx::SwapResponse SkiaOutputDeviceVulkan::SwapBuffers(
+    BufferPresentedCallback feedback) {
   // Reshape should have been called first.
   DCHECK(vulkan_surface_);
   DCHECK(draw_surface_);
 
+  StartSwapBuffers(std::move(feedback));
   auto backend = draw_surface_->getBackendRenderTarget(
       SkSurface::kFlushRead_BackendHandleAccess);
   GrVkImageInfo vk_image_info;
@@ -57,11 +63,11 @@
     NOTREACHED() << "Failed to get the image info.";
   vulkan_surface_->GetSwapChain()->SetCurrentImageLayout(
       vk_image_info.fImageLayout);
-  auto result = vulkan_surface_->SwapBuffers();
+  auto response = FinishSwapBuffers(vulkan_surface_->SwapBuffers());
 
   UpdateDrawSurface();
 
-  return result;
+  return response;
 }
 
 void SkiaOutputDeviceVulkan::CreateVulkanSurface() {
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan.h b/components/viz/service/display_embedder/skia_output_device_vulkan.h
index 0c8d9b6..2d538ac 100644
--- a/components/viz/service/display_embedder/skia_output_device_vulkan.h
+++ b/components/viz/service/display_embedder/skia_output_device_vulkan.h
@@ -20,15 +20,20 @@
 
 class VulkanContextProvider;
 
-class SkiaOutputDeviceVulkan : public SkiaOutputDevice {
+class SkiaOutputDeviceVulkan final : public SkiaOutputDevice {
  public:
-  SkiaOutputDeviceVulkan(VulkanContextProvider* context_provider,
-                         gpu::SurfaceHandle surface_handle);
+  SkiaOutputDeviceVulkan(
+      VulkanContextProvider* context_provider,
+      gpu::SurfaceHandle surface_handle,
+      DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
   ~SkiaOutputDeviceVulkan() override;
 
-  sk_sp<SkSurface> DrawSurface() override;
-  void Reshape(const gfx::Size& size) override;
-  gfx::SwapResult SwapBuffers() override;
+  // SkiaOutputDevice implementation:
+  void Reshape(const gfx::Size& size,
+               float device_scale_factor,
+               const gfx::ColorSpace& color_space,
+               bool has_alpha) override;
+  gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) override;
 
  private:
   void CreateVulkanSurface();
@@ -42,9 +47,6 @@
   // SkSurfaces for swap chain images.
   std::vector<sk_sp<SkSurface>> sk_surfaces_;
 
-  // SkSurface to be drawn to. Updated after Reshape and SwapBuffers.
-  sk_sp<SkSurface> draw_surface_;
-
   DISALLOW_COPY_AND_ASSIGN(SkiaOutputDeviceVulkan);
 };
 
diff --git a/components/viz/service/display_embedder/skia_output_device_x11.cc b/components/viz/service/display_embedder/skia_output_device_x11.cc
index b55a683..f5ef89b 100644
--- a/components/viz/service/display_embedder/skia_output_device_x11.cc
+++ b/components/viz/service/display_embedder/skia_output_device_x11.cc
@@ -4,6 +4,8 @@
 
 #include "components/viz/service/display_embedder/skia_output_device_x11.h"
 
+#include <utility>
+
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/vk/GrVkTypes.h"
@@ -13,11 +15,14 @@
 
 namespace viz {
 
-SkiaOutputDeviceX11::SkiaOutputDeviceX11(GrContext* gr_context,
-                                         gfx::AcceleratedWidget widget)
+SkiaOutputDeviceX11::SkiaOutputDeviceX11(
+    GrContext* gr_context,
+    gfx::AcceleratedWidget widget,
+    DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
     : SkiaOutputDeviceOffscreen(gr_context,
                                 false /* flipped */,
-                                true /* has_alpha */),
+                                true /* has_alpha */,
+                                did_swap_buffer_complete_callback),
       display_(gfx::GetXDisplay()),
       widget_(widget),
       gc_(XCreateGC(display_, widget_, 0, nullptr)) {
@@ -32,23 +37,33 @@
   XFreeGC(display_, gc_);
 }
 
-void SkiaOutputDeviceX11::Reshape(const gfx::Size& size) {
-  SkiaOutputDeviceOffscreen::Reshape(size);
+void SkiaOutputDeviceX11::Reshape(const gfx::Size& size,
+                                  float device_scale_factor,
+                                  const gfx::ColorSpace& color_space,
+                                  bool has_alpha) {
+  SkiaOutputDeviceOffscreen::Reshape(size, device_scale_factor, color_space,
+                                     has_alpha);
   auto ii =
       SkImageInfo::MakeN32(size.width(), size.height(), kOpaque_SkAlphaType);
   pixels_.reserve(ii.computeMinByteSize());
 }
 
-gfx::SwapResult SkiaOutputDeviceX11::SwapBuffers() {
+gfx::SwapResponse SkiaOutputDeviceX11::SwapBuffers(
+    BufferPresentedCallback feedback) {
   return PostSubBuffer(
-      gfx::Rect(0, 0, draw_surface_->width(), draw_surface_->height()));
+      gfx::Rect(0, 0, draw_surface_->width(), draw_surface_->height()),
+      std::move(feedback));
 }
 
 bool SkiaOutputDeviceX11::SupportPostSubBuffer() {
   return true;
 }
 
-gfx::SwapResult SkiaOutputDeviceX11::PostSubBuffer(const gfx::Rect& rect) {
+gfx::SwapResponse SkiaOutputDeviceX11::PostSubBuffer(
+    const gfx::Rect& rect,
+    BufferPresentedCallback feedback) {
+  StartSwapBuffers(std::move(feedback));
+
   auto ii =
       SkImageInfo::MakeN32(rect.width(), rect.height(), kOpaque_SkAlphaType);
   DCHECK_GE(pixels_.capacity(), ii.computeMinByteSize());
@@ -114,7 +129,7 @@
     NOTIMPLEMENTED();
   }
   XFlush(display_);
-  return gfx::SwapResult::SWAP_ACK;
+  return FinishSwapBuffers(gfx::SwapResult::SWAP_ACK);
 }
 
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_device_x11.h b/components/viz/service/display_embedder/skia_output_device_x11.h
index 307a348..8642d58 100644
--- a/components/viz/service/display_embedder/skia_output_device_x11.h
+++ b/components/viz/service/display_embedder/skia_output_device_x11.h
@@ -17,13 +17,20 @@
 
 class SkiaOutputDeviceX11 final : public SkiaOutputDeviceOffscreen {
  public:
-  SkiaOutputDeviceX11(GrContext* gr_context, gfx::AcceleratedWidget widget);
+  SkiaOutputDeviceX11(
+      GrContext* gr_context,
+      gfx::AcceleratedWidget widget,
+      DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
   ~SkiaOutputDeviceX11() override;
 
-  void Reshape(const gfx::Size& size) override;
-  gfx::SwapResult SwapBuffers() override;
+  void Reshape(const gfx::Size& size,
+               float device_scale_factor,
+               const gfx::ColorSpace& color_space,
+               bool has_alpha) override;
+  gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) override;
   bool SupportPostSubBuffer() override;
-  gfx::SwapResult PostSubBuffer(const gfx::Rect& rect) override;
+  gfx::SwapResponse PostSubBuffer(const gfx::Rect& rect,
+                                  BufferPresentedCallback feedback) override;
 
  private:
   XDisplay* const display_;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 325fd23..dff485d 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -18,6 +18,7 @@
 #include "components/viz/service/display/texture_deleter.h"
 #include "components/viz/service/display_embedder/direct_context_provider.h"
 #include "components/viz/service/display_embedder/skia_output_device.h"
+#include "components/viz/service/display_embedder/skia_output_device_gl.h"
 #include "components/viz/service/display_embedder/skia_output_device_offscreen.h"
 #include "components/viz/service/gl/gpu_service_impl.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
@@ -356,45 +357,13 @@
         base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
   }
 
-  if (!is_using_vulkan()) {
-    if (!MakeCurrent(surface_handle_ /* need_fbo0 */))
-      return;
-    size_ = size;
-    color_space_ = color_space;
-    if (output_device_) {
-      output_device_->Reshape(size_);
-      sk_surface_ = output_device_->DrawSurface();
-    } else {
-      // Conversion to GLSurface's color space follows the same logic as in
-      // gl::GetGLColorSpace().
-      gl::GLSurface::ColorSpace surface_color_space =
-          color_space.IsHDR() ? gl::GLSurface::ColorSpace::SCRGB_LINEAR
-                              : gl::GLSurface::ColorSpace::UNSPECIFIED;
-      if (!gl_surface_->Resize(size, device_scale_factor, surface_color_space,
-                               has_alpha)) {
-        LOG(FATAL) << "Failed to resize.";
-        // TODO(penghuang): Handle the failure.
-      }
-      CreateSkSurfaceForGL();
-    }
-  } else {
-#if BUILDFLAG(ENABLE_VULKAN)
-    if (!output_device_) {
-      if (surface_handle_ == gpu::kNullSurfaceHandle) {
-        output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
-            gr_context(), false /* flipped */,
-            renderer_settings_.requires_alpha_channel);
-      } else {
-        output_device_ = std::make_unique<SkiaOutputDeviceVulkan>(
-            vulkan_context_provider_, surface_handle_);
-      }
-    }
-    output_device_->Reshape(size);
-    sk_surface_ = output_device_->DrawSurface();
-#else
-    NOTREACHED();
-#endif
-  }
+  if (!MakeCurrent(surface_handle_ /* need_fbo0 */))
+    return;
+
+  size_ = size;
+  color_space_ = color_space;
+  output_device_->Reshape(size_, device_scale_factor, color_space, has_alpha);
+  sk_surface_ = output_device_->DrawSurface();
 
   if (characterization) {
     sk_surface_->characterize(characterization);
@@ -457,37 +426,26 @@
   if (!MakeCurrent(surface_handle_ /* need_fbo0 */))
     return;
 
-  base::TimeTicks swap_start = base::TimeTicks::Now();
-  OnSwapBuffers();
-
-  base::TimeTicks swap_end;
-  if (output_device_) {
-    gpu::SwapBuffersCompleteParams params;
-    params.swap_response.swap_start = swap_start;
-    if (capabilities_.supports_post_sub_buffer) {
-      DCHECK(frame.sub_buffer_rect);
-      DCHECK(!frame.sub_buffer_rect->IsEmpty());
-      params.swap_response.result =
-          output_device_->PostSubBuffer(*frame.sub_buffer_rect);
-    } else {
-      params.swap_response.result = output_device_->SwapBuffers();
-    }
-    swap_end = params.swap_response.swap_end = base::TimeTicks::Now();
-    sk_surface_ = output_device_->DrawSurface();
-    DidSwapBuffersComplete(params);
-    buffer_presented_callback_.Run(gfx::PresentationFeedback(
-        params.swap_response.swap_end, base::TimeDelta(), 0 /* flag */));
-
+  DCHECK(output_device_);
+  gfx::SwapResponse response;
+  if (capabilities_.supports_post_sub_buffer) {
+    DCHECK(frame.sub_buffer_rect);
+    DCHECK(!frame.sub_buffer_rect->IsEmpty());
+    if (!capabilities_.flipped_output_surface)
+      frame.sub_buffer_rect->set_y(size_.height() - frame.sub_buffer_rect->y() -
+                                   frame.sub_buffer_rect->height());
+    response = output_device_->PostSubBuffer(*frame.sub_buffer_rect,
+                                             buffer_presented_callback_);
   } else {
-    DCHECK(!is_using_vulkan());
-    gl_surface_->SwapBuffers(buffer_presented_callback_);
-    swap_end = base::TimeTicks::Now();
+    response = output_device_->SwapBuffers(buffer_presented_callback_);
   }
+  sk_surface_ = output_device_->DrawSurface();
+
   for (auto& latency : frame.latency_info) {
     latency.AddLatencyNumberWithTimestamp(
-        ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, swap_start, 1);
+        ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, response.swap_start, 1);
     latency.AddLatencyNumberWithTimestamp(
-        ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT, swap_end, 1);
+        ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT, response.swap_end, 1);
   }
   latency_tracker_.OnGpuSwapBuffersCompleted(frame.latency_info);
 }
@@ -580,7 +538,7 @@
     bool flipped = from_fbo0 ? !capabilities_.flipped_output_surface : false;
 
     base::Optional<ScopedSurfaceToTexture> texture_mapper;
-    if (!from_fbo0 || output_device_) {
+    if (!from_fbo0 || surface_handle_ == gpu::kNullSurfaceHandle) {
       texture_mapper.emplace(context_provider_.get(), surface);
       gl_id = texture_mapper.value().client_id();
       internal_format = GL_RGBA;
@@ -791,141 +749,83 @@
   capabilities_ = capabilities;
   output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
       gr_context(), capabilities_.flipped_output_surface,
-      renderer_settings_.requires_alpha_channel);
+      renderer_settings_.requires_alpha_channel,
+      did_swap_buffer_complete_callback_);
 }
 
-#if defined(OS_WIN)
-void SkiaOutputSurfaceImplOnGpu::DidCreateAcceleratedSurfaceChildWindow(
-    gpu::SurfaceHandle parent_window,
-    gpu::SurfaceHandle child_window) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  NOTIMPLEMENTED();
-}
-#endif
+void SkiaOutputSurfaceImplOnGpu::InitializeForGLWithGpuService(
+    GpuServiceImpl* gpu_service) {
+  std::unique_ptr<SkiaOutputDeviceGL> onscreen_device;
+  if (surface_handle_) {
+    onscreen_device = std::make_unique<SkiaOutputDeviceGL>(
+        surface_handle_, feature_info_, did_swap_buffer_complete_callback_);
+    gl_surface_ = onscreen_device->gl_surface();
+  } else {
+    gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
+  }
+  DCHECK(gl_surface_);
 
-void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersComplete(
-    gpu::SwapBuffersCompleteParams params) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  params.swap_response.swap_id = pending_swap_completed_params_.front().first;
-  gfx::Size pixel_size = pending_swap_completed_params_.front().second;
-  pending_swap_completed_params_.pop_front();
-  did_swap_buffer_complete_callback_.Run(params, pixel_size);
-}
-
-const gpu::gles2::FeatureInfo* SkiaOutputSurfaceImplOnGpu::GetFeatureInfo()
-    const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return feature_info_.get();
-}
-
-const gpu::GpuPreferences& SkiaOutputSurfaceImplOnGpu::GetGpuPreferences()
-    const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  NOTIMPLEMENTED();
-  return gpu_preferences_;
-}
-
-void SkiaOutputSurfaceImplOnGpu::BufferPresented(
-    const gfx::PresentationFeedback& feedback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void SkiaOutputSurfaceImplOnGpu::AddFilter(IPC::MessageFilter* message_filter) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  NOTIMPLEMENTED();
-}
-
-int32_t SkiaOutputSurfaceImplOnGpu::GetRouteID() const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-void SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
-  if (!MakeCurrent(true /* need_fbo0 */))
-    return;
+  context_state_ = gpu_service->GetContextState();
+  if (!context_state_) {
+    LOG(FATAL) << "Failed to create GrContext";
+    // TODO(penghuang): handle the failure.
+  }
 
   auto* context = context_state_->real_context();
   auto* current_gl = context->GetCurrentGL();
   api_ = current_gl->Api;
   gl_version_info_ = context->GetVersionInfo();
 
-  if (surface_handle_) {
-    capabilities_.flipped_output_surface = gl_surface_->FlipsVertically();
-
-    // Get alpha and stencil bits from the default frame buffer.
-    api_->glBindFramebufferEXTFn(GL_FRAMEBUFFER, 0);
-    gr_context()->resetContext(kRenderTarget_GrGLBackendState);
-    const auto* version = current_gl->Version;
-    GLint stencil_bits = 0;
-    GLint alpha_bits = 0;
-    if (version->is_desktop_core_profile) {
-      api_->glGetFramebufferAttachmentParameterivEXTFn(
-          GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
-          &stencil_bits);
-      api_->glGetFramebufferAttachmentParameterivEXTFn(
-          GL_FRAMEBUFFER, GL_BACK_LEFT, GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
-          &alpha_bits);
-    } else {
-      api_->glGetIntegervFn(GL_STENCIL_BITS, &stencil_bits);
-      api_->glGetIntegervFn(GL_ALPHA_BITS, &alpha_bits);
+  if (onscreen_device) {
+    if (!MakeCurrent(true /* need_fbo0 */)) {
+      LOG(FATAL) << "Failed to make current during initialization.";
+      return;
     }
-    CHECK_GL_ERROR();
-    capabilities_.supports_stencil = stencil_bits > 0;
-    supports_alpha_ = alpha_bits > 0;
-  }
-}
-
-void SkiaOutputSurfaceImplOnGpu::InitializeForGLWithGpuService(
-    GpuServiceImpl* gpu_service) {
-  if (surface_handle_) {
-    gl_surface_ = gpu::ImageTransportSurface::CreateNativeSurface(
-        weak_ptr_factory_.GetWeakPtr(), surface_handle_, gl::GLSurfaceFormat());
+    onscreen_device->Initialize(gr_context(), context);
+    capabilities_.flipped_output_surface = gl_surface_->FlipsVertically();
+    capabilities_.supports_stencil = onscreen_device->supports_stencil();
+    supports_alpha_ = onscreen_device->supports_alpha();
+    output_device_ = std::move(onscreen_device);
   } else {
-    gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
-  }
-  DCHECK(gl_surface_);
-
-  context_state_ = gpu_service->GetContextStateForGLSurface(gl_surface_.get());
-  if (!context_state_) {
-    LOG(FATAL) << "Failed to create GrContext";
-    // TODO(penghuang): handle the failure.
-  }
-  if (!surface_handle_) {
     output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
         gr_context(), true /* flipped */,
-        renderer_settings_.requires_alpha_channel);
+        renderer_settings_.requires_alpha_channel,
+        did_swap_buffer_complete_callback_);
     capabilities_.flipped_output_surface = true;
     capabilities_.supports_stencil = false;
     supports_alpha_ = renderer_settings_.requires_alpha_channel;
   }
-  InitializeForGL();
+  capabilities_.supports_post_sub_buffer =
+      output_device_->SupportPostSubBuffer();
 }
 
 void SkiaOutputSurfaceImplOnGpu::InitializeForVulkan(
     GpuServiceImpl* gpu_service) {
-  context_state_ = gpu_service->GetContextStateForVulkan();
+  context_state_ = gpu_service->GetContextState();
   DCHECK(context_state_);
   capabilities_.flipped_output_surface = true;
 #if BUILDFLAG(ENABLE_VULKAN)
   if (surface_handle_ == gpu::kNullSurfaceHandle) {
     output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
         gr_context(), false /* flipped */,
-        renderer_settings_.requires_alpha_channel);
+        renderer_settings_.requires_alpha_channel,
+        did_swap_buffer_complete_callback_);
     supports_alpha_ = renderer_settings_.requires_alpha_channel;
   } else {
 #if defined(USE_X11)
     supports_alpha_ = true;
     if (gpu_preferences_.disable_vulkan_surface) {
-      output_device_ =
-          std::make_unique<SkiaOutputDeviceX11>(gr_context(), surface_handle_);
+      output_device_ = std::make_unique<SkiaOutputDeviceX11>(
+          gr_context(), surface_handle_, did_swap_buffer_complete_callback_);
     } else {
       output_device_ = std::make_unique<SkiaOutputDeviceVulkan>(
-          vulkan_context_provider_, surface_handle_);
+          vulkan_context_provider_, surface_handle_,
+          did_swap_buffer_complete_callback_);
     }
 #else
     output_device_ = std::make_unique<SkiaOutputDeviceVulkan>(
-        vulkan_context_provider_, surface_handle_);
+        vulkan_context_provider_, surface_handle_,
+        did_swap_buffer_complete_callback_);
 #endif
   }
   capabilities_.supports_post_sub_buffer =
@@ -960,32 +860,6 @@
   }
 }
 
-void SkiaOutputSurfaceImplOnGpu::OnSwapBuffers() {
-  uint64_t swap_id = swap_id_++;
-  gfx::Size pixel_size(sk_surface_->width(), sk_surface_->height());
-  pending_swap_completed_params_.emplace_back(swap_id, pixel_size);
-}
-
-void SkiaOutputSurfaceImplOnGpu::CreateSkSurfaceForGL() {
-  SkSurfaceProps surface_props =
-      SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
-
-  GrGLFramebufferInfo framebuffer_info;
-  framebuffer_info.fFBOID = gl_surface_->GetBackingFramebufferObject();
-  framebuffer_info.fFormat = supports_alpha_ ? GL_RGBA8 : GL_RGB8_OES;
-  GrBackendRenderTarget render_target(size_.width(), size_.height(), 0, 8,
-                                      framebuffer_info);
-  auto origin = capabilities_.flipped_output_surface
-                    ? kTopLeft_GrSurfaceOrigin
-                    : kBottomLeft_GrSurfaceOrigin;
-  auto color_type =
-      supports_alpha_ ? kRGBA_8888_SkColorType : kRGB_888x_SkColorType;
-  sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
-      gr_context(), render_target, origin, color_type,
-      color_space_.ToSkColorSpace(), &surface_props);
-  DCHECK(sk_surface_);
-}
-
 bool SkiaOutputSurfaceImplOnGpu::MakeCurrent(bool need_fbo0) {
   if (!is_using_vulkan()) {
     // Only make current with |gl_surface_|, if following operations will use
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 1e1e1f4..f872840c 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -69,7 +69,7 @@
 
 // The SkiaOutputSurface implementation running on the GPU thread. This class
 // should be created, used and destroyed on the GPU thread.
-class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
+class SkiaOutputSurfaceImplOnGpu {
  public:
   using DidSwapBufferCompleteCallback =
       base::RepeatingCallback<void(gpu::SwapBuffersCompleteParams,
@@ -98,7 +98,7 @@
       const BufferPresentedCallback& buffer_presented_callback,
       const ContextLostCallback& context_lost_callback);
 
-  ~SkiaOutputSurfaceImplOnGpu() override;
+  ~SkiaOutputSurfaceImplOnGpu();
 
   gpu::CommandBufferId command_buffer_id() const {
     return sync_point_client_state_->command_buffer_id();
@@ -160,33 +160,11 @@
       const OutputSurface::Capabilities& capabilities);
 
  private:
-// gpu::ImageTransportSurfaceDelegate implementation:
-#if defined(OS_WIN)
-  void DidCreateAcceleratedSurfaceChildWindow(
-      gpu::SurfaceHandle parent_window,
-      gpu::SurfaceHandle child_window) override;
-#endif
-  void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params) override;
-  const gpu::gles2::FeatureInfo* GetFeatureInfo() const override;
-  const gpu::GpuPreferences& GetGpuPreferences() const override;
-  void BufferPresented(const gfx::PresentationFeedback& feedback) override;
-  void AddFilter(IPC::MessageFilter* message_filter) override;
-  int32_t GetRouteID() const override;
-
-  void InitializeForGL();
   void InitializeForGLWithGpuService(GpuServiceImpl* gpu_service);
-  void InitializeForGLWithTaskExecutor(
-      gpu::CommandBufferTaskExecutor* task_executor,
-      scoped_refptr<gl::GLSurface> gl_surface);
   void InitializeForVulkan(GpuServiceImpl* gpu_service);
 
   void BindOrCopyTextureIfNecessary(gpu::TextureBase* texture_base);
 
-  // Generage the next swap ID and push it to our pending swap ID queues.
-  void OnSwapBuffers();
-
-  void CreateSkSurfaceForGL();
-
   // Make context current for GL, and return false if the context is lost.
   // It will do nothing when Vulkan is used.
   bool MakeCurrent(bool need_fbo0);
@@ -253,12 +231,6 @@
   };
   base::flat_map<RenderPassId, OffscreenSurface> offscreen_surfaces_;
 
-  // Params are pushed each time we begin a swap, and popped each time we
-  // present or complete a swap.
-  base::circular_deque<std::pair<uint64_t, gfx::Size>>
-      pending_swap_completed_params_;
-  uint64_t swap_id_ = 0;
-
   ui::LatencyTracker latency_tracker_;
 
   scoped_refptr<base::SingleThreadTaskRunner> context_current_task_runner_;
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index 8abfccc..34ae888a 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -299,23 +299,8 @@
   (*gpu_host_)->DisableGpuCompositing();
 }
 
-scoped_refptr<gpu::SharedContextState>
-GpuServiceImpl::GetContextStateForGLSurface(gl::GLSurface* surface) {
+scoped_refptr<gpu::SharedContextState> GpuServiceImpl::GetContextState() {
   DCHECK(main_runner_->BelongsToCurrentThread());
-  DCHECK(!is_using_vulkan());
-  gpu::ContextResult result;
-  auto context_state = gpu_channel_manager_->GetSharedContextState(&result);
-  // TODO(penghuang): https://crbug.com/899740 Support GLSurface which is not
-  // compatible.
-  DCHECK_EQ(surface->GetCompatibilityKey(),
-            context_state->surface()->GetCompatibilityKey());
-  return context_state;
-}
-
-scoped_refptr<gpu::SharedContextState>
-GpuServiceImpl::GetContextStateForVulkan() {
-  DCHECK(main_runner_->BelongsToCurrentThread());
-  DCHECK(is_using_vulkan());
   gpu::ContextResult result;
   return gpu_channel_manager_->GetSharedContextState(&result);
 }
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h
index f510072..dcc3462 100644
--- a/components/viz/service/gl/gpu_service_impl.h
+++ b/components/viz/service/gl/gpu_service_impl.h
@@ -90,9 +90,7 @@
       base::WaitableEvent* shutdown_event = nullptr);
   void Bind(mojom::GpuServiceRequest request);
 
-  scoped_refptr<gpu::SharedContextState> GetContextStateForGLSurface(
-      gl::GLSurface* surface);
-  scoped_refptr<gpu::SharedContextState> GetContextStateForVulkan();
+  scoped_refptr<gpu::SharedContextState> GetContextState();
 
   // Notifies the GpuHost to stop using GPU compositing. This should be called
   // in response to an error in the GPU process that occurred after
diff --git a/components/viz/service/surfaces/surface_reference.h b/components/viz/service/surfaces/surface_reference.h
index 6085a9b..b07f01e 100644
--- a/components/viz/service/surfaces/surface_reference.h
+++ b/components/viz/service/surfaces/surface_reference.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/service/viz_service_export.h"
 
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn
index 727f5f9..75a7d95 100644
--- a/content/app/BUILD.gn
+++ b/content/app/BUILD.gn
@@ -58,7 +58,7 @@
       "//media/midi",
       "//net",
       "//skia",
-      "//third_party/android_tools:cpu_features",
+      "//third_party/android_sdk:cpu_features",
       "//ui/android",
       "//ui/events",
       "//ui/shell_dialogs",
diff --git a/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc b/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
index 40acf21..481a8c6 100644
--- a/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/test_browser_accessibility_delegate.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/platform/ax_platform_node_auralinux.h"
@@ -21,6 +22,10 @@
   BrowserAccessibilityAuraLinuxTest();
   ~BrowserAccessibilityAuraLinuxTest() override;
 
+ protected:
+  std::unique_ptr<TestBrowserAccessibilityDelegate>
+      test_browser_accessibility_delegate_;
+
  private:
   void SetUp() override;
 
@@ -33,7 +38,10 @@
 
 BrowserAccessibilityAuraLinuxTest::~BrowserAccessibilityAuraLinuxTest() {}
 
-void BrowserAccessibilityAuraLinuxTest::SetUp() {}
+void BrowserAccessibilityAuraLinuxTest::SetUp() {
+  test_browser_accessibility_delegate_ =
+      std::make_unique<TestBrowserAccessibilityDelegate>();
+}
 
 TEST_F(BrowserAccessibilityAuraLinuxTest, TestSimpleAtkText) {
   ui::AXNodeData root_data;
@@ -42,8 +50,10 @@
   root_data.SetName("\xE2\x98\xBA Multiple Words");
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
-      BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root_data), nullptr,
-                                          new BrowserAccessibilityFactory()));
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root_data),
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ui::AXPlatformNodeAuraLinux* root_obj =
       ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
@@ -94,9 +104,10 @@
   root.child_ids.push_back(text2.id);
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
-      BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root, text1, text2),
-                                          nullptr,
-                                          new BrowserAccessibilityFactory()));
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root, text1, text2),
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ui::AXPlatformNodeAuraLinux* root_obj =
       ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
@@ -199,7 +210,8 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, text1, combo_box, text2, check_box, button,
                            button_text, link, link_text),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ui::AXPlatformNodeAuraLinux* root_obj =
       ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index c5068cc..d785b61 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -1271,7 +1271,7 @@
 }
 
 bool BrowserAccessibilityManager::IsRootTree() {
-  return GetRootManager() == this;
+  return delegate()->AccessibilityIsMainFrame();
 }
 
 ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 9ec676f..3bc89525 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -88,6 +88,10 @@
   virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() = 0;
   virtual gfx::NativeViewAccessible
   AccessibilityGetNativeViewAccessibleForWindow() = 0;
+
+  // Returns true if this delegate represents the main (topmost) frame in a
+  // tree of frames.
+  virtual bool AccessibilityIsMainFrame() = 0;
 };
 
 class CONTENT_EXPORT BrowserAccessibilityFactory {
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index c3afc10..a8ac524 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -225,6 +225,7 @@
     case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
     case ui::AXEventGenerator::Event::READONLY_CHANGED:
     case ui::AXEventGenerator::Event::RELATED_NODE_CHANGED:
+    case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
     case ui::AXEventGenerator::Event::ROLE_CHANGED:
     case ui::AXEventGenerator::Event::ROW_COUNT_CHANGED:
     case ui::AXEventGenerator::Event::SELECTED_CHANGED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 26bb49c..96e0f3f0 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -395,6 +395,7 @@
     case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
     case ui::AXEventGenerator::Event::READONLY_CHANGED:
     case ui::AXEventGenerator::Event::RELATED_NODE_CHANGED:
+    case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
     case ui::AXEventGenerator::Event::ROLE_CHANGED:
     case ui::AXEventGenerator::Event::SCROLL_POSITION_CHANGED:
     case ui::AXEventGenerator::Event::SELECTED_CHANGED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index 17ec486d..4ac2bbc 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -14,6 +14,7 @@
 #if defined(OS_WIN)
 #include "content/browser/accessibility/browser_accessibility_win.h"
 #endif
+#include "content/browser/accessibility/test_browser_accessibility_delegate.h"
 #include "content/public/browser/ax_event_notification_details.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -37,6 +38,8 @@
       delete this;
   }
 
+  bool CanFireEvents() const override { return false; }
+
   int native_ref_count_;
   static int global_obj_count_;
 };
@@ -52,33 +55,6 @@
   }
 };
 
-class TestBrowserAccessibilityDelegate : public BrowserAccessibilityDelegate {
- public:
-  TestBrowserAccessibilityDelegate() : got_fatal_error_(false) {}
-
-  void AccessibilityPerformAction(const ui::AXActionData& data) override {}
-  bool AccessibilityViewHasFocus() const override { return false; }
-  gfx::Rect AccessibilityGetViewBounds() const override { return gfx::Rect(); }
-  float AccessibilityGetDeviceScaleFactor() const override { return 1.0f; }
-  void AccessibilityFatalError() override { got_fatal_error_ = true; }
-  gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override {
-    return gfx::kNullAcceleratedWidget;
-  }
-  gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override {
-    return nullptr;
-  }
-  gfx::NativeViewAccessible AccessibilityGetNativeViewAccessibleForWindow()
-      override {
-    return nullptr;
-  }
-
-  bool got_fatal_error() const { return got_fatal_error_; }
-  void reset_got_fatal_error() { got_fatal_error_ = false; }
-
- private:
-  bool got_fatal_error_;
-};
-
 class CountingAXTreeObserver : public ui::AXTreeObserver {
  public:
   CountingAXTreeObserver() {}
@@ -101,7 +77,27 @@
 
 }  // anonymous namespace
 
-TEST(BrowserAccessibilityManagerTest, TestNoLeaks) {
+class BrowserAccessibilityManagerTest : public testing::Test {
+ public:
+  BrowserAccessibilityManagerTest() = default;
+  ~BrowserAccessibilityManagerTest() override = default;
+
+ protected:
+  std::unique_ptr<TestBrowserAccessibilityDelegate>
+      test_browser_accessibility_delegate_;
+
+ private:
+  void SetUp() override;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerTest);
+};
+
+void BrowserAccessibilityManagerTest::SetUp() {
+  test_browser_accessibility_delegate_ =
+      std::make_unique<TestBrowserAccessibilityDelegate>();
+}
+
+TEST_F(BrowserAccessibilityManagerTest, TestNoLeaks) {
   // Create ui::AXNodeData objects for a simple document tree,
   // representing the accessibility information used to initialize
   // BrowserAccessibilityManager.
@@ -128,7 +124,8 @@
   // created. Note that the manager takes ownership of the factory.
   CountedBrowserAccessibility::global_obj_count_ = 0;
   BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(root, button, checkbox), nullptr,
+      MakeAXTreeUpdate(root, button, checkbox),
+      test_browser_accessibility_delegate_.get(),
       new CountedBrowserAccessibilityFactory());
 
   ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_);
@@ -140,7 +137,8 @@
   // Construct a manager again, and this time save references to two of
   // the three nodes in the tree.
   manager = BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(root, button, checkbox), nullptr,
+      MakeAXTreeUpdate(root, button, checkbox),
+      test_browser_accessibility_delegate_.get(),
       new CountedBrowserAccessibilityFactory());
   ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_);
 
@@ -165,7 +163,7 @@
   ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
 }
 
-TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects) {
+TEST_F(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects) {
   // Make sure that changes to a subtree reuse as many objects as possible.
 
   // Tree 1:
@@ -223,7 +221,8 @@
   CountedBrowserAccessibility::global_obj_count_ = 0;
   BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create(
       MakeAXTreeUpdate(tree1_root, tree1_child1, tree1_child2, tree1_child3),
-      nullptr, new CountedBrowserAccessibilityFactory());
+      test_browser_accessibility_delegate_.get(),
+      new CountedBrowserAccessibilityFactory());
   ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
 
   // Save references to all of the objects.
@@ -284,7 +283,7 @@
   ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
 }
 
-TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects2) {
+TEST_F(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects2) {
   // Similar to the test above, but with a more complicated tree.
 
   // Tree 1:
@@ -382,7 +381,8 @@
       MakeAXTreeUpdate(tree1_root, tree1_container, tree1_child1,
                        tree1_grandchild1, tree1_child2, tree1_grandchild2,
                        tree1_child3, tree1_grandchild3),
-      nullptr, new CountedBrowserAccessibilityFactory());
+      test_browser_accessibility_delegate_.get(),
+      new CountedBrowserAccessibilityFactory());
   ASSERT_EQ(8, CountedBrowserAccessibility::global_obj_count_);
 
   // Save references to some objects.
@@ -447,7 +447,7 @@
   ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
 }
 
-TEST(BrowserAccessibilityManagerTest, TestMoveChildUp) {
+TEST_F(BrowserAccessibilityManagerTest, TestMoveChildUp) {
   // Tree 1:
   //
   // 1
@@ -496,7 +496,8 @@
   // Construct a BrowserAccessibilityManager with tree1.
   CountedBrowserAccessibility::global_obj_count_ = 0;
   BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(tree1_1, tree1_2, tree1_3, tree1_4), nullptr,
+      MakeAXTreeUpdate(tree1_1, tree1_2, tree1_3, tree1_4),
+      test_browser_accessibility_delegate_.get(),
       new CountedBrowserAccessibilityFactory());
   ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
 
@@ -518,7 +519,7 @@
 }
 
 // Temporarily disabled due to bug http://crbug.com/765490
-TEST(BrowserAccessibilityManagerTest, DISABLED_TestFatalError) {
+TEST_F(BrowserAccessibilityManagerTest, DISABLED_TestFatalError) {
   // Test that BrowserAccessibilityManager raises a fatal error
   // (which will crash the renderer) if the same id is used in
   // two places in the tree.
@@ -531,13 +532,12 @@
 
   CountedBrowserAccessibilityFactory* factory =
       new CountedBrowserAccessibilityFactory();
-  std::unique_ptr<TestBrowserAccessibilityDelegate> delegate(
-      new TestBrowserAccessibilityDelegate());
   std::unique_ptr<BrowserAccessibilityManager> manager;
-  ASSERT_FALSE(delegate->got_fatal_error());
-  manager.reset(BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root),
-                                                    delegate.get(), factory));
-  ASSERT_TRUE(delegate->got_fatal_error());
+  ASSERT_FALSE(test_browser_accessibility_delegate_->got_fatal_error());
+  manager.reset(BrowserAccessibilityManager::Create(
+      MakeAXTreeUpdate(root), test_browser_accessibility_delegate_.get(),
+      factory));
+  ASSERT_TRUE(test_browser_accessibility_delegate_->got_fatal_error());
 
   ui::AXNodeData root2;
   root2.id = 1;
@@ -564,16 +564,16 @@
   ui::AXNodeData grandchild6;
   grandchild6.id = 6;
 
-  delegate->reset_got_fatal_error();
+  test_browser_accessibility_delegate_->reset_got_fatal_error();
   factory = new CountedBrowserAccessibilityFactory();
   manager.reset(BrowserAccessibilityManager::Create(
       MakeAXTreeUpdate(root2, child1, child2, grandchild4, grandchild5,
                        grandchild6),
-      delegate.get(), factory));
-  ASSERT_TRUE(delegate->got_fatal_error());
+      test_browser_accessibility_delegate_.get(), factory));
+  ASSERT_TRUE(test_browser_accessibility_delegate_->got_fatal_error());
 }
 
-TEST(BrowserAccessibilityManagerTest, BoundsForRange) {
+TEST_F(BrowserAccessibilityManagerTest, BoundsForRange) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -624,7 +624,8 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, inline_text2),
-          nullptr, new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -657,7 +658,7 @@
             root_accessible->GetPageBoundsForRange(0, 13).ToString());
 }
 
-TEST(BrowserAccessibilityManagerTest, BoundsForRangeMultiElement) {
+TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeMultiElement) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -702,7 +703,8 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, static_text2,
                            inline_text2),
-          nullptr, new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -763,7 +765,7 @@
                 .ToString());
 }
 
-TEST(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) {
+TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) {
   // In this example, we assume that the string "123abc" is rendered with
   // "123" going left-to-right and "abc" going right-to-left. In other
   // words, on-screen it would look like "123cba". This is possible to
@@ -815,7 +817,8 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, inline_text2),
-          nullptr, new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -844,7 +847,7 @@
             static_text_accessible->GetPageBoundsForRange(2, 2).ToString());
 }
 
-TEST(BrowserAccessibilityManagerTest, BoundsForRangeScrolledWindow) {
+TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeScrolledWindow) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -875,7 +878,8 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, static_text, inline_text), nullptr,
+          MakeAXTreeUpdate(root, static_text, inline_text),
+          test_browser_accessibility_delegate_.get(),
           new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
@@ -893,7 +897,7 @@
   }
 }
 
-TEST(BrowserAccessibilityManagerTest, BoundsForRangeOnParentElement) {
+TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeOnParentElement) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -956,7 +960,8 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, div, static_text1, img, static_text2,
                            inline_text1, inline_text2),
-          nullptr, new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
   BrowserAccessibility* div_accessible = root_accessible->PlatformGetChild(0);
@@ -981,7 +986,7 @@
             div_accessible->GetPageBoundsForRange(0, 5).ToString());
 }
 
-TEST(BrowserAccessibilityManagerTest, TestNextPreviousInTreeOrder) {
+TEST_F(BrowserAccessibilityManagerTest, TestNextPreviousInTreeOrder) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1004,7 +1009,8 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, node2, node3, node4, node5), nullptr,
+          MakeAXTreeUpdate(root, node2, node3, node4, node5),
+          test_browser_accessibility_delegate_.get(),
           new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
@@ -1081,7 +1087,7 @@
                                                       *root_accessible));
 }
 
-TEST(BrowserAccessibilityManagerTest, TestNextPreviousTextOnlyObject) {
+TEST_F(BrowserAccessibilityManagerTest, TestNextPreviousTextOnlyObject) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1126,7 +1132,8 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, node2, node3, node4, node5, text1, text2,
                            text3, text4),
-          nullptr, new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -1182,7 +1189,7 @@
   EXPECT_EQ(nullptr, manager->PreviousTextOnlyObject(root_accessible));
 }
 
-TEST(BrowserAccessibilityManagerTest, TestFindIndicesInCommonParent) {
+TEST_F(BrowserAccessibilityManagerTest, TestFindIndicesInCommonParent) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1236,7 +1243,8 @@
           MakeAXTreeUpdate(root, div, button, button_text, line_break,
                            paragraph, paragraph_text, paragraph_line1,
                            paragraph_line2),
-          nullptr, new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -1325,7 +1333,7 @@
   EXPECT_EQ(1, child_index2);
 }
 
-TEST(BrowserAccessibilityManagerTest, TestGetTextForRange) {
+TEST_F(BrowserAccessibilityManagerTest, TestGetTextForRange) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1380,7 +1388,8 @@
           MakeAXTreeUpdate(root, div, button, button_text, line_break,
                            paragraph, paragraph_text, paragraph_line1,
                            paragraph_line2),
-          nullptr, new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -1491,7 +1500,7 @@
           *paragraph_line2_accessible, 6, *paragraph_line1_accessible, 0));
 }
 
-TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash) {
+TEST_F(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash) {
   // Create a really simple tree with one root node and one focused child.
   ui::AXNodeData root;
   root.id = 1;
@@ -1506,7 +1515,8 @@
   initial_state.tree_data.focus_id = 2;
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          initial_state, nullptr, new CountedBrowserAccessibilityFactory()));
+          initial_state, test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   ASSERT_EQ(1, manager->GetRoot()->GetId());
   ASSERT_EQ(2, manager->GetFocus()->GetId());
@@ -1527,7 +1537,7 @@
   ASSERT_EQ(3, manager->GetFocus()->GetId());
 }
 
-TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash2) {
+TEST_F(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash2) {
   // Create a really simple tree with one root node and one focused child.
   ui::AXNodeData root;
   root.id = 1;
@@ -1550,7 +1560,8 @@
   initial_state.tree_data.focus_id = 2;
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          initial_state, nullptr, new CountedBrowserAccessibilityFactory()));
+          initial_state, test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   ASSERT_EQ(1, manager->GetRoot()->GetId());
   ASSERT_EQ(2, manager->GetFocus()->GetId());
@@ -1573,7 +1584,7 @@
   ASSERT_EQ(3, manager->GetFocus()->GetId());
 }
 
-TEST(BrowserAccessibilityManagerTest, TreeUpdatesAreMergedWhenPossible) {
+TEST_F(BrowserAccessibilityManagerTest, TreeUpdatesAreMergedWhenPossible) {
   ui::AXTreeUpdate tree;
   tree.root_id = 1;
   tree.nodes.resize(4);
@@ -1589,7 +1600,8 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          tree, nullptr, new CountedBrowserAccessibilityFactory()));
+          tree, test_browser_accessibility_delegate_.get(),
+          new CountedBrowserAccessibilityFactory()));
 
   CountingAXTreeObserver observer;
   manager->ax_tree()->AddObserver(&observer);
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index b4ce6ae..e9964be 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -258,6 +258,9 @@
       else if (ui::IsValuePatternSupported(node))
         FireUiaPropertyChangedEvent(UIA_ValueIsReadOnlyPropertyId, node);
       break;
+    case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_IsRequiredForFormPropertyId, node);
+      break;
     case ui::AXEventGenerator::Event::ROLE_CHANGED:
       FireUiaPropertyChangedEvent(UIA_AriaRolePropertyId, node);
       break;
@@ -294,7 +297,6 @@
         FireUiaPropertyChangedEvent(UIA_RangeValueLargeChangePropertyId, node);
       }
       break;
-
     case ui::AXEventGenerator::Event::AUTO_COMPLETE_CHANGED:
     case ui::AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED:
     case ui::AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_win_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_win_unittest.cc
new file mode 100644
index 0000000..4d67502d
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_manager_win_unittest.cc
@@ -0,0 +1,85 @@
+// 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 "content/browser/accessibility/browser_accessibility.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/test_browser_accessibility_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/accessibility_switches.h"
+#include "ui/accessibility/platform/ax_fragment_root_win.h"
+#include "ui/accessibility/platform/ax_platform_node_win.h"
+#include "ui/accessibility/platform/test_ax_node_wrapper.h"
+
+namespace content {
+
+class BrowserAccessibilityManagerWinTest : public testing::Test {
+ public:
+  BrowserAccessibilityManagerWinTest() = default;
+  ~BrowserAccessibilityManagerWinTest() override = default;
+
+ protected:
+  std::unique_ptr<TestBrowserAccessibilityDelegate>
+      test_browser_accessibility_delegate_;
+
+ private:
+  void SetUp() override;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerWinTest);
+};
+
+void BrowserAccessibilityManagerWinTest::SetUp() {
+  test_browser_accessibility_delegate_ =
+      std::make_unique<TestBrowserAccessibilityDelegate>();
+}
+
+TEST_F(BrowserAccessibilityManagerWinTest, DynamicallyAddedIFrame) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      ::switches::kEnableExperimentalUIAutomation);
+
+  ui::AXNodeData root;
+  root.id = 1;
+  root.role = ax::mojom::Role::kRootWebArea;
+
+  test_browser_accessibility_delegate_->accelerated_widget_ =
+      gfx::kMockAcceleratedWidget;
+
+  std::unique_ptr<BrowserAccessibilityManager> root_manager(
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root), test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
+
+  ui::AXPlatformNode* root_document_root_node =
+      ui::AXPlatformNode::FromNativeViewAccessible(
+          root_manager->GetRoot()->GetNativeViewAccessible());
+
+  std::unique_ptr<ui::AXPlatformNodeDelegate> fragment_root =
+      std::make_unique<ui::AXFragmentRootWin>(
+          gfx::kMockAcceleratedWidget,
+          static_cast<ui::AXPlatformNodeWin*>(root_document_root_node));
+
+  EXPECT_EQ(fragment_root->GetChildCount(), 1);
+  EXPECT_EQ(fragment_root->ChildAtIndex(0),
+            root_document_root_node->GetNativeViewAccessible());
+
+  // Simulate the case where an iframe is created but the update to add the
+  // element to the root frame's document has not yet come through.
+  std::unique_ptr<TestBrowserAccessibilityDelegate> iframe_delegate =
+      std::make_unique<TestBrowserAccessibilityDelegate>();
+  iframe_delegate->is_root_frame_ = false;
+  iframe_delegate->accelerated_widget_ = gfx::kMockAcceleratedWidget;
+
+  std::unique_ptr<BrowserAccessibilityManager> iframe_manager(
+      BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root),
+                                          iframe_delegate.get(),
+                                          new BrowserAccessibilityFactory()));
+
+  // The new frame is not a root frame, so the fragment root's lone child should
+  // still be the same as before.
+  EXPECT_EQ(fragment_root->GetChildCount(), 1);
+  EXPECT_EQ(fragment_root->ChildAtIndex(0),
+            root_document_root_node->GetNativeViewAccessible());
+}
+
+}  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_unittest.cc b/content/browser/accessibility/browser_accessibility_unittest.cc
index 330d435..d070c06 100644
--- a/content/browser/accessibility/browser_accessibility_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/test/scoped_task_environment.h"
 #include "build/build_config.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/test_browser_accessibility_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
@@ -34,7 +35,13 @@
   BrowserAccessibilityTest();
   ~BrowserAccessibilityTest() override;
 
+ protected:
+  std::unique_ptr<TestBrowserAccessibilityDelegate>
+      test_browser_accessibility_delegate_;
+
  private:
+  void SetUp() override;
+
   base::test::ScopedTaskEnvironment task_environment_;
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityTest);
 };
@@ -43,6 +50,11 @@
 
 BrowserAccessibilityTest::~BrowserAccessibilityTest() {}
 
+void BrowserAccessibilityTest::SetUp() {
+  test_browser_accessibility_delegate_ =
+      std::make_unique<TestBrowserAccessibilityDelegate>();
+}
+
 TEST_F(BrowserAccessibilityTest, TestCanFireEvents) {
   ui::AXNodeData text1;
   text1.id = 111;
@@ -60,9 +72,10 @@
   root.child_ids.push_back(para1.id);
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
-      BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root, para1, text1),
-                                          nullptr,
-                                          new BrowserAccessibilityFactory()));
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root, para1, text1),
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_obj = manager->GetRoot();
   EXPECT_FALSE(root_obj->PlatformIsLeaf());
@@ -121,7 +134,8 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, para1, text1, text2, text3), nullptr,
+          MakeAXTreeUpdate(root, para1, text1, text2, text3),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_obj = manager->GetRoot();
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 3b3d131..e82634e 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -19,6 +19,7 @@
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/accessibility/test_browser_accessibility_delegate.h"
 #include "content/browser/renderer_host/legacy_render_widget_host_win.h"
 #include "content/common/accessibility_messages.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -36,6 +37,10 @@
   BrowserAccessibilityWinTest();
   ~BrowserAccessibilityWinTest() override;
 
+ protected:
+  std::unique_ptr<TestBrowserAccessibilityDelegate>
+      test_browser_accessibility_delegate_;
+
  private:
   void SetUp() override;
 
@@ -50,6 +55,8 @@
 
 void BrowserAccessibilityWinTest::SetUp() {
   ui::win::CreateATLModuleIfNeeded();
+  test_browser_accessibility_delegate_ =
+      std::make_unique<TestBrowserAccessibilityDelegate>();
 }
 
 // Actual tests ---------------------------------------------------------------
@@ -83,7 +90,8 @@
   // created. Note that the manager takes ownership of the factory.
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, button, checkbox), nullptr,
+          MakeAXTreeUpdate(root, button, checkbox),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   // Delete the manager and test that all 3 instances are deleted.
@@ -92,7 +100,8 @@
   // Construct a manager again, and this time use the IAccessible interface
   // to get new references to two of the three nodes in the tree.
   manager.reset(BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(root, button, checkbox), nullptr,
+      MakeAXTreeUpdate(root, button, checkbox),
+      test_browser_accessibility_delegate_.get(),
       new BrowserAccessibilityFactory()));
   IAccessible* root_accessible =
       ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
@@ -134,8 +143,10 @@
   // ui::AXNodeData tree and a factory for an instance-counting
   // BrowserAccessibility.
   std::unique_ptr<BrowserAccessibilityManager> manager(
-      BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root, text), nullptr,
-                                          new BrowserAccessibilityFactory()));
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root, text),
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   // Query for the text IAccessible and verify that it returns "old text" as its
   // value.
@@ -222,7 +233,8 @@
   // created. Note that the manager takes ownership of the factory.
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, div, text3, text4), nullptr,
+          MakeAXTreeUpdate(root, div, text3, text4),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   // Notify the BrowserAccessibilityManager that the div node and its children
@@ -314,7 +326,8 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, text_field, static_text1, inline_box1,
                            line_break, static_text2, inline_box2),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   BrowserAccessibilityWin* root_obj =
       ToBrowserAccessibilityWin(manager->GetRoot());
@@ -430,9 +443,10 @@
   root.child_ids.push_back(text2.id);
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
-      BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root, text1, text2),
-                                          nullptr,
-                                          new BrowserAccessibilityFactory()));
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root, text1, text2),
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   BrowserAccessibilityComWin* root_obj =
       ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
@@ -545,7 +559,8 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, text1, combo_box, text2, check_box, button,
                            button_text, link, link_text),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   BrowserAccessibilityComWin* root_obj =
       ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
@@ -635,7 +650,8 @@
   // set automatically.
   std::unique_ptr<BrowserAccessibilityManager> manager(
       new BrowserAccessibilityManagerWin(
-          BrowserAccessibilityManagerWin::GetEmptyDocument(), nullptr,
+          BrowserAccessibilityManagerWin::GetEmptyDocument(),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   // Verify the root is as we expect by default.
@@ -716,7 +732,8 @@
 TEST_F(BrowserAccessibilityWinTest, EmptyDocHasUniqueIdWin) {
   std::unique_ptr<BrowserAccessibilityManagerWin> manager(
       new BrowserAccessibilityManagerWin(
-          BrowserAccessibilityManagerWin::GetEmptyDocument(), nullptr,
+          BrowserAccessibilityManagerWin::GetEmptyDocument(),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   // Verify the root is as we expect by default.
@@ -761,7 +778,8 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, pseudo_before, checkbox), nullptr,
+          MakeAXTreeUpdate(root, pseudo_before, checkbox),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
@@ -874,7 +892,8 @@
           MakeAXTreeUpdate(root, combo_box, combo_box_text, search_box,
                            search_box_text, new_line, text_field, link,
                            link_text, slider, slider_text),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1038,7 +1057,8 @@
           MakeAXTreeUpdate(root, textarea, textarea_div, textarea_text,
                            textarea_line1, textarea_line2, text_field,
                            text_field_div, text_field_text, text_field_line),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1133,7 +1153,8 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, combo_box, text_field), nullptr,
+          MakeAXTreeUpdate(root, combo_box, text_field),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
@@ -1248,8 +1269,9 @@
   update.tree_data.sel_focus_offset = 1;
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
-      BrowserAccessibilityManager::Create(update, nullptr,
-                                          new BrowserAccessibilityFactory()));
+      BrowserAccessibilityManager::Create(
+          update, test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1370,8 +1392,9 @@
   update.tree_data.sel_focus_offset = 4;
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
-      BrowserAccessibilityManager::Create(update, nullptr,
-                                          new BrowserAccessibilityFactory()));
+      BrowserAccessibilityManager::Create(
+          update, test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1505,7 +1528,8 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, div, link, text), nullptr,
+          MakeAXTreeUpdate(root, div, link, text),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
@@ -1705,8 +1729,9 @@
                                              link, link_text, text_after);
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
-      BrowserAccessibilityManager::Create(update, nullptr,
-                                          new BrowserAccessibilityFactory()));
+      BrowserAccessibilityManager::Create(
+          update, test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* ax_root =
@@ -1930,7 +1955,8 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, combo_box, combo_box_div, static_text1,
                            static_text2),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* ax_root =
@@ -2029,7 +2055,8 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, combo_box, combo_box_div, static_text1,
                            static_text2),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* ax_root =
@@ -2134,7 +2161,8 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, child1, child2, child2_child1, child2_child2),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -2217,7 +2245,8 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, child1, child2, child2_child1, child2_child2),
-          nullptr, new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get(),
+          new BrowserAccessibilityFactory()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -2282,7 +2311,8 @@
 
   std::unique_ptr<BrowserAccessibilityManagerWin> manager(
       new BrowserAccessibilityManagerWin(
-          MakeAXTreeUpdate(root_node, child_node), nullptr,
+          MakeAXTreeUpdate(root_node, child_node),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   BrowserAccessibility* root = manager->GetRoot();
@@ -2292,7 +2322,8 @@
 
   // Now destroy that original tree and create a new tree.
   manager.reset(new BrowserAccessibilityManagerWin(
-      MakeAXTreeUpdate(root_node, child_node), nullptr,
+      MakeAXTreeUpdate(root_node, child_node),
+      test_browser_accessibility_delegate_.get(),
       new BrowserAccessibilityFactory()));
   root = manager->GetRoot();
   int32_t root_unique_id_2 = GetUniqueId(root);
@@ -2341,7 +2372,8 @@
 
   std::unique_ptr<BrowserAccessibilityManagerWin> manager(
       new BrowserAccessibilityManagerWin(
-          MakeAXTreeUpdate(root_node, child_node), nullptr,
+          MakeAXTreeUpdate(root_node, child_node),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   BrowserAccessibility* root = manager->GetRoot();
@@ -2380,7 +2412,8 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root, child1, child2), nullptr,
+          MakeAXTreeUpdate(root, child1, child2),
+          test_browser_accessibility_delegate_.get(),
           new BrowserAccessibilityFactory()));
 
   BrowserAccessibilityWin* ax_root =
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 6a93e66..04328a6 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -366,6 +366,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+                       AccessibilityEventsFormRequiredChanged) {
+  RunEventTest(FILE_PATH_LITERAL("form-required-changed.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
                        AccessibilityEventsInnerHtmlChange) {
   RunEventTest(FILE_PATH_LITERAL("inner-html-change.html"));
 }
@@ -544,6 +549,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+                       AccessibilityEventsAriaRequiredChanged) {
+  RunEventTest(FILE_PATH_LITERAL("aria-required-changed.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
                        AccessibilityEventsAriaPressedChanged) {
   RunEventTest(FILE_PATH_LITERAL("aria-pressed-changed.html"));
 }
diff --git a/content/browser/accessibility/test_browser_accessibility_delegate.cc b/content/browser/accessibility/test_browser_accessibility_delegate.cc
new file mode 100644
index 0000000..1540e0c
--- /dev/null
+++ b/content/browser/accessibility/test_browser_accessibility_delegate.cc
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/test_browser_accessibility_delegate.h"
+
+namespace content {
+
+TestBrowserAccessibilityDelegate::TestBrowserAccessibilityDelegate()
+    : is_root_frame_(true),
+      accelerated_widget_(gfx::kNullAcceleratedWidget),
+      got_fatal_error_(false) {}
+
+void TestBrowserAccessibilityDelegate::AccessibilityPerformAction(
+    const ui::AXActionData& data) {}
+
+bool TestBrowserAccessibilityDelegate::AccessibilityViewHasFocus() const {
+  return false;
+}
+
+gfx::Rect TestBrowserAccessibilityDelegate::AccessibilityGetViewBounds() const {
+  return gfx::Rect();
+}
+
+float TestBrowserAccessibilityDelegate::AccessibilityGetDeviceScaleFactor()
+    const {
+  return 1.0f;
+}
+
+void TestBrowserAccessibilityDelegate::AccessibilityFatalError() {
+  got_fatal_error_ = true;
+}
+
+gfx::AcceleratedWidget
+TestBrowserAccessibilityDelegate::AccessibilityGetAcceleratedWidget() {
+  return accelerated_widget_;
+}
+
+gfx::NativeViewAccessible
+TestBrowserAccessibilityDelegate::AccessibilityGetNativeViewAccessible() {
+  return nullptr;
+}
+
+gfx::NativeViewAccessible TestBrowserAccessibilityDelegate::
+    AccessibilityGetNativeViewAccessibleForWindow() {
+  return nullptr;
+}
+
+bool TestBrowserAccessibilityDelegate::AccessibilityIsMainFrame() {
+  return is_root_frame_;
+}
+
+bool TestBrowserAccessibilityDelegate::got_fatal_error() const {
+  return got_fatal_error_;
+}
+
+void TestBrowserAccessibilityDelegate::reset_got_fatal_error() {
+  got_fatal_error_ = false;
+}
+
+}  // namespace content
diff --git a/content/browser/accessibility/test_browser_accessibility_delegate.h b/content/browser/accessibility/test_browser_accessibility_delegate.h
new file mode 100644
index 0000000..86fb3e9
--- /dev/null
+++ b/content/browser/accessibility/test_browser_accessibility_delegate.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_TEST_BROWSER_ACCESSIBILITY_DELEGATE_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_TEST_BROWSER_ACCESSIBILITY_DELEGATE_H_
+
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+
+namespace content {
+
+class TestBrowserAccessibilityDelegate : public BrowserAccessibilityDelegate {
+ public:
+  TestBrowserAccessibilityDelegate();
+
+  void AccessibilityPerformAction(const ui::AXActionData& data) override;
+  bool AccessibilityViewHasFocus() const override;
+  gfx::Rect AccessibilityGetViewBounds() const override;
+  float AccessibilityGetDeviceScaleFactor() const override;
+  void AccessibilityFatalError() override;
+  gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override;
+  gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override;
+  gfx::NativeViewAccessible AccessibilityGetNativeViewAccessibleForWindow()
+      override;
+  bool AccessibilityIsMainFrame() override;
+
+  bool got_fatal_error() const;
+  void reset_got_fatal_error();
+
+  bool is_root_frame_;
+  gfx::AcceleratedWidget accelerated_widget_;
+
+ private:
+  bool got_fatal_error_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_ACCESSIBILITY_TEST_BROWSER_ACCESSIBILITY_DELEGATE_H_
diff --git a/content/browser/android/web_contents_observer_proxy.cc b/content/browser/android/web_contents_observer_proxy.cc
index 72c1aa8e8..ca81246 100644
--- a/content/browser/android/web_contents_observer_proxy.cc
+++ b/content/browser/android/web_contents_observer_proxy.cc
@@ -204,9 +204,11 @@
   Java_WebContentsObserverProxy_didDetachInterstitialPage(env, java_observer_);
 }
 
-void WebContentsObserverProxy::DidChangeThemeColor(SkColor color) {
+void WebContentsObserverProxy::DidChangeThemeColor(
+    base::Optional<SkColor> color) {
   JNIEnv* env = AttachCurrentThread();
-  Java_WebContentsObserverProxy_didChangeThemeColor(env, java_observer_, color);
+  Java_WebContentsObserverProxy_didChangeThemeColor(
+      env, java_observer_, color.value_or(SK_ColorTRANSPARENT));
 }
 
 void WebContentsObserverProxy::MediaEffectivelyFullscreenChanged(
diff --git a/content/browser/android/web_contents_observer_proxy.h b/content/browser/android/web_contents_observer_proxy.h
index 226f386..03cebb4 100644
--- a/content/browser/android/web_contents_observer_proxy.h
+++ b/content/browser/android/web_contents_observer_proxy.h
@@ -59,7 +59,7 @@
   void WebContentsDestroyed() override;
   void DidAttachInterstitialPage() override;
   void DidDetachInterstitialPage() override;
-  void DidChangeThemeColor(SkColor color) override;
+  void DidChangeThemeColor(base::Optional<SkColor> color) override;
   void MediaEffectivelyFullscreenChanged(bool is_fullscreen) override;
   void SetToBaseURLForDataURLIfNeeded(std::string* url);
   void ViewportFitChanged(blink::mojom::ViewportFit value) override;
diff --git a/content/browser/appcache/appcache.cc b/content/browser/appcache/appcache.cc
index 8995f60..a3c983f 100644
--- a/content/browser/appcache/appcache.cc
+++ b/content/browser/appcache/appcache.cc
@@ -287,7 +287,8 @@
     info.is_fallback = pair.second.IsFallback();
     info.is_foreign = pair.second.IsForeign();
     info.is_explicit = pair.second.IsExplicit();
-    info.size = pair.second.response_size();
+    info.response_size = pair.second.response_size();
+    info.padding_size = pair.second.padding_size();
     info.response_id = pair.second.response_id();
   }
 }
diff --git a/content/browser/appcache/appcache_host.cc b/content/browser/appcache/appcache_host.cc
index 4d058e4..d6ed8eb6 100644
--- a/content/browser/appcache/appcache_host.cc
+++ b/content/browser/appcache/appcache_host.cc
@@ -52,7 +52,8 @@
   info->group_id = cache->owning_group()->group_id();
   info->last_update_time = cache->update_time();
   info->creation_time = cache->owning_group()->creation_time();
-  info->size = cache->cache_size();
+  info->response_sizes = cache->cache_size();
+  info->padding_sizes = cache->padding_size();
   return info;
 }
 
diff --git a/content/browser/appcache/appcache_internals_ui.cc b/content/browser/appcache/appcache_internals_ui.cc
index 38f10de..b05f3cc 100644
--- a/content/browser/appcache/appcache_internals_ui.cc
+++ b/content/browser/appcache/appcache_internals_ui.cc
@@ -83,9 +83,16 @@
                         appcache_info.last_update_time.ToJsTime());
   dict_value->SetDouble("lastAccessTime",
                         appcache_info.last_access_time.ToJsTime());
+  dict_value->SetString("responseSizes",
+                        base::UTF16ToUTF8(base::FormatBytesUnlocalized(
+                            appcache_info.response_sizes)));
+  dict_value->SetString("paddingSizes",
+                        base::UTF16ToUTF8(base::FormatBytesUnlocalized(
+                            appcache_info.padding_sizes)));
   dict_value->SetString(
-      "size",
-      base::UTF16ToUTF8(base::FormatBytesUnlocalized(appcache_info.size)));
+      "totalSize",
+      base::UTF16ToUTF8(base::FormatBytesUnlocalized(
+          appcache_info.response_sizes + appcache_info.padding_sizes)));
   dict_value->SetString("groupId",
                         base::NumberToString(appcache_info.group_id));
 
@@ -118,9 +125,14 @@
     const blink::mojom::AppCacheResourceInfo& resource_info) {
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
   dict->SetString("url", resource_info.url.spec());
-  dict->SetString(
-      "size",
-      base::UTF16ToUTF8(base::FormatBytesUnlocalized(resource_info.size)));
+  dict->SetString("responseSize",
+                  base::UTF16ToUTF8(base::FormatBytesUnlocalized(
+                      resource_info.response_size)));
+  dict->SetString("paddingSize", base::UTF16ToUTF8(base::FormatBytesUnlocalized(
+                                     resource_info.padding_size)));
+  dict->SetString("totalSize", base::UTF16ToUTF8(base::FormatBytesUnlocalized(
+                                   resource_info.response_size +
+                                   resource_info.padding_size)));
   dict->SetString("responseId",
                   base::NumberToString(resource_info.response_id));
   dict->SetBoolean("isExplicit", resource_info.is_explicit);
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index 98125a30..4193784fd 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -378,7 +378,8 @@
       blink::mojom::AppCacheInfo info;
       info.manifest_url = group.manifest_url;
       info.creation_time = group.creation_time;
-      info.size = cache_record.cache_size;
+      info.response_sizes = cache_record.cache_size;
+      info.padding_sizes = cache_record.padding_size;
       info.last_access_time = group.last_access_time;
       info.last_update_time = cache_record.update_time;
       info.cache_id = cache_record.cache_id;
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 042cd8f..622ffc16 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -1222,6 +1222,7 @@
 
   // The event ran to completion, we should count it, no matter what happens
   // from here.
+  bool succeeded = status_code == blink::ServiceWorkerStatusCode::kOk;
   ServiceWorkerRegistration* sw_registration =
       service_worker_context_->GetLiveRegistration(
           registration_info->service_worker_registration_id);
@@ -1230,8 +1231,7 @@
   if (sw_registration) {
     HasMainFrameProviderHost(
         origin,
-        base::BindOnce(&BackgroundSyncMetrics::RecordEventResult,
-                       status_code == blink::ServiceWorkerStatusCode::kOk));
+        base::BindOnce(&BackgroundSyncMetrics::RecordEventResult, succeeded));
   }
 
   bool registration_completed = true;
@@ -1243,8 +1243,8 @@
     registration->set_sync_state(blink::mojom::BackgroundSyncState::PENDING);
     registration->set_num_attempts(0);
     registration_completed = false;
-  } else if (status_code != blink::ServiceWorkerStatusCode::kOk &&
-             can_retry) {  // Sync failed but can retry
+  } else if (!succeeded && can_retry) {
+    // Sync failed but can retry.
     registration->set_sync_state(blink::mojom::BackgroundSyncState::PENDING);
     base::TimeDelta delay =
         parameters_->initial_retry_delay *
@@ -1266,18 +1266,20 @@
   }
 
   if (registration_completed) {
+    BackgroundSyncMetrics::RecordRegistrationComplete(
+        succeeded, registration->num_attempts());
+
     RemoveActiveRegistration(*registration_info);
 
     if (devtools_context_->IsRecording(devtools::proto::BACKGROUND_SYNC) &&
         registration_info->sync_type ==
             blink::mojom::BackgroundSyncType::ONE_SHOT) {
-      bool succeded = status_code == blink::ServiceWorkerStatusCode::kOk;
       devtools_context_->LogBackgroundServiceEvent(
           sw_registration->id(), origin, devtools::proto::BACKGROUND_SYNC,
           /* event_name= */ "sync complete",
           /* instance_id= */ registration_info->tag,
           /* event_metadata= */
-          {{"succeeded", succeded ? "yes" : "no"}});
+          {{"succeeded", succeeded ? "yes" : "no"}});
     }
   }
 
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index 7ed86d94..e9edf6d 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -1218,9 +1218,7 @@
             GetController()->registration_origin());
 }
 
-// TODO(https://crbug.com/944871): Flakes after setting CONNECTION_WIFI, on
-// some bots.
-TEST_F(BackgroundSyncManagerTest, DISABLED_WakeBrowserCalled) {
+TEST_F(BackgroundSyncManagerTest, WakeBrowserCalled) {
   InitDelayedSyncEventTest();
 
   // The BackgroundSyncManager should declare in initialization
diff --git a/content/browser/background_sync/background_sync_metrics.cc b/content/browser/background_sync/background_sync_metrics.cc
index 8ae07b7..ce50b26 100644
--- a/content/browser/background_sync/background_sync_metrics.cc
+++ b/content/browser/background_sync/background_sync_metrics.cc
@@ -39,6 +39,22 @@
 }
 
 // static
+void BackgroundSyncMetrics::RecordRegistrationComplete(
+    bool event_succeeded,
+    int num_attempts_required) {
+  UMA_HISTOGRAM_BOOLEAN(
+      "BackgroundSync.Registration.OneShot.EventSucceededAtCompletion",
+      event_succeeded);
+
+  if (!event_succeeded)
+    return;
+
+  UMA_HISTOGRAM_EXACT_LINEAR(
+      "BackgroundSync.Registration.OneShot.NumAttemptsForSuccessfulEvent",
+      num_attempts_required, 50);
+}
+
+// static
 void BackgroundSyncMetrics::RecordEventResult(bool success,
                                               bool finished_in_foreground) {
   UMA_HISTOGRAM_ENUMERATION(
diff --git a/content/browser/background_sync/background_sync_metrics.h b/content/browser/background_sync/background_sync_metrics.h
index 3280896..5dfd6509c 100644
--- a/content/browser/background_sync/background_sync_metrics.h
+++ b/content/browser/background_sync/background_sync_metrics.h
@@ -34,6 +34,11 @@
   // Records the result of a single sync event firing.
   static void RecordEventResult(bool result, bool finished_in_foreground);
 
+  // Records, at the completion of a one-shot sync registration, whether the
+  // sync event was successful, and how many attempts it took to get there.
+  static void RecordRegistrationComplete(bool event_succeeded,
+                                         int num_attempts_required);
+
   // Records the result of running a batch of sync events, including the total
   // time spent, and the batch size.
   static void RecordBatchSyncEventComplete(const base::TimeDelta& time,
diff --git a/content/browser/bluetooth/bluetooth_metrics.cc b/content/browser/bluetooth/bluetooth_metrics.cc
index 8b68152..48f7070 100644
--- a/content/browser/bluetooth/bluetooth_metrics.cc
+++ b/content/browser/bluetooth/bluetooth_metrics.cc
@@ -11,7 +11,7 @@
 #include <set>
 #include <unordered_set>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "device/bluetooth/bluetooth_uuid.h"
diff --git a/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc b/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
index 530bb049..830369c 100644
--- a/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
+++ b/content/browser/bluetooth/tools/bluetooth_metrics_hash.cc
@@ -4,7 +4,7 @@
 
 #include <iostream>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index b2b3920..ef5c5cc0 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -564,13 +564,13 @@
     }
   }
 
-  // Clean up any isolated origins associated with this BrowserContext.  This
+  // Clean up any security state associated with this BrowserContext.  This
   // should be safe now that all RenderProcessHosts are destroyed, since future
   // navigations or security decisions shouldn't ever need to consult these
-  // isolated origins.
+  // renderer processes.
   ChildProcessSecurityPolicyImpl* policy =
       ChildProcessSecurityPolicyImpl::GetInstance();
-  policy->RemoveIsolatedOriginsForBrowserContext(*browser_context);
+  policy->OnBrowserContextBeingDestroyed(*browser_context);
 }
 
 void BrowserContext::EnsureResourceContextInitialized(BrowserContext* context) {
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc
index 8ccf3c92..69ac9445 100644
--- a/content/browser/cache_storage/cache_storage.cc
+++ b/content/browser/cache_storage/cache_storage.cc
@@ -16,13 +16,13 @@
 #include "base/files/file_util.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/guid.h"
+#include "base/hash/sha1.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/sequenced_task_runner.h"
-#include "base/sha1.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/content/browser/cache_storage/cache_storage_manager.cc b/content/browser/cache_storage/cache_storage_manager.cc
index 4ad1922..01512ef 100644
--- a/content/browser/cache_storage/cache_storage_manager.cc
+++ b/content/browser/cache_storage/cache_storage_manager.cc
@@ -17,9 +17,9 @@
 #include "base/containers/id_map.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
+#include "base/hash/sha1.h"
 #include "base/memory/ptr_util.h"
 #include "base/sequenced_task_runner.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index c79493c..55f1920f 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -132,7 +132,8 @@
 
 // The SecurityState class is used to maintain per-child process security state
 // information.
-class ChildProcessSecurityPolicyImpl::SecurityState {
+class ChildProcessSecurityPolicyImpl::SecurityState
+    : public base::RefCountedThreadSafe<SecurityState> {
  public:
   explicit SecurityState(BrowserContext* browser_context)
       : enabled_bindings_(0),
@@ -141,18 +142,6 @@
         browser_context_(browser_context),
         resource_context_(browser_context->GetResourceContext()) {}
 
-  ~SecurityState() {
-    storage::IsolatedContext* isolated_context =
-        storage::IsolatedContext::GetInstance();
-    for (auto iter = filesystem_permissions_.begin();
-         iter != filesystem_permissions_.end(); ++iter) {
-      isolated_context->RemoveReference(iter->first);
-    }
-    UMA_HISTOGRAM_COUNTS_1M(
-        "ChildProcessSecurityPolicy.PerChildFilePermissions",
-        file_permissions_.size());
-  }
-
   // Grant permission to request and commit URLs with the specified origin.
   void GrantCommitOrigin(const url::Origin& origin) {
     if (origin.opaque())
@@ -182,9 +171,6 @@
   void GrantPermissionsForFile(const base::FilePath& file, int permissions) {
     base::FilePath stripped = file.StripTrailingSeparators();
     file_permissions_[stripped] |= permissions;
-    UMA_HISTOGRAM_COUNTS_1M(
-        "ChildProcessSecurityPolicy.FilePermissionPathLength",
-        stripped.value().size());
   }
 
   // Grant navigation to a file but not the file:// scheme in general.
@@ -376,14 +362,39 @@
     return BrowserOrResourceContext();
   }
 
-  void ClearBrowserContext() { browser_context_ = nullptr; }
+  void ClearMatchingContexts(const BrowserContext* browser_context) {
+    if (browser_context != browser_context_)
+      return;
+
+    browser_context_ = nullptr;
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::IO},
+        base::BindOnce(
+            [](ChildProcessSecurityPolicyImpl::SecurityState* state) {
+              DCHECK_CURRENTLY_ON(BrowserThread::IO);
+              state->resource_context_ = nullptr;
+            },
+            base::RetainedRef(this)));
+  }
 
  private:
+  friend class base::RefCountedThreadSafe<
+      ChildProcessSecurityPolicyImpl::SecurityState>;
+
   enum class CommitRequestPolicy {
     kRequestOnly,
     kCommitAndRequest,
   };
 
+  ~SecurityState() {
+    storage::IsolatedContext* isolated_context =
+        storage::IsolatedContext::GetInstance();
+    for (auto iter = filesystem_permissions_.begin();
+         iter != filesystem_permissions_.end(); ++iter) {
+      isolated_context->RemoveReference(iter->first);
+    }
+  }
+
   bool CanCommitOrigin(const url::Origin& origin) {
     auto it = origin_map_.find(origin);
     if (it == origin_map_.end())
@@ -552,8 +563,6 @@
   if (state == security_state_.end())
     return;
 
-  state->second->ClearBrowserContext();
-
   // Moving the existing SecurityState object into a pending map so
   // that we can preserve permission state and avoid mutations to this
   // state after Remove() has been called.
@@ -1272,7 +1281,8 @@
     return;
   }
 
-  security_state_[child_id] = std::make_unique<SecurityState>(browser_context);
+  security_state_[child_id] =
+      base::MakeRefCounted<SecurityState>(browser_context);
 }
 
 bool ChildProcessSecurityPolicyImpl::ChildProcessHasPermissionsForFile(
@@ -1506,8 +1516,20 @@
   }
 }
 
-void ChildProcessSecurityPolicyImpl::RemoveIsolatedOriginsForBrowserContext(
+void ChildProcessSecurityPolicyImpl::OnBrowserContextBeingDestroyed(
     const BrowserContext& browser_context) {
+  {
+    // Clear any references we may have to |browser_context|.
+    base::AutoLock lock(lock_);
+    for (auto& itr : security_state_) {
+      itr.second->ClearMatchingContexts(&browser_context);
+    }
+
+    for (auto& itr : pending_remove_state_) {
+      itr.second->ClearMatchingContexts(&browser_context);
+    }
+  }
+
   base::AutoLock isolated_origins_lock(isolated_origins_lock_);
 
   for (auto& iter : isolated_origins_) {
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h
index eca358d..c98f180 100644
--- a/content/browser/child_process_security_policy_impl.h
+++ b/content/browser/child_process_security_policy_impl.h
@@ -292,14 +292,14 @@
   // Returns true if sending system exclusive messages is allowed.
   bool CanSendMidiSysExMessage(int child_id);
 
-  // Remove all isolated origins associated with |browser_context|.  This is
-  // typically used when |browser_context| is being destroyed and assumes that
-  // no processes are running or will run for that profile; this makes the
-  // isolated origin removal safe.  Note that |browser_context| cannot be null;
-  // i.e., isolated origins that apply globally to all profiles cannot
-  // currently be removed, since that is not safe to do at runtime.
-  void RemoveIsolatedOriginsForBrowserContext(
-      const BrowserContext& browser_context);
+  // Remove all references to the |browser_context| and all isolated origins
+  // associated with |browser_context|.  This is called when |browser_context|
+  // is being destroyed and assumes that no processes are running or will run
+  // for that profile; this makes the isolated origin removal safe.  Note that
+  // |browser_context| cannot be null; i.e., isolated origins that apply
+  // globally to all profiles cannot currently be removed, since that is not
+  // safe to do at runtime.
+  void OnBrowserContextBeingDestroyed(const BrowserContext& browser_context);
 
   // Check whether |origin| requires origin-wide process isolation within
   // |isolation_context|.
@@ -356,7 +356,7 @@
   class SecurityState;
 
   typedef std::set<std::string> SchemeSet;
-  typedef std::map<int, std::unique_ptr<SecurityState>> SecurityStateMap;
+  typedef std::map<int, scoped_refptr<SecurityState>> SecurityStateMap;
   typedef std::map<storage::FileSystemType, int> FileSystemPermissionPolicyMap;
 
   // This class holds an isolated origin along with information such as which
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index c88086c..f0e2396 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -141,6 +141,18 @@
 // The client of the devtools session will call this method to send a message
 // to handlers / agents that the session is connected with.
 bool DevToolsSession::DispatchProtocolMessage(const std::string& message) {
+  // If the session is in proxy mode, then |message| will be sent to
+  // an external session, so it needs to be sent as JSON.
+  // TODO(dgozman): revisit the proxy delegate.
+  if (proxy_delegate_) {
+    if (client_->UsesBinaryProtocol()) {
+      DCHECK(IsCBOR(message));
+      proxy_delegate_->SendMessageToBackend(this, ConvertCBORToJSON(message));
+      return true;
+    }
+    proxy_delegate_->SendMessageToBackend(this, message);
+    return true;
+  }
   std::string converted_cbor_message;
   const std::string* message_to_send = &message;
   if (EnableInternalDevToolsBinaryProtocol()) {
@@ -153,15 +165,6 @@
       message_to_send = &converted_cbor_message;
     }
   }
-  if (proxy_delegate_) {
-    // TODO(dgozman): revisit the proxy delegate.
-    // TODO(johannes): Should we send CBOR to an external backend? Maybe not!
-    // Revisit this when EnableInternalDevToolsBinaryProtocol() is on
-    // unconditionally.  Note: we assume that child sessions are not forwarding.
-    proxy_delegate_->SendMessageToBackend(this, *message_to_send);
-    return true;
-  }
-
   std::unique_ptr<protocol::DictionaryValue> value =
       protocol::DictionaryValue::cast(protocol::StringUtil::parseMessage(
           message, client_->UsesBinaryProtocol()));
@@ -345,7 +348,20 @@
 }
 
 void DevToolsSession::DispatchOnClientHost(const std::string& message) {
-  client_->DispatchProtocolMessage(agent_host_, message);
+  if (!EnableInternalDevToolsBinaryProtocol()) {
+    client_->DispatchProtocolMessage(agent_host_, message);
+    return;
+  }
+  // |message| either comes from a web socket, in which case it's JSON.
+  // Or it comes from another devtools_session, in which case it may be CBOR
+  // already. We auto-detect and convert to what the client wants as needed.
+  if (client_->UsesBinaryProtocol()) {
+    client_->DispatchProtocolMessage(
+        agent_host_, IsCBOR(message) ? message : ConvertJSONToCBOR(message));
+  } else {
+    client_->DispatchProtocolMessage(
+        agent_host_, !IsCBOR(message) ? message : ConvertCBORToJSON(message));
+  }
   // |this| may be deleted at this point.
 }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 60a4b041..9f563eb 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -13,7 +13,7 @@
 #include "base/command_line.h"
 #include "base/containers/queue.h"
 #include "base/debug/alias.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
@@ -1549,6 +1549,10 @@
   return nullptr;
 }
 
+bool RenderFrameHostImpl::AccessibilityIsMainFrame() {
+  return frame_tree_node()->IsMainFrame();
+}
+
 void RenderFrameHostImpl::RenderProcessGone(SiteInstanceImpl* site_instance) {
   DCHECK_EQ(site_instance_.get(), site_instance);
 
@@ -3200,23 +3204,6 @@
 
     // For testing only.
     if (!accessibility_testing_callback_.is_null()) {
-      // Apply tree updates to test tree.
-      for (size_t i = 0; i < details.updates.size(); i++) {
-        if (!ax_tree_for_testing_) {
-          if (browser_accessibility_manager_) {
-            ax_tree_for_testing_.reset(new ui::AXTree(
-                browser_accessibility_manager_->SnapshotAXTreeForTesting()));
-          } else {
-            ax_tree_for_testing_.reset(new ui::AXTree());
-            CHECK(ax_tree_for_testing_->Unserialize(details.updates[i]))
-                << ax_tree_for_testing_->error();
-          }
-        } else {
-          CHECK(ax_tree_for_testing_->Unserialize(details.updates[i]))
-              << ax_tree_for_testing_->error();
-        }
-      }
-
       if (details.events.empty()) {
         // Objects were marked dirty but no events were provided.
         // The callback must still run, otherwise dump event tests can hang.
@@ -5249,10 +5236,6 @@
   Send(new FrameMsg_SetTextTrackSettings(routing_id_, params));
 }
 
-const ui::AXTree* RenderFrameHostImpl::GetAXTreeForTesting() {
-  return ax_tree_for_testing_.get();
-}
-
 BrowserAccessibilityManager*
     RenderFrameHostImpl::GetOrCreateBrowserAccessibilityManager() {
   RenderWidgetHostViewBase* view = GetViewForAccessibility();
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index ea543f1..6b1d576 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -293,6 +293,7 @@
   gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override;
   gfx::NativeViewAccessible AccessibilityGetNativeViewAccessibleForWindow()
       override;
+  bool AccessibilityIsMainFrame() override;
 
   // SiteInstanceImpl::Observer
   void RenderProcessGone(SiteInstanceImpl* site_instance) override;
@@ -600,8 +601,7 @@
 
   // Turn on accessibility testing. The given callback will be run
   // every time an accessibility notification is received from the
-  // renderer process, and the accessibility tree it sent can be
-  // retrieved using GetAXTreeForTesting().
+  // renderer process.
   void SetAccessibilityCallbackForTesting(
       const AccessibilityCallbackForTesting& callback);
 
@@ -618,11 +618,6 @@
   // Send a message to the render process to change text track style settings.
   void SetTextTrackSettings(const FrameMsg_TextTrackSettings_Params& params);
 
-  // Returns a snapshot of the accessibility tree received from the
-  // renderer as of the last time an accessibility notification was
-  // received.
-  const ui::AXTree* GetAXTreeForTesting();
-
   // Access the BrowserAccessibilityManager if it already exists.
   BrowserAccessibilityManager* browser_accessibility_manager() const {
     return browser_accessibility_manager_.get();
@@ -1739,8 +1734,6 @@
 
   // Callback when an event is received, for testing.
   AccessibilityCallbackForTesting accessibility_testing_callback_;
-  // The most recently received accessibility tree - for testing only.
-  std::unique_ptr<ui::AXTree> ax_tree_for_testing_;
   // Flag to not create a BrowserAccessibilityManager, for testing. If one
   // already exists it will still be used.
   bool no_create_browser_accessibility_manager_for_testing_;
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 8521ec1..e240b4f 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -2278,4 +2278,19 @@
   EXPECT_EQ(0, popup->GetController().GetEntryCount());
 }
 
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       AccessibilityIsRootIframe) {
+  GURL main_url(
+      embedded_test_server()->GetURL("foo.com", "/page_with_iframe.html"));
+  ASSERT_TRUE(NavigateToURL(shell(), main_url));
+
+  RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
+      shell()->web_contents()->GetMainFrame());
+  EXPECT_TRUE(main_frame->AccessibilityIsMainFrame());
+
+  ASSERT_EQ(1u, main_frame->child_count());
+  RenderFrameHostImpl* iframe = main_frame->child_at(0)->current_frame_host();
+  EXPECT_FALSE(iframe->AccessibilityIsMainFrame());
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index 3260ea6..dc8e8249 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/lazy_instance.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 6a28827..ac2ae6d 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -228,7 +228,7 @@
     switches::kSkiaResourceCacheLimitMb,
     switches::kTestGLLib,
     switches::kTraceToConsole,
-    switches::kUseFakeJpegDecodeAccelerator,
+    switches::kUseFakeMjpegDecodeAccelerator,
     switches::kUseGpuInTests,
     switches::kV,
     switches::kVModule,
diff --git a/content/browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc b/content/browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc
index ca4d08c..c0ac89ac 100644
--- a/content/browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc
+++ b/content/browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc
@@ -10,6 +10,7 @@
 #include "ui/accessibility/accessibility_switches.h"
 #include "ui/accessibility/platform/ax_platform_node_win.h"
 #include "ui/accessibility/platform/ax_system_caret_win.h"
+#include "ui/base/win/hwnd_subclass.h"
 
 namespace content {
 
@@ -91,6 +92,50 @@
   EXPECT_EQ(test_node_->m_dwRef, 1);
 }
 
+// Window subclassing message filter for the legacy window to allow us to
+// examine state after the call to LegacyRenderWidgetHostHWND::Destroy() but
+// before the window is torn down completely. Operating system hooks can run in
+// this narrow window; see crbug.com/945584 for one example.
+class AccessibilityTeardownTestMessageFilter : public ui::HWNDMessageFilter {
+ public:
+  AccessibilityTeardownTestMessageFilter(RenderWidgetHostViewAura* view)
+      : view_(view) {
+    HWND hwnd = view->AccessibilityGetAcceleratedWidget();
+    CHECK(hwnd);
+    ui::HWNDSubclass::AddFilterToTarget(hwnd, this);
+  }
+  ~AccessibilityTeardownTestMessageFilter() override = default;
+
+  // ui::HWNDMessageFilter:
+  bool FilterMessage(HWND hwnd,
+                     UINT message,
+                     WPARAM w_param,
+                     LPARAM l_param,
+                     LRESULT* l_result) override {
+    if (message == WM_DESTROY) {
+      // Verify that the view no longer exposes a NativeViewAccessible.
+      EXPECT_EQ(view_->GetNativeViewAccessible(), nullptr);
+
+      // Remove ourselves as a subclass.
+      ui::HWNDSubclass::RemoveFilterFromAllTargets(this);
+    }
+
+    return true;
+  }
+
+ private:
+  RenderWidgetHostViewAura* view_;
+};
+
+IN_PROC_BROWSER_TEST_F(AccessibilityObjectLifetimeWinBrowserTest,
+                       DoNotReturnObjectDuringTeardown) {
+  NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+  AccessibilityTeardownTestMessageFilter test_message_filter(GetView());
+
+  shell()->Close();
+}
+
 class AccessibilityObjectLifetimeUiaWinBrowserTest
     : public AccessibilityObjectLifetimeWinBrowserTest {
  public:
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
index 6cdd1d1..625566d 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -289,8 +289,6 @@
   }
   DCHECK_EQ(state_, new_state);
   delegated_frame_host_->AttachToCompositor(GetCompositor());
-  if (!dfh_local_surface_id_allocator_.HasValidLocalSurfaceIdAllocation())
-    dfh_local_surface_id_allocator_.GenerateId();
   has_saved_frame_before_state_transition_ =
       delegated_frame_host_->HasSavedFrame();
   delegated_frame_host_->WasShown(
@@ -422,6 +420,9 @@
 
 const viz::LocalSurfaceIdAllocation&
 BrowserCompositorMac::GetRendererLocalSurfaceIdAllocation() {
+  if (!dfh_local_surface_id_allocator_.HasValidLocalSurfaceIdAllocation())
+    dfh_local_surface_id_allocator_.GenerateId();
+
   return dfh_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
 }
 
diff --git a/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc b/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc
index b476b57..35fdee9 100644
--- a/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc
+++ b/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc
@@ -14,7 +14,7 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/i18n/case_conversion.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
index 2ba46640..2a71deea 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -580,6 +580,9 @@
 
 gfx::NativeViewAccessible
 LegacyRenderWidgetHostHWND::GetOrCreateWindowRootAccessible() {
+  if (!host_)
+    return nullptr;
+
   RenderWidgetHostImpl* rwhi =
       RenderWidgetHostImpl::From(host_->GetRenderWidgetHost());
   if (!rwhi)
diff --git a/content/browser/renderer_host/media/video_capture_browsertest.cc b/content/browser/renderer_host/media/video_capture_browsertest.cc
index d649aaa..ba759a0c 100644
--- a/content/browser/renderer_host/media/video_capture_browsertest.cc
+++ b/content/browser/renderer_host/media/video_capture_browsertest.cc
@@ -165,7 +165,7 @@
     command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
     if (params_.exercise_accelerated_jpeg_decoding) {
       base::CommandLine::ForCurrentProcess()->AppendSwitch(
-          switches::kUseFakeJpegDecodeAccelerator);
+          switches::kUseFakeMjpegDecodeAccelerator);
     } else {
       base::CommandLine::ForCurrentProcess()->AppendSwitch(
           switches::kDisableAcceleratedMjpegDecode);
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 098b775..d9d2154 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -15,7 +15,7 @@
 #include "base/command_line.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/feature_list.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/i18n/rtl.h"
 #include "base/json/json_reader.h"
 #include "base/metrics/field_trial.h"
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 8cab000..50e2aad 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -16,7 +16,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/i18n/rtl.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index 7706062..495da59 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -232,6 +232,7 @@
 
 // TODO(jonross): Update Mac to also invalidate its viz::LocalSurfaceIds when
 // performing navigations while hidden. https://crbug.com/935364
+#if !defined(OS_MACOSX)
 // When a navigation occurs while the RenderWidgetHostViewBase is hidden, it
 // should invalidate it's viz::LocalSurfaceId. When subsequently being shown,
 // a new surface should be generated with a new viz::LocalSurfaceId
@@ -293,6 +294,7 @@
   EXPECT_NE(initial_local_surface_id, new_local_surface_id);
 #endif
 }
+#endif  // !defined(OS_MACOSX)
 
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTestBase,
                        CompositorWorksWhenReusingRenderer) {
diff --git a/content/browser/resources/appcache/OWNERS b/content/browser/resources/appcache/OWNERS
index 7afe42b..cacf3fe1 100644
--- a/content/browser/resources/appcache/OWNERS
+++ b/content/browser/resources/appcache/OWNERS
@@ -1,3 +1,7 @@
+# Primary
+mek@chromium.org
+
+# Secondary
 jsbell@chromium.org
 pwnall@chromium.org
 
diff --git a/content/browser/resources/appcache/appcache_internals.html b/content/browser/resources/appcache/appcache_internals.html
index 01bdd32..45ce6bbb 100644
--- a/content/browser/resources/appcache/appcache_internals.html
+++ b/content/browser/resources/appcache/appcache_internals.html
@@ -37,7 +37,11 @@
               </div>
               <div class="appcache-size">
                 <span> Size: </span>
-                <span jscontent="size"></span>
+                <span jscontent="totalSize"></span>
+                =
+                <span jscontent="responseSizes"></span> (response)
+                +
+                <span jscontent="paddingSizes"></span> (padding)
               </div>
               <div class="appcache-dates">
                 <ul>
@@ -82,7 +86,11 @@
                       jscontent="fileUrl" jsvalues=".responseId:responseId">
           </a>
         </span>
-        <span jscontent="size"></span>
+        <span jscontent="totalSize"></span>
+        =
+        <span jscontent="responseSize"></span> (response)
+        +
+        <span jscontent="paddingSize"></span> (padding)
         <span jscontent="properties"></span>
       </div>
     </div>
diff --git a/content/browser/resources/appcache/appcache_internals.js b/content/browser/resources/appcache/appcache_internals.js
index 6191754..91bc543c 100644
--- a/content/browser/resources/appcache/appcache_internals.js
+++ b/content/browser/resources/appcache/appcache_internals.js
@@ -168,7 +168,9 @@
       }
       properties = properties.join(',');
       simpleVector.push({
-        size: details.size,
+        responseSize: details.responseSize,
+        paddingSize: details.paddingSize,
+        totalSize: details.totalSize,
         properties: properties,
         fileUrl: details.url,
         responseId: details.responseId
diff --git a/content/browser/service_worker/service_worker_navigation_handle.h b/content/browser/service_worker/service_worker_navigation_handle.h
index 9e29cb8..c11f08f 100644
--- a/content/browser/service_worker/service_worker_navigation_handle.h
+++ b/content/browser/service_worker/service_worker_navigation_handle.h
@@ -37,17 +37,10 @@
 //
 //   4) When the navigation is ready to commit, the NavigationRequest will
 //   call ServiceWorkerNavigationHandle::OnBeginNavigationCommit() to
-//     - update the render process id and the frame id for the
-//     ServiceWorkerProviderHost.
+//     - complete the initialization for the ServiceWorkerProviderHost.
 //     - take out the provider info to be sent as part of navigation commit IPC.
 //
-//   5) If the commit leads to the creation of a
-//   ServiceWorkerNetworkProviderForFrame based on the provider info in the
-//   renderer, a ServiceWorkerContainerHost::OnProviderCreated() Mojo call will
-//   be received by the ServiceWorkerProviderHost to complete its
-//   initialization.
-//
-//   6) When the navigation finishes, the ServiceWorkerNavigationHandle is
+//   5) When the navigation finishes, the ServiceWorkerNavigationHandle is
 //   destroyed. The destructor of the ServiceWorkerNavigationHandle destroys
 //   the provider info which in turn leads to the destruction of an unclaimed
 //   ServiceWorkerProviderHost, and posts a task to destroy the
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 51715b5..f1c2138 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -710,6 +710,8 @@
   DCHECK_EQ(MSG_ROUTING_NONE, frame_id_);
   DCHECK_NE(MSG_ROUTING_NONE, render_frame_id);
   frame_id_ = render_frame_id;
+
+  TransitionToClientPhase(ClientPhase::kResponseCommitted);
 }
 
 blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr
@@ -1194,17 +1196,6 @@
   versions_to_update_.clear();
 }
 
-void ServiceWorkerProviderHost::OnProviderCreated() {
-  DCHECK_EQ(blink::mojom::ServiceWorkerProviderType::kForWindow, type_);
-  DCHECK_EQ(kDocumentMainThreadId, render_thread_id_);
-  // |frame_id_| and |render_process_id_| have already been set by
-  // OnBeginNavigationCommit().
-  DCHECK_NE(MSG_ROUTING_NONE, frame_id_);
-  DCHECK_NE(ChildProcessHost::kInvalidUniqueID, render_process_id_);
-
-  TransitionToClientPhase(ClientPhase::kResponseCommitted);
-}
-
 void ServiceWorkerProviderHost::OnExecutionReady() {
   if (!IsProviderForClient()) {
     mojo::ReportBadMessage("SWPH_OER_NOT_CLIENT");
@@ -1367,10 +1358,6 @@
   return client_phase_ == ClientPhase::kExecutionReady;
 }
 
-void ServiceWorkerProviderHost::CallOnProviderCreatedForTesting() {
-  OnProviderCreated();
-}
-
 void ServiceWorkerProviderHost::SetExecutionReady() {
   DCHECK(!is_execution_ready());
   TransitionToClientPhase(ClientPhase::kExecutionReady);
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 6136f13..5e0b84a 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -124,9 +124,8 @@
   //
   // The returned host stays alive as long as the filled |out_provider_info|
   // stays alive (namely, as long as |out_provider_info->host_ptr_info| stays
-  // alive). Upon successful navigation, another Mojo call
-  // ServiceWorkerContainerHost::OnProviderCreated() coming from the renderer
-  // process will complete initialization for it.
+  // alive). Upon navigation commit, OnBeginNavigationCommit() will complete
+  // initialization for it.
   static base::WeakPtr<ServiceWorkerProviderHost> PreCreateNavigationHost(
       base::WeakPtr<ServiceWorkerContextCore> context,
       bool are_ancestors_secure,
@@ -355,10 +354,8 @@
       scoped_refptr<ServiceWorkerRegistration> registration);
 
   // For service worker window clients. Called when the navigation is ready to
-  // commit in the browser process to set up some information (renderer process
-  // id and frame id) already available for the pre-created instance. Later the
-  // Mojo call ServiceWorkerContainerHost::OnProviderCreated() will be triggered
-  // from the renderer process to complete the initialization.
+  // commit in the browser process to complete the initialization for the
+  // pre-created instance.
   void OnBeginNavigationCommit(int render_process_id, int render_frame_id);
 
   // For service worker execution contexts. Completes initialization of this
@@ -456,8 +453,6 @@
   // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-execution-ready-flag
   bool is_execution_ready() const;
 
-  void CallOnProviderCreatedForTesting();
-
  private:
   // For service worker clients. The flow is kInitial -> kResponseCommitted ->
   // kExecutionReady.
@@ -563,7 +558,6 @@
                               container_host_request) override;
   void Ping(PingCallback callback) override;
   void HintToUpdateServiceWorker() override;
-  void OnProviderCreated() override;
   void OnExecutionReady() override;
 
   // Callback for ServiceWorkerContextCore::RegisterServiceWorker().
diff --git a/content/browser/service_worker/service_worker_provider_host_unittest.cc b/content/browser/service_worker/service_worker_provider_host_unittest.cc
index 10bbf43d..85a7408 100644
--- a/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -166,10 +166,6 @@
     // process right before navigation commit.
     host->OnBeginNavigationCommit(helper_->mock_render_process_id(),
                                   1 /* route_id */);
-    // In production code this is a Mojo call
-    // ServiceWorkerContainerHost::OnProviderCreated() triggered from the
-    // renderer process.
-    host->OnProviderCreated();
   }
 
   blink::mojom::ServiceWorkerErrorType Register(
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc
index c280f3a..89a9b4cf 100644
--- a/content/browser/service_worker/service_worker_test_utils.cc
+++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -247,10 +247,6 @@
   // In production code this is called from NavigationRequest in the browser
   // process right before navigation commit.
   host->OnBeginNavigationCommit(process_id, 1 /* route_id */);
-  // In production code this is a Mojo call
-  // ServiceWorkerContainerHost::OnProviderCreated() triggered from the renderer
-  // process.
-  host->CallOnProviderCreatedForTesting();
   return host;
 }
 
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index 560bae8..777e99b 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -1284,7 +1284,7 @@
   EXPECT_FALSE(IsIsolatedOrigin(blank_url));
 
   // Cleanup.
-  policy->RemoveIsolatedOriginsForBrowserContext(*context());
+  policy->OnBrowserContextBeingDestroyed(*context());
 }
 
 }  // namespace content
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index ec25ad8..3f7bf8fb 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -5072,8 +5072,15 @@
 
 // Tests that performing a touchpad double-tap zoom over an OOPIF offers the
 // synthetic wheel event to the child.
+#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_WIN)
+// Flaky on mac, linux and win. crbug.com/947193
+#define MAYBE_TouchpadDoubleTapZoomOverOOPIF \
+  DISABLED_TouchpadDoubleTapZoomOverOOPIF
+#else
+#define MAYBE_TouchpadDoubleTapZoomOverOOPIF TouchpadDoubleTapZoomOverOOPIF
+#endif
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       TouchpadDoubleTapZoomOverOOPIF) {
+                       MAYBE_TouchpadDoubleTapZoomOverOOPIF) {
   GURL main_url(embedded_test_server()->GetURL(
       "/frame_tree/page_with_positioned_frame.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc
index dde1b73..20cf874 100644
--- a/content/browser/tracing/background_tracing_manager_browsertest.cc
+++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -394,9 +394,8 @@
 }
 
 // This tests that non-whitelisted args get stripped if required.
-// TODO(https://crbug.com/945484): This tracing test is flaky.
 IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
-                       DISABLED_NotWhitelistedArgsStripped) {
+                       NotWhitelistedArgsStripped) {
   TestTraceReceiverHelper trace_receiver_helper;
   TestBackgroundTracingHelper background_tracing_helper;
 
@@ -437,9 +436,8 @@
 // the full WaitForTracingEnabled() callback (background tracing will directly
 // enable the TraceLog so we get events prior to waiting for the whole IPC
 // sequence to enable tracing coming back from the tracing service).
-// TODO(https://crbug.com/945484): This tracing test is flaky.
 IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
-                       DISABLED_EarlyTraceEventsInTrace) {
+                       EarlyTraceEventsInTrace) {
   TestTraceReceiverHelper trace_receiver_helper;
   TestBackgroundTracingHelper background_tracing_helper;
 
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index 91a11cc..51f72c8 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -389,7 +389,7 @@
       switches::kProxyServer,
       switches::kDisableAcceleratedMjpegDecode,
       switches::kUseFakeDeviceForMediaStream,
-      switches::kUseFakeJpegDecodeAccelerator,
+      switches::kUseFakeMjpegDecodeAccelerator,
       switches::kUseFileForFakeVideoCapture,
       switches::kUseMockCertVerifierForTesting,
       switches::kUtilityStartupDialog,
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 6bf5dfc..895b1c4a 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -599,7 +599,7 @@
 
 jint WebContentsAndroid::GetThemeColor(JNIEnv* env,
                                        const JavaParamRef<jobject>& obj) {
-  return web_contents_->GetThemeColor();
+  return web_contents_->GetThemeColor().value_or(SK_ColorTRANSPARENT);
 }
 
 void WebContentsAndroid::RequestSmartClipExtract(
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index 6223f76..b6c793d 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -151,6 +151,7 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jobj);
 
+  // No theme color is represented by SK_ColorTRANSPARENT.
   jint GetThemeColor(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& obj);
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 2491627..cb08246 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -562,8 +562,6 @@
       is_resume_pending_(false),
       interstitial_page_(nullptr),
       has_accessed_initial_document_(false),
-      theme_color_(SK_ColorTRANSPARENT),
-      last_sent_theme_color_(SK_ColorTRANSPARENT),
       did_first_visually_non_empty_paint_(false),
       capturer_count_(0),
       is_being_destroyed_(false),
@@ -1090,7 +1088,7 @@
   screen_orientation_provider_->OnOrientationChange();
 }
 
-SkColor WebContentsImpl::GetThemeColor() {
+base::Optional<SkColor> WebContentsImpl::GetThemeColor() {
   return theme_color_;
 }
 
@@ -4416,7 +4414,7 @@
     did_first_visually_non_empty_paint_ = false;
 
     // Reset theme color on navigation to new page.
-    theme_color_ = SK_ColorTRANSPARENT;
+    theme_color_.reset();
   }
 
   if (delegate_)
@@ -4459,7 +4457,7 @@
 }
 
 void WebContentsImpl::OnThemeColorChanged(RenderFrameHostImpl* source,
-                                          SkColor theme_color) {
+                                          base::Optional<SkColor> theme_color) {
   if (source != GetMainFrame()) {
     // Only the main frame may control the theme.
     return;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index be9931e..3fb7ee650 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -309,7 +309,7 @@
   RenderWidgetHostView* GetTopLevelRenderWidgetHostView() override;
   void ClosePage() override;
   RenderWidgetHostView* GetFullscreenRenderWidgetHostView() override;
-  SkColor GetThemeColor() override;
+  base::Optional<SkColor> GetThemeColor() override;
   WebUI* GetWebUI() override;
   WebUI* GetCommittedWebUI() override;
   void SetUserAgentOverride(const std::string& override,
@@ -1209,7 +1209,8 @@
                       const base::string16& user_input);
 
   // IPC message handlers.
-  void OnThemeColorChanged(RenderFrameHostImpl* source, SkColor theme_color);
+  void OnThemeColorChanged(RenderFrameHostImpl* source,
+                           base::Optional<SkColor> theme_color);
   void OnDidLoadResourceFromMemoryCache(
       RenderFrameHostImpl* source,
       const GURL& url,
@@ -1572,10 +1573,10 @@
 
   // The theme color for the underlying document as specified
   // by theme-color meta tag.
-  SkColor theme_color_;
+  base::Optional<SkColor> theme_color_;
 
   // The last published theme color.
-  SkColor last_sent_theme_color_;
+  base::Optional<SkColor> last_sent_theme_color_;
 
   // Whether the first visually non-empty paint has occurred.
   bool did_first_visually_non_empty_paint_;
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index eed1e64..b65ab005 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -276,9 +276,7 @@
 class TestWebContentsObserver : public WebContentsObserver {
  public:
   explicit TestWebContentsObserver(WebContents* contents)
-      : WebContentsObserver(contents),
-        last_theme_color_(SK_ColorTRANSPARENT) {
-  }
+      : WebContentsObserver(contents) {}
   ~TestWebContentsObserver() override {}
 
   void DidFinishLoad(RenderFrameHost* render_frame_host,
@@ -297,19 +295,19 @@
     EXPECT_TRUE(web_contents()->CompletedFirstVisuallyNonEmptyPaint());
   }
 
-  void DidChangeThemeColor(SkColor theme_color) override {
+  void DidChangeThemeColor(base::Optional<SkColor> theme_color) override {
     last_theme_color_ = theme_color;
   }
 
   const GURL& last_url() const { return last_url_; }
-  SkColor last_theme_color() const { return last_theme_color_; }
+  base::Optional<SkColor> last_theme_color() const { return last_theme_color_; }
   bool observed_did_first_visually_non_empty_paint() const {
     return observed_did_first_visually_non_empty_paint_;
   }
 
  private:
   GURL last_url_;
-  SkColor last_theme_color_;
+  base::Optional<SkColor> last_theme_color_;
   bool observed_did_first_visually_non_empty_paint_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
@@ -3199,10 +3197,8 @@
   TestRenderFrameHost* rfh = main_test_rfh();
   rfh->InitializeRenderFrameIfNeeded();
 
-  SkColor transparent = SK_ColorTRANSPARENT;
-
-  EXPECT_EQ(transparent, contents()->GetThemeColor());
-  EXPECT_EQ(transparent, observer.last_theme_color());
+  EXPECT_EQ(base::nullopt, contents()->GetThemeColor());
+  EXPECT_EQ(base::nullopt, observer.last_theme_color());
 
   // Theme color changes should not propagate past the WebContentsImpl before
   // the first visually non-empty paint has occurred.
@@ -3210,7 +3206,7 @@
       FrameHostMsg_DidChangeThemeColor(rfh->GetRoutingID(), SK_ColorRED));
 
   EXPECT_EQ(SK_ColorRED, contents()->GetThemeColor());
-  EXPECT_EQ(transparent, observer.last_theme_color());
+  EXPECT_EQ(base::nullopt, observer.last_theme_color());
 
   // Simulate that the first visually non-empty paint has occurred. This will
   // propagate the current theme color to the delegates.
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 540ef3c0..bfe21f5a 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -42,6 +42,7 @@
 #include "device/fido/authenticator_data.h"
 #include "device/fido/fake_fido_discovery.h"
 #include "device/fido/features.h"
+#include "device/fido/fido_authenticator.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/hid/fake_hid_impl_for_testing.h"
 #include "device/fido/mock_fido_device.h"
@@ -2561,14 +2562,20 @@
     : public AuthenticatorRequestClientDelegate {
  public:
   explicit PINTestAuthenticatorRequestDelegate(
+      bool supports_pin,
       const PINList& pins,
       base::Optional<InterestingFailureReason>* failure_reason)
-      : expected_(pins), failure_reason_(failure_reason) {}
+      : supports_pin_(supports_pin),
+        expected_(pins),
+        failure_reason_(failure_reason) {}
   ~PINTestAuthenticatorRequestDelegate() override { DCHECK(expected_.empty()); }
 
+  bool SupportsPIN() const override { return supports_pin_; }
+
   void CollectPIN(
       base::Optional<int> attempts,
       base::OnceCallback<void(std::string)> provide_pin_cb) override {
+    DCHECK(supports_pin_);
     DCHECK(!expected_.empty());
     DCHECK(attempts == expected_.front().first)
         << "got: " << attempts.value_or(-1)
@@ -2580,6 +2587,8 @@
         FROM_HERE, base::BindOnce(std::move(provide_pin_cb), std::move(pin)));
   }
 
+  void FinishCollectPIN() override {}
+
   bool DoesBlockRequestOnFailure(InterestingFailureReason reason) override {
     *failure_reason_ = reason;
     return AuthenticatorRequestClientDelegate::DoesBlockRequestOnFailure(
@@ -2587,6 +2596,7 @@
   }
 
  private:
+  const bool supports_pin_;
   PINList expected_;
   base::Optional<InterestingFailureReason>* const failure_reason_;
   DISALLOW_COPY_AND_ASSIGN(PINTestAuthenticatorRequestDelegate);
@@ -2598,9 +2608,10 @@
   GetWebAuthenticationRequestDelegate(
       RenderFrameHost* render_frame_host) override {
     return std::make_unique<PINTestAuthenticatorRequestDelegate>(
-        expected, &failure_reason);
+        supports_pin, expected, &failure_reason);
   }
 
+  bool supports_pin = true;
   PINList expected;
   base::Optional<InterestingFailureReason> failure_reason;
 };
@@ -2644,6 +2655,8 @@
       case 0:
         // No support.
         config.pin_support = false;
+        virtual_device_.mutable_state()->pin = "";
+        virtual_device_.mutable_state()->retries = 0;
         break;
 
       case 1:
@@ -2687,8 +2700,12 @@
 
 TEST_F(PINAuthenticatorImplTest, MakeCredential) {
   TestServiceManagerContext smc;
+
+  typedef int Expectations[3][3];
+  // kExpectedWithUISupport enumerates the expected behaviour when the embedder
+  // supports prompting the user for a PIN.
   // clang-format off
-  const int kExpected[3][3] = {
+  const Expectations kExpectedWithUISupport = {
     //                   discouraged | preferred | required
     /* No support */  {    kNoPIN,      kNoPIN,     kFailure },
     /* PIN not set */ {    kNoPIN,      kNoPIN,     kSetPIN  },
@@ -2699,61 +2716,85 @@
   };
   // clang-format on
 
-  for (int support_level = 0; support_level <= 2; support_level++) {
-    SCOPED_TRACE(kPINSupportDescription[support_level]);
-    ConfigureVirtualDevice(support_level);
+  // kExpectedWithoutUISupport enumerates the expected behaviour when the
+  // embedder cannot prompt the user for a PIN.
+  // clang-format off
+  const Expectations kExpectedWithoutUISupport = {
+    //                   discouraged | preferred | required
+    /* No support */  {    kNoPIN,      kNoPIN,     kFailure },
+    /* PIN not set */ {    kNoPIN,      kNoPIN,     kFailure },
+    /* PIN set */     {    kFailure,    kFailure,   kFailure },
+    //                        ^            ^
+    //                        |            |
+    //            VirtualCtap2Device cannot fall back to U2F and
+    //            a PIN is required to create credentials once set
+    //            in CTAP 2.0.
+  };
+  // clang-format on
 
-    for (int uv_level = 0; uv_level <= 2; uv_level++) {
-      SCOPED_TRACE(kUVDescription[uv_level]);
+  for (bool ui_support : {false, true}) {
+    SCOPED_TRACE(::testing::Message() << "ui_support=" << ui_support);
+    const Expectations& expected =
+        ui_support ? kExpectedWithUISupport : kExpectedWithoutUISupport;
+    test_client_.supports_pin = ui_support;
 
-      switch (kExpected[support_level][uv_level]) {
-        case kNoPIN:
-        case kFailure:
-          // There shouldn't be any PIN prompts.
-          test_client_.expected.clear();
-          break;
+    for (int support_level = 0; support_level <= 2; support_level++) {
+      SCOPED_TRACE(kPINSupportDescription[support_level]);
+      ConfigureVirtualDevice(support_level);
 
-        case kSetPIN:
-          // A single PIN prompt to set a PIN is expected.
-          test_client_.expected = {{base::nullopt, kTestPIN}};
-          break;
+      for (int uv_level = 0; uv_level <= 2; uv_level++) {
+        SCOPED_TRACE(kUVDescription[uv_level]);
 
-        case kUsePIN:
-          // A single PIN prompt to get the PIN is expected.
-          test_client_.expected = {{8, kTestPIN}};
-          break;
+        switch (expected[support_level][uv_level]) {
+          case kNoPIN:
+          case kFailure:
+            // There shouldn't be any PIN prompts.
+            test_client_.expected.clear();
+            break;
 
-        default:
-          NOTREACHED();
-      }
+          case kSetPIN:
+            // A single PIN prompt to set a PIN is expected.
+            test_client_.expected = {{base::nullopt, kTestPIN}};
+            break;
 
-      AuthenticatorPtr authenticator = ConnectToAuthenticator();
-      TestMakeCredentialCallback callback_receiver;
-      authenticator->MakeCredential(make_credential_options(kUVLevel[uv_level]),
-                                    callback_receiver.callback());
-      callback_receiver.WaitForCallback();
+          case kUsePIN:
+            // A single PIN prompt to get the PIN is expected.
+            test_client_.expected = {{8, kTestPIN}};
+            break;
 
-      switch (kExpected[support_level][uv_level]) {
-        case kFailure:
-          EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR,
-                    callback_receiver.status());
-          break;
+          default:
+            NOTREACHED();
+        }
 
-        case kNoPIN:
-          EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
-          EXPECT_EQ("", virtual_device_.mutable_state()->pin);
-          EXPECT_FALSE(HasUV(callback_receiver));
-          break;
+        AuthenticatorPtr authenticator = ConnectToAuthenticator();
+        TestMakeCredentialCallback callback_receiver;
+        authenticator->MakeCredential(
+            make_credential_options(kUVLevel[uv_level]),
+            callback_receiver.callback());
+        callback_receiver.WaitForCallback();
 
-        case kSetPIN:
-        case kUsePIN:
-          EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
-          EXPECT_EQ(kTestPIN, virtual_device_.mutable_state()->pin);
-          EXPECT_TRUE(HasUV(callback_receiver));
-          break;
+        switch (expected[support_level][uv_level]) {
+          case kFailure:
+            EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR,
+                      callback_receiver.status());
+            break;
 
-        default:
-          NOTREACHED();
+          case kNoPIN:
+            EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+            EXPECT_EQ("", virtual_device_.mutable_state()->pin);
+            EXPECT_FALSE(HasUV(callback_receiver));
+            break;
+
+          case kSetPIN:
+          case kUsePIN:
+            EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+            EXPECT_EQ(kTestPIN, virtual_device_.mutable_state()->pin);
+            EXPECT_TRUE(HasUV(callback_receiver));
+            break;
+
+          default:
+            NOTREACHED();
+        }
       }
     }
   }
@@ -2798,67 +2839,89 @@
 
 TEST_F(PINAuthenticatorImplTest, GetAssertion) {
   TestServiceManagerContext smc;
+
+  typedef int Expectations[3][3];
+  // kExpectedWithUISupport enumerates the expected behaviour when the embedder
+  // supports prompting the user for a PIN.
   // clang-format off
-  const int kExpected[3][3] = {
+  const Expectations kExpectedWithUISupport = {
     //                   discouraged | preferred | required
     /* No support */  {    kNoPIN,      kNoPIN,     kFailure },
-    /* PIN not set */ {    kNoPIN,      kNoPIN,     kFailure  },
+    /* PIN not set */ {    kNoPIN,      kNoPIN,     kFailure },
     /* PIN set */     {    kNoPIN,      kUsePIN,    kUsePIN  },
   };
   // clang-format on
 
+  // kExpectedWithoutUISupport enumerates the expected behaviour when the
+  // embedder cannot prompt the user for a PIN.
+  // clang-format off
+  const Expectations kExpectedWithoutUISupport = {
+    //                   discouraged | preferred | required
+    /* No support */  {    kNoPIN,      kNoPIN,     kFailure },
+    /* PIN not set */ {    kNoPIN,      kNoPIN,     kFailure },
+    /* PIN set */     {    kNoPIN,      kNoPIN,     kFailure },
+  };
+  // clang-format on
+
   PublicKeyCredentialRequestOptionsPtr dummy_options = get_credential_options();
   ASSERT_TRUE(virtual_device_.mutable_state()->InjectRegistration(
       dummy_options->allow_credentials[0]->id, kTestRelyingPartyId));
 
-  for (int support_level = 0; support_level <= 2; support_level++) {
-    SCOPED_TRACE(kPINSupportDescription[support_level]);
-    ConfigureVirtualDevice(support_level);
+  for (bool ui_support : {false, true}) {
+    SCOPED_TRACE(::testing::Message() << "ui_support=" << ui_support);
+    const Expectations& expected =
+        ui_support ? kExpectedWithUISupport : kExpectedWithoutUISupport;
+    test_client_.supports_pin = ui_support;
 
-    for (int uv_level = 0; uv_level <= 2; uv_level++) {
-      SCOPED_TRACE(kUVDescription[uv_level]);
+    for (int support_level = 0; support_level <= 2; support_level++) {
+      SCOPED_TRACE(kPINSupportDescription[support_level]);
+      ConfigureVirtualDevice(support_level);
 
-      switch (kExpected[support_level][uv_level]) {
-        case kNoPIN:
-        case kFailure:
-          // No PIN prompts are expected.
-          test_client_.expected.clear();
-          break;
+      for (int uv_level = 0; uv_level <= 2; uv_level++) {
+        SCOPED_TRACE(kUVDescription[uv_level]);
 
-        case kUsePIN:
-          // A single prompt to get the PIN is expected.
-          test_client_.expected = {{8, kTestPIN}};
-          break;
+        switch (expected[support_level][uv_level]) {
+          case kNoPIN:
+          case kFailure:
+            // No PIN prompts are expected.
+            test_client_.expected.clear();
+            break;
 
-        default:
-          NOTREACHED();
-      }
+          case kUsePIN:
+            // A single prompt to get the PIN is expected.
+            test_client_.expected = {{8, kTestPIN}};
+            break;
 
-      AuthenticatorPtr authenticator = ConnectToAuthenticator();
-      TestGetAssertionCallback callback_receiver;
-      authenticator->GetAssertion(get_credential_options(kUVLevel[uv_level]),
-                                  callback_receiver.callback());
-      callback_receiver.WaitForCallback();
+          default:
+            NOTREACHED();
+        }
 
-      switch (kExpected[support_level][uv_level]) {
-        case kFailure:
-          EXPECT_EQ(AuthenticatorStatus::CREDENTIAL_NOT_RECOGNIZED,
-                    callback_receiver.status());
-          break;
+        AuthenticatorPtr authenticator = ConnectToAuthenticator();
+        TestGetAssertionCallback callback_receiver;
+        authenticator->GetAssertion(get_credential_options(kUVLevel[uv_level]),
+                                    callback_receiver.callback());
+        callback_receiver.WaitForCallback();
 
-        case kNoPIN:
-          EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
-          EXPECT_FALSE(HasUV(callback_receiver));
-          break;
+        switch (expected[support_level][uv_level]) {
+          case kFailure:
+            EXPECT_EQ(AuthenticatorStatus::CREDENTIAL_NOT_RECOGNIZED,
+                      callback_receiver.status());
+            break;
 
-        case kUsePIN:
-          EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
-          EXPECT_EQ(kTestPIN, virtual_device_.mutable_state()->pin);
-          EXPECT_TRUE(HasUV(callback_receiver));
-          break;
+          case kNoPIN:
+            EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+            EXPECT_FALSE(HasUV(callback_receiver));
+            break;
 
-        default:
-          NOTREACHED();
+          case kUsePIN:
+            EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+            EXPECT_EQ(kTestPIN, virtual_device_.mutable_state()->pin);
+            EXPECT_TRUE(HasUV(callback_receiver));
+            break;
+
+          default:
+            NOTREACHED();
+        }
       }
     }
   }
@@ -2915,6 +2978,7 @@
     UVAuthenticatorImplTest::SetUp();
     device::VirtualCtap2Device::Config config;
     config.internal_uv_support = true;
+    config.u2f_support = true;
     virtual_device_.SetCtap2Config(config);
     NavigateAndCommit(GURL(kTestOrigin1));
   }
@@ -2964,6 +3028,36 @@
   }
 }
 
+TEST_F(InternalUVAuthenticatorImplTest, MakeCredentialCryptotoken) {
+  TestServiceManagerContext smc;
+  auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
+      base::Time::Now(), base::TimeTicks::Now());
+  auto authenticator = ConstructAuthenticatorWithTimer(task_runner);
+  url::AddStandardScheme("chrome-extension", url::SCHEME_WITH_HOST);
+  OverrideLastCommittedOrigin(main_rfh(),
+                              url::Origin::Create(GURL(kCryptotokenOrigin)));
+
+  for (const auto fingerprints_enrolled : {false, true}) {
+    SCOPED_TRACE(::testing::Message()
+                 << "fingerprints_enrolled=" << fingerprints_enrolled);
+    virtual_device_.mutable_state()->fingerprints_enrolled =
+        fingerprints_enrolled;
+    TestMakeCredentialCallback callback_receiver;
+    authenticator->MakeCredential(
+        make_credential_options(
+            blink::mojom::UserVerificationRequirement::PREFERRED),
+        callback_receiver.callback());
+
+    callback_receiver.WaitForCallback();
+    EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+    // The credential should have been created over U2F.
+    for (const auto& registration :
+         virtual_device_.mutable_state()->registrations) {
+      EXPECT_TRUE(registration.second.is_u2f);
+    }
+  }
+}
+
 TEST_F(InternalUVAuthenticatorImplTest, GetAssertion) {
   TestServiceManagerContext smc;
   AuthenticatorPtr authenticator = ConnectToAuthenticator();
@@ -3009,6 +3103,31 @@
   }
 }
 
+TEST_F(InternalUVAuthenticatorImplTest, GetAssertionCryptotoken) {
+  TestServiceManagerContext smc;
+  AuthenticatorPtr authenticator = ConnectToAuthenticator();
+  url::AddStandardScheme("chrome-extension", url::SCHEME_WITH_HOST);
+  OverrideLastCommittedOrigin(main_rfh(),
+                              url::Origin::Create(GURL(kCryptotokenOrigin)));
+  ASSERT_TRUE(virtual_device_.mutable_state()->InjectRegistration(
+      get_credential_options()->allow_credentials[0]->id, kTestRelyingPartyId));
+
+  for (const auto fingerprints_enrolled : {false, true}) {
+    SCOPED_TRACE(::testing::Message()
+                 << "fingerprints_enrolled=" << fingerprints_enrolled);
+    virtual_device_.mutable_state()->fingerprints_enrolled =
+        fingerprints_enrolled;
+    TestGetAssertionCallback callback_receiver;
+    authenticator->GetAssertion(
+        get_credential_options(
+            blink::mojom::UserVerificationRequirement::PREFERRED),
+        callback_receiver.callback());
+
+    callback_receiver.WaitForCallback();
+    EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+  }
+}
+
 // ResidentKeyTestAuthenticatorRequestDelegate is a delegate that:
 //   a) always returns |kTestPIN| when asked for a PIN.
 //   b) sorts potential resident-key accounts by user ID, maps them to a string
@@ -3024,6 +3143,8 @@
       : expected_accounts_(expected_accounts),
         selected_user_id_(selected_user_id) {}
 
+  bool SupportsPIN() const override { return true; }
+
   void CollectPIN(
       base::Optional<int> attempts,
       base::OnceCallback<void(std::string)> provide_pin_cb) override {
@@ -3031,6 +3152,8 @@
         FROM_HERE, base::BindOnce(std::move(provide_pin_cb), kTestPIN));
   }
 
+  void FinishCollectPIN() override {}
+
   bool SupportsResidentKeys() override { return true; }
 
   void SelectAccount(
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index 8a51f69e8..3713e1a 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -137,7 +137,7 @@
   }
 
   if (is_android) {
-    deps += [ "//third_party/android_tools:cpu_features" ]
+    deps += [ "//third_party/android_sdk:cpu_features" ]
   }
 
   if (is_linux) {
diff --git a/content/common/child_process_host_impl.cc b/content/common/child_process_host_impl.cc
index 761d1453..160dd43 100644
--- a/content/common/child_process_host_impl.cc
+++ b/content/common/child_process_host_impl.cc
@@ -9,7 +9,7 @@
 #include "base/atomic_sequence_num.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_math.h"
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 5ea1818..98cd76c 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -1465,7 +1465,7 @@
 
 // Notify browser the theme color has been changed.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeThemeColor,
-                    SkColor /* theme_color */)
+                    base::Optional<SkColor> /* theme_color */)
 
 // Response for FrameMsg_TextSurroundingSelectionRequest, |startOffset| and
 // |endOffset| are the offsets of the selection in the returned |content|.
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc
index ebcd52e..8ba33d4 100644
--- a/content/public/browser/authenticator_request_client_delegate.cc
+++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -95,10 +95,18 @@
     base::StringPiece authenticator_id,
     bool is_in_pairing_mode) {}
 
+bool AuthenticatorRequestClientDelegate::SupportsPIN() const {
+  return false;
+}
+
 void AuthenticatorRequestClientDelegate::CollectPIN(
     base::Optional<int> attempts,
-    base::OnceCallback<void(std::string)> provide_pin_cb) {}
+    base::OnceCallback<void(std::string)> provide_pin_cb) {
+  NOTREACHED();
+}
 
-void AuthenticatorRequestClientDelegate::FinishCollectPIN() {}
+void AuthenticatorRequestClientDelegate::FinishCollectPIN() {
+  NOTREACHED();
+}
 
 }  // namespace content
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h
index 066a0b3..f1e40e8 100644
--- a/content/public/browser/authenticator_request_client_delegate.h
+++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -12,6 +12,7 @@
 #include "base/optional.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
+#include "device/fido/authenticator_get_assertion_response.h"
 #include "device/fido/fido_request_handler_base.h"
 #include "device/fido/fido_transport_protocol.h"
 
@@ -155,6 +156,7 @@
                                   std::string new_authenticator_id) override;
   void FidoAuthenticatorPairingModeChanged(base::StringPiece authenticator_id,
                                            bool is_in_pairing_mode) override;
+  bool SupportsPIN() const override;
   void CollectPIN(
       base::Optional<int> attempts,
       base::OnceCallback<void(std::string)> provide_pin_cb) override;
diff --git a/content/public/browser/global_routing_id.h b/content/public/browser/global_routing_id.h
index bf6a9d8..7cb4ea0 100644
--- a/content/public/browser/global_routing_id.h
+++ b/content/public/browser/global_routing_id.h
@@ -7,7 +7,7 @@
 
 #include <tuple>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "ipc/ipc_message.h"
 
 namespace content {
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 2fe0a25a..b33d118 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -361,8 +361,8 @@
   virtual RenderWidgetHostView* GetFullscreenRenderWidgetHostView() = 0;
 
   // Returns the theme color for the underlying content as set by the
-  // theme-color meta tag.
-  virtual SkColor GetThemeColor() = 0;
+  // theme-color meta tag if any.
+  virtual base::Optional<SkColor> GetThemeColor() = 0;
 
   // Returns the committed WebUI if one exists, otherwise the pending one.
   virtual WebUI* GetWebUI() = 0;
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index d35cdd3..88d812b 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -472,7 +472,7 @@
       const std::vector<AXLocationChangeNotificationDetails>& details) {}
 
   // Invoked when theme color is changed to |theme_color|.
-  virtual void DidChangeThemeColor(SkColor theme_color) {}
+  virtual void DidChangeThemeColor(base::Optional<SkColor> theme_color) {}
 
   // Invoked when media is playing or paused.  |id| is unique per player and per
   // RenderFrameHost.  There may be multiple players within a RenderFrameHost
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h
index e5c2a0a..3e23941 100644
--- a/content/public/renderer/render_frame.h
+++ b/content/public/renderer/render_frame.h
@@ -306,6 +306,12 @@
       const url::Origin& initiator_origin,
       network::mojom::URLLoaderFactoryPtr url_loader_factory) = 0;
 
+  // Synchronously performs the complete set of document lifecycle phases,
+  // including updates to the compositor state and rasterization, then sending
+  // a frame to the viz display compositor. Does nothing if RenderFrame is not
+  // a local root.
+  virtual void UpdateAllLifecyclePhasesAndCompositeForTesting() = 0;
+
  protected:
   ~RenderFrame() override {}
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index b3c62889..69f96d9 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -203,8 +203,6 @@
     "manifest/manifest_change_notifier.h",
     "manifest/manifest_manager.cc",
     "manifest/manifest_manager.h",
-    "manifest/manifest_parser.cc",
-    "manifest/manifest_parser.h",
     "manifest/manifest_uma_util.cc",
     "manifest/manifest_uma_util.h",
     "media/android/flinging_renderer_client_factory.cc",
@@ -576,6 +574,7 @@
   ]
 
   deps = [
+    "//base",
     "//base:i18n",
     "//cc",
     "//cc/animation",
@@ -749,7 +748,7 @@
     set_sources_assignment_filter(sources_assignment_filter)
 
     deps += [
-      "//third_party/android_tools:cpu_features",
+      "//third_party/android_sdk:cpu_features",
       "//third_party/libphonenumber",
     ]
   } else {
diff --git a/content/renderer/appcache/web_application_cache_host_impl.cc b/content/renderer/appcache/web_application_cache_host_impl.cc
index b41aca99..9c3a69d 100644
--- a/content/renderer/appcache/web_application_cache_host_impl.cc
+++ b/content/renderer/appcache/web_application_cache_host_impl.cc
@@ -317,7 +317,8 @@
     return;
   info->creation_time = cache_info_.creation_time.ToDoubleT();
   info->update_time = cache_info_.last_update_time.ToDoubleT();
-  info->total_size = cache_info_.size;
+  info->response_sizes = cache_info_.response_sizes;
+  info->padding_sizes = cache_info_.padding_sizes;
 }
 
 int WebApplicationCacheHostImpl::GetHostID() const {
@@ -337,7 +338,8 @@
 
   WebVector<ResourceInfo> web_resources(resource_infos.size());
   for (size_t i = 0; i < resource_infos.size(); ++i) {
-    web_resources[i].size = resource_infos[i].size;
+    web_resources[i].response_size = resource_infos[i].response_size;
+    web_resources[i].padding_size = resource_infos[i].padding_size;
     web_resources[i].is_master = resource_infos[i].is_master;
     web_resources[i].is_explicit = resource_infos[i].is_explicit;
     web_resources[i].is_manifest = resource_infos[i].is_manifest;
diff --git a/content/renderer/compositor/layer_tree_view.cc b/content/renderer/compositor/layer_tree_view.cc
index d1dd3998..083afd5 100644
--- a/content/renderer/compositor/layer_tree_view.cc
+++ b/content/renderer/compositor/layer_tree_view.cc
@@ -394,11 +394,6 @@
   }
 }
 
-void LayerTreeView::UpdateAllLifecyclePhasesAndCompositeForTesting(
-    bool do_raster) {
-  SynchronouslyComposite(do_raster, nullptr /* swap_promise */);
-}
-
 void LayerTreeView::SynchronouslyComposite(
     bool raster,
     std::unique_ptr<cc::SwapPromise> swap_promise) {
diff --git a/content/renderer/compositor/layer_tree_view.h b/content/renderer/compositor/layer_tree_view.h
index 5ecf3a4..7cf65194 100644
--- a/content/renderer/compositor/layer_tree_view.h
+++ b/content/renderer/compositor/layer_tree_view.h
@@ -135,10 +135,6 @@
   void HeuristicsForGpuRasterizationUpdated(bool matches_heuristics) override;
   void CompositeAndReadbackAsync(
       base::OnceCallback<void(const SkBitmap&)> callback) override;
-  // Synchronously performs the complete set of document lifecycle phases,
-  // including updates to the compositor state, optionally including
-  // rasterization.
-  void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) override;
   std::unique_ptr<cc::ScopedDeferMainFrameUpdate> DeferMainFrameUpdate()
       override;
   void StartDeferringCommits(base::TimeDelta timeout) override;
@@ -206,6 +202,12 @@
 
   const cc::LayerTreeSettings& GetLayerTreeSettings() const;
 
+  // Performs a composite including a main frame and all lifecycle stages,
+  // immediately and synchronously. Should only be called in testing, when
+  // CompositeIsSynchronous() is true.
+  void SynchronouslyComposite(bool raster,
+                              std::unique_ptr<cc::SwapPromise> swap_promise);
+
   // Sets the RenderFrameMetadataObserver, which is sent to the compositor
   // thread for binding.
   void SetRenderFrameObserver(
@@ -229,8 +231,6 @@
   void SetLayerTreeFrameSink(
       std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink);
   bool CompositeIsSynchronous() const;
-  void SynchronouslyComposite(bool raster,
-                              std::unique_ptr<cc::SwapPromise> swap_promise);
 
   LayerTreeViewDelegate* const delegate_;
   const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
diff --git a/content/renderer/compositor/layer_tree_view_unittest.cc b/content/renderer/compositor/layer_tree_view_unittest.cc
index cf7fe8fc..7d58782 100644
--- a/content/renderer/compositor/layer_tree_view_unittest.cc
+++ b/content/renderer/compositor/layer_tree_view_unittest.cc
@@ -423,11 +423,9 @@
           std::move(callback).Run();
         },
         run_loop.QuitClosure(), &swap_time));
-    blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            &LayerTreeView::UpdateAllLifecyclePhasesAndCompositeForTesting,
-            base::Unretained(&layer_tree_view_), true /* do_raster */));
+    layer_tree_view_.SynchronouslyComposite(/*raster=*/true,
+                                            /*swap_promise=*/nullptr);
+    // The swap time notify comes as a posted task.
     run_loop.Run();
     return swap_time;
   }
diff --git a/content/renderer/manifest/manifest_manager.cc b/content/renderer/manifest/manifest_manager.cc
index 07cac06..77b5333b 100644
--- a/content/renderer/manifest/manifest_manager.cc
+++ b/content/renderer/manifest/manifest_manager.cc
@@ -11,13 +11,14 @@
 #include "base/strings/nullable_string16.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/renderer/fetchers/manifest_fetcher.h"
-#include "content/renderer/manifest/manifest_parser.h"
 #include "content/renderer/manifest/manifest_uma_util.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
 #include "third_party/blink/public/platform/web_url_response.h"
 #include "third_party/blink/public/web/web_console_message.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_manifest_parser.h"
 
 namespace content {
 
@@ -150,36 +151,40 @@
   ManifestUmaUtil::FetchSucceeded();
   GURL response_url = response.CurrentRequestUrl();
   base::StringPiece data_piece(data);
-  ManifestParser parser(data_piece, response_url, document_url);
-  parser.Parse();
+
+  blink::WebVector<blink::ManifestError> errors;
+  bool result = blink::WebManifestParser::ParseManifest(
+      data_piece, response_url, document_url, &manifest_, &errors);
 
   manifest_debug_info_ = blink::mojom::ManifestDebugInfo::New();
   manifest_debug_info_->raw_manifest = data;
-  parser.TakeErrors(&manifest_debug_info_->errors);
 
-  for (const auto& error : manifest_debug_info_->errors) {
+  for (const auto& error : errors) {
     blink::WebConsoleMessage message;
-    message.level = error->critical
+    message.level = error.critical
                         ? blink::mojom::ConsoleMessageLevel::kError
                         : blink::mojom::ConsoleMessageLevel::kWarning;
     message.text =
-        blink::WebString::FromUTF8(GetMessagePrefix() + error->message);
+        blink::WebString::FromUTF8(GetMessagePrefix() + error.message);
     message.url =
         render_frame()->GetWebFrame()->GetDocument().ManifestURL().GetString();
-    message.line_number = error->line;
-    message.column_number = error->column;
+    message.line_number = error.line;
+    message.column_number = error.column;
     render_frame()->GetWebFrame()->AddMessageToConsole(message);
+
+    manifest_debug_info_->errors.push_back({base::in_place, error.message,
+                                            error.critical, error.line,
+                                            error.column});
   }
 
   // Having errors while parsing the manifest doesn't mean the manifest parsing
   // failed. Some properties might have been ignored but some others kept.
-  if (parser.failed()) {
+  if (!result) {
     ResolveCallbacks(ResolveStateFailure);
     return;
   }
 
   manifest_url_ = response.CurrentRequestUrl();
-  manifest_ = parser.manifest();
   ResolveCallbacks(ResolveStateSuccess);
 }
 
diff --git a/content/renderer/media/stream/webmediaplayer_ms_compositor.cc b/content/renderer/media/stream/webmediaplayer_ms_compositor.cc
index 47288dbc..9373f9a7 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_compositor.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms_compositor.cc
@@ -10,7 +10,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/message_loop/message_loop_current.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/content/renderer/media/webrtc/media_stream_track_metrics.cc b/content/renderer/media/webrtc/media_stream_track_metrics.cc
index a735811..389edc97 100644
--- a/content/renderer/media/webrtc/media_stream_track_metrics.cc
+++ b/content/renderer/media/webrtc/media_stream_track_metrics.cc
@@ -7,7 +7,7 @@
 #include <inttypes.h>
 #include <string>
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/child/child_thread_impl.h"
 #include "content/public/common/service_names.mojom.h"
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index d67ebe9..9ae8c3cc 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -2210,7 +2210,7 @@
     web_transceivers[i] =
         CreateOrUpdateTransceiver(std::move(transceiver_states[i]));
 
-    // Log a "transcieverAdded" or "transceiverModified" event in
+    // Log a "transceiverAdded" or "transceiverModified" event in
     // chrome://webrtc-internals if new or modified.
     if (peer_connection_tracker_ &&
         (transceiver_is_new || transceiver_was_modified)) {
diff --git a/content/renderer/media/webrtc/transmission_encoding_info_handler.cc b/content/renderer/media/webrtc/transmission_encoding_info_handler.cc
index 4113785..335c57f 100644
--- a/content/renderer/media/webrtc/transmission_encoding_info_handler.cc
+++ b/content/renderer/media/webrtc/transmission_encoding_info_handler.cc
@@ -8,16 +8,19 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/cpu.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/system/sys_info.h"
 #include "content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h"
 #include "content/renderer/media/webrtc/audio_codec_factory.h"
 #include "content/renderer/media/webrtc/video_codec_factory.h"
 #include "content/renderer/render_thread_impl.h"
 #include "third_party/blink/public/platform/modules/media_capabilities/web_media_configuration.h"
+#include "third_party/blink/public/platform/modules/media_capabilities/web_video_configuration.h"
 #include "third_party/blink/public/platform/scoped_web_callbacks.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/webrtc/api/audio_codecs/audio_encoder_factory.h"
@@ -60,32 +63,32 @@
   return nullptr;
 }
 
-// An empirical threshold that roughly estimate if CPU can encode video
-// smoothly. Refer content/renderer/media_recorder/media_recorder_handler.cc
-// for detail.
-const double kNumPixelsPerSecondSmoothnessThreshold = 1280 * 720 * 30.0;
-
-// Returns true if software encoder can smoothly encode the given
-// |configuration|.
-// TODO(crbug.com/941352): provide a better algorithm to estimate software
-// encoder's smoothness capability.
-bool CanSoftwareEncoderRunSmoothly(
-    const blink::WebVideoConfiguration& configuration) {
-  const double pixels_per_second = base::checked_cast<double>(
-      configuration.width * configuration.height * configuration.framerate);
-  return pixels_per_second <= kNumPixelsPerSecondSmoothnessThreshold;
+// Returns true if CPU can encode HD video smoothly.
+// The logic is borrowed from Google Meet (crbug.com/941352).
+bool CanCpuEncodeHdSmoothly() {
+  const int num_processors = base::SysInfo::NumberOfProcessors();
+  if (num_processors >= 4)
+    return true;
+  if (num_processors < 2)
+    return false;
+  return base::CPU().has_sse41();
 }
 
+const unsigned int kHdVideoAreaSize = 1280 * 720;
+
 }  // namespace
 
-// If GetGpuFactories() returns null, CreateWebrtcVideoEncoderFactory() returns
-// software encoder factory only.
+// If GetGpuFactories() returns null, CreateWebrtcVideoEncoderFactory()
+// returns software encoder factory only.
 TransmissionEncodingInfoHandler::TransmissionEncodingInfoHandler()
     : TransmissionEncodingInfoHandler(
-          CreateWebrtcVideoEncoderFactory(GetGpuFactories())) {}
+          CreateWebrtcVideoEncoderFactory(GetGpuFactories()),
+          CanCpuEncodeHdSmoothly()) {}
 
 TransmissionEncodingInfoHandler::TransmissionEncodingInfoHandler(
-    std::unique_ptr<webrtc::VideoEncoderFactory> video_encoder_factory) {
+    std::unique_ptr<webrtc::VideoEncoderFactory> video_encoder_factory,
+    bool cpu_hd_smooth)
+    : cpu_hd_smooth_(cpu_hd_smooth) {
   std::vector<webrtc::SdpVideoFormat> supported_video_formats =
       video_encoder_factory->GetSupportedFormats();
   for (const auto& video_format : supported_video_formats) {
@@ -133,6 +136,13 @@
   return "";
 }
 
+bool TransmissionEncodingInfoHandler::CanCpuEncodeSmoothly(
+    const blink::WebVideoConfiguration& configuration) const {
+  if (configuration.width * configuration.height < kHdVideoAreaSize)
+    return true;
+  return cpu_hd_smooth_;
+}
+
 void TransmissionEncodingInfoHandler::EncodingInfo(
     const blink::WebMediaConfiguration& configuration,
     std::unique_ptr<blink::WebMediaCapabilitiesEncodingInfoCallbacks> callbacks)
@@ -168,8 +178,8 @@
     if (info->supported) {
       const bool is_hardware_accelerated =
           base::ContainsKey(hardware_accelerated_video_codecs_, codec_name);
-      info->smooth = is_hardware_accelerated ||
-                     CanSoftwareEncoderRunSmoothly(video_config);
+      info->smooth =
+          is_hardware_accelerated || CanCpuEncodeSmoothly(video_config);
       info->power_efficient = is_hardware_accelerated;
     } else {
       info->smooth = false;
diff --git a/content/renderer/media/webrtc/transmission_encoding_info_handler.h b/content/renderer/media/webrtc/transmission_encoding_info_handler.h
index dc3a0267..f56a9cde 100644
--- a/content/renderer/media/webrtc/transmission_encoding_info_handler.h
+++ b/content/renderer/media/webrtc/transmission_encoding_info_handler.h
@@ -13,6 +13,10 @@
 #include "content/common/content_export.h"
 #include "third_party/blink/public/platform/web_transmission_encoding_info_handler.h"
 
+namespace blink {
+struct WebVideoConfiguration;
+}  // namespace blink
+
 namespace webrtc {
 class VideoEncoderFactory;
 }  // namespace webrtc
@@ -24,9 +28,11 @@
     : public blink::WebTransmissionEncodingInfoHandler {
  public:
   TransmissionEncodingInfoHandler();
-  // Constructor for unittest to inject VideoEncodeFactory instance.
+  // Constructor for unittest to inject VideoEncodeFactory instance and
+  // |cpu_hd_smooth|.
   explicit TransmissionEncodingInfoHandler(
-      std::unique_ptr<webrtc::VideoEncoderFactory> video_encoder_factory);
+      std::unique_ptr<webrtc::VideoEncoderFactory> video_encoder_factory,
+      bool cpu_hd_smooth);
   ~TransmissionEncodingInfoHandler() override;
 
   // blink::WebTransmissionEncodingInfoHandler implementation.
@@ -41,6 +47,10 @@
   std::string ExtractSupportedCodecFromMimeType(
       const std::string& mime_type) const;
 
+  // True if it can encode |configuration| smoothly via CPU.
+  bool CanCpuEncodeSmoothly(
+      const blink::WebVideoConfiguration& configuration) const;
+
   // List of supported video codecs.
   base::flat_set<std::string> supported_video_codecs_;
   // List of hardware accelerated codecs.
@@ -48,6 +58,9 @@
   // List of supported audio codecs.
   base::flat_set<std::string> supported_audio_codecs_;
 
+  // True if CPU is capable to encode 720p video smoothly.
+  bool cpu_hd_smooth_;
+
   DISALLOW_COPY_AND_ASSIGN(TransmissionEncodingInfoHandler);
 };
 
diff --git a/content/renderer/media/webrtc/transmission_encoding_info_handler_unittest.cc b/content/renderer/media/webrtc/transmission_encoding_info_handler_unittest.cc
index 43f91aa..ed9910b 100644
--- a/content/renderer/media/webrtc/transmission_encoding_info_handler_unittest.cc
+++ b/content/renderer/media/webrtc/transmission_encoding_info_handler_unittest.cc
@@ -181,7 +181,8 @@
   auto video_encoder_factory = std::make_unique<FakeVideoEncoderFactory>();
   video_encoder_factory->AddSupportedFormat(webrtc::SdpVideoFormat("vp8"),
                                             false);
-  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory));
+  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory),
+                                          false);
   VerifyEncodingInfo(handler,
                      ComposeWebMediaConfigurationForVideo("video/vp8", ""),
                      true, false, false);
@@ -215,12 +216,60 @@
   auto video_encoder_factory = std::make_unique<FakeVideoEncoderFactory>();
   video_encoder_factory->AddSupportedFormat(webrtc::SdpVideoFormat("vp8"),
                                             true);
-  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory));
+  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory),
+                                          false);
   VerifyEncodingInfo(handler,
                      ComposeWebMediaConfigurationForVideo("video/vp8", ""),
                      true, true, true);
 }
 
+TEST_F(TransmissionEncodingInfoHandlerTest, SmoothVideoCodecPowerfulCpu) {
+  // Assume no HW vp8 encoder.
+  auto video_encoder_factory = std::make_unique<FakeVideoEncoderFactory>();
+  video_encoder_factory->AddSupportedFormat(webrtc::SdpVideoFormat("vp8"),
+                                            false);
+  // Assume powerful CPU.
+  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory),
+                                          true);
+  VerifyEncodingInfo(handler,
+                     ComposeWebMediaConfigurationForVideo("video/vp8", ""),
+                     true, true, false);
+}
+
+TEST_F(TransmissionEncodingInfoHandlerTest, SmoothVideoCodecVgaResolution) {
+  // Assume no HW vp8 encoder.
+  auto video_encoder_factory = std::make_unique<FakeVideoEncoderFactory>();
+  video_encoder_factory->AddSupportedFormat(webrtc::SdpVideoFormat("vp8"),
+                                            false);
+  // Assume no powerful CPU.
+  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory),
+                                          false);
+
+  // VP8 encoding for 640x480 video.
+  blink::WebMediaConfiguration config(
+      blink::MediaConfigurationType::kTransmission, base::nullopt,
+      ComposeVideoConfiguration("video/vp8", "", 640, 480));
+
+  VerifyEncodingInfo(handler, config, true, true, false);
+}
+
+TEST_F(TransmissionEncodingInfoHandlerTest, SmoothVideoCodecBelowHdResolution) {
+  // Assume no HW vp8 encoder.
+  auto video_encoder_factory = std::make_unique<FakeVideoEncoderFactory>();
+  video_encoder_factory->AddSupportedFormat(webrtc::SdpVideoFormat("vp8"),
+                                            false);
+  // Assume no powerful CPU.
+  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory),
+                                          false);
+
+  // VP8 encoding for 1024x768 video. Note its area size is below 1280x720).
+  blink::WebMediaConfiguration config(
+      blink::MediaConfigurationType::kTransmission, base::nullopt,
+      ComposeVideoConfiguration("video/vp8", "", 1024, 768));
+
+  VerifyEncodingInfo(handler, config, true, true, false);
+}
+
 TEST_F(TransmissionEncodingInfoHandlerTest, AudioAndVideoCodec) {
   // Both video/vp8 and audio/opus are given.
   blink::WebMediaConfiguration config(
@@ -231,7 +280,8 @@
   auto video_encoder_factory = std::make_unique<FakeVideoEncoderFactory>();
   video_encoder_factory->AddSupportedFormat(webrtc::SdpVideoFormat("vp8"),
                                             false);
-  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory));
+  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory),
+                                          false);
   VerifyEncodingInfo(handler, config, true, false, false);
 }
 
@@ -246,8 +296,26 @@
   auto video_encoder_factory = std::make_unique<FakeVideoEncoderFactory>();
   video_encoder_factory->AddSupportedFormat(webrtc::SdpVideoFormat("vp8"),
                                             true);
-  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory));
+  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory),
+                                          false);
   VerifyEncodingInfo(handler, config, true, true, true);
 }
 
+TEST_F(TransmissionEncodingInfoHandlerTest, AudioAndVideoCodecWithPowerfulCpu) {
+  // Both video/vp8 and audio/opus are given.
+  blink::WebMediaConfiguration config(
+      blink::MediaConfigurationType::kTransmission,
+      ComposeAudioConfiguration("audio/opus", ""),
+      ComposeVideoConfiguration("video/vp8", ""));
+
+  // Assume no HW vp8 encoder.
+  auto video_encoder_factory = std::make_unique<FakeVideoEncoderFactory>();
+  video_encoder_factory->AddSupportedFormat(webrtc::SdpVideoFormat("vp8"),
+                                            false);
+  // Assume powerful CPU.
+  TransmissionEncodingInfoHandler handler(std::move(video_encoder_factory),
+                                          true);
+  VerifyEncodingInfo(handler, config, true, true, false);
+}
+
 }  // namespace content
diff --git a/content/renderer/pepper/v8_var_converter.cc b/content/renderer/pepper/v8_var_converter.cc
index d2695a5..55a5dea 100644
--- a/content/renderer/pepper/v8_var_converter.cc
+++ b/content/renderer/pepper/v8_var_converter.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <functional>
 #include <map>
 #include <memory>
 #include <string>
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 29b7ae172..c5e70ba 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -7382,6 +7382,12 @@
   renderer_media_playback_options_ = opts;
 }
 
+void RenderFrameImpl::UpdateAllLifecyclePhasesAndCompositeForTesting() {
+  // This is only called for web tests and WebFrameTestProxy overrides this
+  // method to implement it there.
+  NOTREACHED();
+}
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 void RenderFrameImpl::PepperInstanceCreated(
     PepperPluginInstanceImpl* instance) {
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 4d9a60a..6141582 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -522,6 +522,7 @@
       override;
   void SetRenderFrameMediaPlaybackOptions(
       const RenderFrameMediaPlaybackOptions& opts) override;
+  void UpdateAllLifecyclePhasesAndCompositeForTesting() override;
 
   // blink::mojom::AutoplayConfigurationClient implementation:
   void AddAutoplayFlags(const url::Origin& origin,
@@ -993,6 +994,9 @@
  protected:
   explicit RenderFrameImpl(CreateParams params);
 
+  bool IsLocalRoot() const;
+  const RenderFrameImpl* GetLocalRoot() const;
+
  private:
   friend class RenderFrameImplTest;
   friend class RenderFrameObserver;
@@ -1083,9 +1087,6 @@
   void AddObserver(RenderFrameObserver* observer);
   void RemoveObserver(RenderFrameObserver* observer);
 
-  bool IsLocalRoot() const;
-  const RenderFrameImpl* GetLocalRoot() const;
-
   // Swaps the current frame into the frame tree, replacing the
   // RenderFrameProxy it is associated with.  Return value indicates whether
   // the swap operation succeeded.  This should only be used for provisional
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index b026f79..e60f863 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -76,7 +76,6 @@
 #include "third_party/blink/public/web/web_device_emulation_params.h"
 #include "third_party/blink/public/web/web_document_loader.h"
 #include "third_party/blink/public/web/web_frame_content_dumper.h"
-#include "third_party/blink/public/web/web_global_object_reuse_policy.h"
 #include "third_party/blink/public/web/web_history_commit_type.h"
 #include "third_party/blink/public/web/web_history_item.h"
 #include "third_party/blink/public/web/web_input_method_controller.h"
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index e656cc6..82ef71ec 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -157,6 +157,9 @@
 
   // WebPagePopup implementation.
   blink::WebPoint PositionRelativeToOwner() override { return {}; }
+  blink::WebPagePopupClient* GetClientForTesting() const override {
+    return nullptr;
+  }
 };
 
 class MockWebPagePopup : public StubWebPagePopup {
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_frame.cc b/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
index 8ccc2e9..a416fde 100644
--- a/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
+++ b/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
@@ -71,7 +71,6 @@
       std::move(provider_info->client_request),
       std::move(provider_info->host_ptr_info), std::move(controller_info),
       std::move(fallback_loader_factory));
-  provider->context_->NotifyProviderCreated();
 
   return provider;
 }
diff --git a/content/renderer/service_worker/service_worker_provider_context.cc b/content/renderer/service_worker/service_worker_provider_context.cc
index 2e019077..5e755ce 100644
--- a/content/renderer/service_worker/service_worker_provider_context.cc
+++ b/content/renderer/service_worker/service_worker_provider_context.cc
@@ -262,13 +262,6 @@
   container_host_->OnExecutionReady();
 }
 
-void ServiceWorkerProviderContext::NotifyProviderCreated() {
-  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK_EQ(provider_type(),
-            blink::mojom::ServiceWorkerProviderType::kForWindow);
-  container_host_->OnProviderCreated();
-}
-
 void ServiceWorkerProviderContext::UnregisterWorkerFetchContext(
     blink::mojom::ServiceWorkerWorkerClient* client) {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
diff --git a/content/renderer/service_worker/service_worker_provider_context.h b/content/renderer/service_worker/service_worker_provider_context.h
index 5da7e72d..835b6dd 100644
--- a/content/renderer/service_worker/service_worker_provider_context.h
+++ b/content/renderer/service_worker/service_worker_provider_context.h
@@ -170,11 +170,6 @@
   // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-execution-ready-flag
   void NotifyExecutionReady();
 
-  // Only for service worker window clients. Only called once when the
-  // renderer-side provider has been created successfully to tell the container
-  // host to complete its initialization for this navigation.
-  void NotifyProviderCreated();
-
  private:
   friend class base::DeleteHelper<ServiceWorkerProviderContext>;
   friend class base::RefCountedThreadSafe<ServiceWorkerProviderContext,
diff --git a/content/renderer/service_worker/service_worker_provider_context_unittest.cc b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
index 7165822..0a7bf9f1 100644
--- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -252,7 +252,6 @@
   void Ping(PingCallback callback) override { NOTIMPLEMENTED(); }
   void HintToUpdateServiceWorker() override { NOTIMPLEMENTED(); }
   void OnExecutionReady() override {}
-  void OnProviderCreated() override {}
 
  private:
   mojo::BindingSet<blink::mojom::ServiceWorkerContainerHost> bindings_;
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index 3dcaa83e..40e5a6ab 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -449,7 +449,6 @@
   void Ping(PingCallback callback) override { NOTIMPLEMENTED(); }
   void HintToUpdateServiceWorker() override { NOTIMPLEMENTED(); }
   void OnExecutionReady() override {}
-  void OnProviderCreated() override {}
 
  private:
   int get_controller_service_worker_count_ = 0;
diff --git a/content/shell/renderer/web_test/blink_test_runner.cc b/content/shell/renderer/web_test/blink_test_runner.cc
index ed7c44c..d0cf619 100644
--- a/content/shell/renderer/web_test/blink_test_runner.cc
+++ b/content/shell/renderer/web_test/blink_test_runner.cc
@@ -19,9 +19,9 @@
 #include "base/compiler_specific.h"
 #include "base/debug/debugger.h"
 #include "base/files/file_path.h"
+#include "base/hash/md5.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/content/shell/renderer/web_test/web_test_render_frame_observer.cc b/content/shell/renderer/web_test/web_test_render_frame_observer.cc
index 7b38a549..99381d8 100644
--- a/content/shell/renderer/web_test/web_test_render_frame_observer.cc
+++ b/content/shell/renderer/web_test/web_test_render_frame_observer.cc
@@ -55,22 +55,7 @@
 
 void WebTestRenderFrameObserver::CompositeWithRaster(
     CompositeWithRasterCallback callback) {
-  blink::WebWidget* widget = render_frame()->GetWebFrame()->FrameWidget();
-  blink::WebView* view = render_frame()->GetWebFrame()->View();
-  if (widget) {
-    widget->UpdateAllLifecyclePhasesAndCompositeForTesting(/*do_raster=*/true);
-
-    // The current PagePopup is composited together with the main frame.
-    // TODO(danakj): This means that an OOPIF's popup, which is attached to a
-    // WebView without a main frame, would have no opportunity to execute this
-    // method call.
-    if (render_frame()->IsMainFrame()) {
-      if (blink::WebPagePopup* popup = view->GetPagePopup()) {
-        popup->UpdateAllLifecyclePhasesAndCompositeForTesting(
-            /*do_raster=*/true);
-      }
-    }
-  }
+  render_frame()->UpdateAllLifecyclePhasesAndCompositeForTesting();
   std::move(callback).Run();
 }
 
diff --git a/content/shell/test_runner/test_runner_for_specific_view.cc b/content/shell/test_runner/test_runner_for_specific_view.cc
index 032708a..2a36e84 100644
--- a/content/shell/test_runner/test_runner_for_specific_view.cc
+++ b/content/shell/test_runner/test_runner_for_specific_view.cc
@@ -28,6 +28,7 @@
 #include "content/shell/test_runner/test_runner.h"
 #include "content/shell/test_runner/web_test_delegate.h"
 #include "content/shell/test_runner/web_view_test_proxy.h"
+#include "content/shell/test_runner/web_widget_test_proxy.h"
 #include "gin/arguments.h"
 #include "gin/array_buffer.h"
 #include "gin/handle.h"
@@ -204,16 +205,14 @@
 void TestRunnerForSpecificView::UpdateAllLifecyclePhasesAndComposite() {
   // Note, this is executed synchronously. Wrap in setTimeout() to run
   // asynchronously.
-  blink::WebWidget* widget =
-      web_view()->MainFrame()->ToWebLocalFrame()->FrameWidget();
-  widget->UpdateAllLifecyclePhasesAndCompositeForTesting(/* raster = */ true);
+  main_frame_render_widget()->SynchronouslyComposite(/*raster=*/true);
 }
 
 void TestRunnerForSpecificView::UpdateAllLifecyclePhasesAndCompositeThen(
     v8::Local<v8::Function> callback) {
   // Note, this is executed synchronously. Wrap in setTimeout() to run
   // asynchronously.
-  TestRunnerForSpecificView::UpdateAllLifecyclePhasesAndComposite();
+  UpdateAllLifecyclePhasesAndComposite();
   InvokeV8Callback(
       v8::UniquePersistent<v8::Function>(blink::MainThreadIsolate(), callback));
 }
@@ -678,8 +677,8 @@
   return web_view()->MainFrame()->ToWebLocalFrame();
 }
 
-content::RenderWidget* TestRunnerForSpecificView::main_frame_render_widget() {
-  return web_view_test_proxy_->GetWidget();
+WebWidgetTestProxy* TestRunnerForSpecificView::main_frame_render_widget() {
+  return static_cast<WebWidgetTestProxy*>(web_view_test_proxy_->GetWidget());
 }
 
 blink::WebView* TestRunnerForSpecificView::web_view() {
diff --git a/content/shell/test_runner/test_runner_for_specific_view.h b/content/shell/test_runner/test_runner_for_specific_view.h
index ea0e034..ce28d66 100644
--- a/content/shell/test_runner/test_runner_for_specific_view.h
+++ b/content/shell/test_runner/test_runner_for_specific_view.h
@@ -25,17 +25,13 @@
 class WebView;
 }
 
-namespace content {
-class RenderWidget;
-}  // namespace content
-
 namespace gin {
 class Arguments;
 }
 
 namespace test_runner {
-
 class WebTestDelegate;
+class WebWidgetTestProxy;
 class WebViewTestProxy;
 
 // TestRunnerForSpecificView implements part of |testRunner| javascript bindings
@@ -223,7 +219,7 @@
   blink::WebLocalFrame* GetLocalMainFrame();
 
   // Helpers for accessing pointers exposed by |web_view_test_proxy_|.
-  content::RenderWidget* main_frame_render_widget();
+  WebWidgetTestProxy* main_frame_render_widget();
   blink::WebView* web_view();
   WebTestDelegate* delegate();
 
diff --git a/content/shell/test_runner/web_frame_test_proxy.cc b/content/shell/test_runner/web_frame_test_proxy.cc
index 965c850..1ce1b59 100644
--- a/content/shell/test_runner/web_frame_test_proxy.cc
+++ b/content/shell/test_runner/web_frame_test_proxy.cc
@@ -128,6 +128,13 @@
   new TestRenderFrameObserver(this, view_proxy_for_frame);  // deletes itself.
 }
 
+void WebFrameTestProxy::UpdateAllLifecyclePhasesAndCompositeForTesting() {
+  if (!IsLocalRoot())
+    return;
+  auto* widget = static_cast<WebWidgetTestProxy*>(GetLocalRootRenderWidget());
+  widget->SynchronouslyComposite(/*do_raster=*/true);
+}
+
 // WebLocalFrameClient implementation.
 blink::WebPlugin* WebFrameTestProxy::CreatePlugin(
     const blink::WebPluginParams& params) {
diff --git a/content/shell/test_runner/web_frame_test_proxy.h b/content/shell/test_runner/web_frame_test_proxy.h
index 36e8055..9a03b7b 100644
--- a/content/shell/test_runner/web_frame_test_proxy.h
+++ b/content/shell/test_runner/web_frame_test_proxy.h
@@ -38,6 +38,9 @@
   void Initialize(WebTestInterfaces* interfaces,
                   content::RenderViewImpl* render_view_for_frame);
 
+  // RenderFrameImpl overrides.
+  void UpdateAllLifecyclePhasesAndCompositeForTesting() override;
+
   // WebLocalFrameClient implementation.
   blink::WebPlugin* CreatePlugin(const blink::WebPluginParams& params) override;
   void DidAddMessageToConsole(const blink::WebConsoleMessage& message,
diff --git a/content/shell/test_runner/web_widget_test_proxy.cc b/content/shell/test_runner/web_widget_test_proxy.cc
index d2774f9f..d51a530 100644
--- a/content/shell/test_runner/web_widget_test_proxy.cc
+++ b/content/shell/test_runner/web_widget_test_proxy.cc
@@ -19,6 +19,8 @@
 
 namespace test_runner {
 
+WebWidgetTestProxy::~WebWidgetTestProxy() = default;
+
 void WebWidgetTestProxy::ScheduleAnimation() {
   if (!GetTestRunner()->TestIsRunning())
     return;
@@ -108,7 +110,26 @@
   widget_input_handler_manager()->InvokeInputProcessedCallback();
 }
 
-WebWidgetTestProxy::~WebWidgetTestProxy() = default;
+void WebWidgetTestProxy::SynchronouslyComposite(bool do_raster) {
+  layer_tree_view()->SynchronouslyComposite(do_raster,
+                                            /*swap_promise=*/nullptr);
+
+  // If the RenderWidget is for the main frame, we also composite the current
+  // PagePopup afterward.
+  //
+  // TODO(danakj): This means that an OOPIF's popup, which is attached to a
+  // WebView without a main frame, would have no opportunity to execute this
+  // method call.
+  if (delegate()) {
+    blink::WebView* view = GetWebViewTestProxy()->webview();
+    if (blink::WebPagePopup* popup = view->GetPagePopup()) {
+      auto* popup_render_widget =
+          static_cast<RenderWidget*>(popup->GetClientForTesting());
+      popup_render_widget->layer_tree_view()->SynchronouslyComposite(
+          do_raster, /*swap_promise=*/nullptr);
+    }
+  }
+}
 
 TestRunnerForSpecificView* WebWidgetTestProxy::GetViewTestRunner() {
   return GetWebViewTestProxy()->view_test_runner();
@@ -140,25 +161,7 @@
   animation_scheduled_ = false;
   CHECK(GetTestRunner());
   bool animation_requires_raster = GetTestRunner()->animation_requires_raster();
-  blink::WebWidget* web_widget = GetWebWidget();
-  CHECK(web_widget);
-  web_widget->UpdateAllLifecyclePhasesAndCompositeForTesting(
-      animation_requires_raster);
-
-  // If this RenderWidget is attached to a RenderView, we composite the
-  // current PagePopup with the widget.
-  //
-  // TODO(danakj): This means that an OOPIF's popup, which is attached to a
-  // WebView without a main frame, would have no opportunity to execute this
-  // method call.
-  if (delegate()) {
-    blink::WebView* view = GetWebViewTestProxy()->webview();
-    CHECK(view);
-    if (blink::WebPagePopup* popup = view->GetPagePopup()) {
-      popup->UpdateAllLifecyclePhasesAndCompositeForTesting(
-          animation_requires_raster);
-    }
-  }
+  SynchronouslyComposite(animation_requires_raster);
 }
 
 }  // namespace test_runner
diff --git a/content/shell/test_runner/web_widget_test_proxy.h b/content/shell/test_runner/web_widget_test_proxy.h
index df4edea..9fef1da8 100644
--- a/content/shell/test_runner/web_widget_test_proxy.h
+++ b/content/shell/test_runner/web_widget_test_proxy.h
@@ -82,6 +82,8 @@
 
   void EndSyntheticGestures();
 
+  void SynchronouslyComposite(bool do_raster);
+
  private:
   // RenderWidget does not have a public destructor.
   ~WebWidgetTestProxy() override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 15968c4..e89aa32 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1362,9 +1362,12 @@
   sources = [
     "../browser/accessibility/browser_accessibility_mac_unittest.mm",
     "../browser/accessibility/browser_accessibility_manager_unittest.cc",
+    "../browser/accessibility/browser_accessibility_manager_win_unittest.cc",
     "../browser/accessibility/browser_accessibility_unittest.cc",
     "../browser/accessibility/browser_accessibility_win_unittest.cc",
     "../browser/accessibility/one_shot_accessibility_tree_search_unittest.cc",
+    "../browser/accessibility/test_browser_accessibility_delegate.cc",
+    "../browser/accessibility/test_browser_accessibility_delegate.h",
     "../browser/appcache/appcache_database_unittest.cc",
     "../browser/appcache/appcache_disk_cache_unittest.cc",
     "../browser/appcache/appcache_group_unittest.cc",
@@ -1789,7 +1792,6 @@
     "../renderer/loader/web_data_consumer_handle_impl_unittest.cc",
     "../renderer/loader/web_url_loader_impl_unittest.cc",
     "../renderer/low_memory_mode_controller_unittest.cc",
-    "../renderer/manifest/manifest_parser_unittest.cc",
     "../renderer/media/audio/audio_output_ipc_factory_unittest.cc",
     "../renderer/media/audio/audio_renderer_mixer_manager_unittest.cc",
     "../renderer/media/audio/audio_renderer_sink_cache_unittest.cc",
@@ -2033,6 +2035,7 @@
     "//third_party/webrtc_overrides:task_queue_factory",
     "//third_party/widevine/cdm:headers",
     "//ui/accessibility",
+    "//ui/accessibility:test_support",
     "//ui/base:test_support",
     "//ui/base/clipboard:clipboard_test_support",
     "//ui/base/ime",
diff --git a/content/test/accessibility_browser_test_utils.cc b/content/test/accessibility_browser_test_utils.cc
index c853e91..27963d3 100644
--- a/content/test/accessibility_browser_test_utils.cc
+++ b/content/test/accessibility_browser_test_utils.cc
@@ -114,10 +114,11 @@
 
 const ui::AXTree& AccessibilityNotificationWaiter::GetAXTree() const {
   static base::NoDestructor<ui::AXTree> empty_tree;
-  RenderFrameHostImpl* main_frame =
-      static_cast<RenderFrameHostImpl*>(web_contents()->GetMainFrame());
-  const ui::AXTree* tree = main_frame->GetAXTreeForTesting();
-  return tree ? *tree : *empty_tree;
+  WebContentsImpl* web_contents_impl =
+      static_cast<WebContentsImpl*>(web_contents());
+  BrowserAccessibilityManager* manager =
+      web_contents_impl->GetRootBrowserAccessibilityManager();
+  return manager && manager->ax_tree() ? *manager->ax_tree() : *empty_tree;
 }
 
 void AccessibilityNotificationWaiter::BindOnAccessibilityEvent(
diff --git a/content/test/data/accessibility/event/aria-required-changed-expected-uia-win.txt b/content/test/data/accessibility/event/aria-required-changed-expected-uia-win.txt
new file mode 100644
index 0000000..f6dfdb36
--- /dev/null
+++ b/content/test/data/accessibility/event/aria-required-changed-expected-uia-win.txt
@@ -0,0 +1,2 @@
+IsRequiredForForm changed on role=checkbox
+IsRequiredForForm changed on role=radio
diff --git a/content/test/data/accessibility/event/aria-required-changed-expected-win.txt b/content/test/data/accessibility/event/aria-required-changed-expected-win.txt
index 444de8e4..b31a7d8 100644
--- a/content/test/data/accessibility/event/aria-required-changed-expected-win.txt
+++ b/content/test/data/accessibility/event/aria-required-changed-expected-win.txt
@@ -1,2 +1,2 @@
-EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_CHECKBUTTON IA2_STATE_CHECKABLE,IA2_STATE_REQUIRED
-EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_RADIOBUTTON IA2_STATE_CHECKABLE
\ No newline at end of file
+EVENT_OBJECT_STATECHANGE on <div> role=ROLE_SYSTEM_CHECKBUTTON IA2_STATE_CHECKABLE,IA2_STATE_REQUIRED
+EVENT_OBJECT_STATECHANGE on <div> role=ROLE_SYSTEM_RADIOBUTTON IA2_STATE_CHECKABLE PosInSet=1 SetSize=1
diff --git a/content/test/data/accessibility/event/form-required-changed-expected-mac.txt b/content/test/data/accessibility/event/form-required-changed-expected-mac.txt
index 9311208..ec2bbaf2 100644
--- a/content/test/data/accessibility/event/form-required-changed-expected-mac.txt
+++ b/content/test/data/accessibility/event/form-required-changed-expected-mac.txt
@@ -1 +1,2 @@
-AXInvalidStatusChanged on AXCheckBox
\ No newline at end of file
+AXInvalidStatusChanged on AXCheckBox
+AXValueChanged on AXRadioButton
\ No newline at end of file
diff --git a/content/test/data/accessibility/event/form-required-changed-expected-uia-win.txt b/content/test/data/accessibility/event/form-required-changed-expected-uia-win.txt
new file mode 100644
index 0000000..f6dfdb36
--- /dev/null
+++ b/content/test/data/accessibility/event/form-required-changed-expected-uia-win.txt
@@ -0,0 +1,2 @@
+IsRequiredForForm changed on role=checkbox
+IsRequiredForForm changed on role=radio
diff --git a/content/test/data/accessibility/event/form-required-changed-expected-win.txt b/content/test/data/accessibility/event/form-required-changed-expected-win.txt
index 4676dfc..7d93416 100644
--- a/content/test/data/accessibility/event/form-required-changed-expected-win.txt
+++ b/content/test/data/accessibility/event/form-required-changed-expected-win.txt
@@ -1,2 +1,2 @@
-EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_CHECKBUTTON FOCUSABLE IA2_STATE_CHECKABLE,IA2_STATE_INVALID_ENTRY,IA2_STATE_REQUIRED
-EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_RADIOBUTTON FOCUSABLE IA2_STATE_CHECKABLE
\ No newline at end of file
+EVENT_OBJECT_STATECHANGE on <input> role=ROLE_SYSTEM_CHECKBUTTON FOCUSABLE IA2_STATE_CHECKABLE,IA2_STATE_INVALID_ENTRY,IA2_STATE_REQUIRED
+EVENT_OBJECT_STATECHANGE on <input> role=ROLE_SYSTEM_RADIOBUTTON CHECKED,FOCUSABLE IA2_STATE_CHECKABLE PosInSet=1 SetSize=1
diff --git a/content/test/data/accessibility/event/form-required-changed.html b/content/test/data/accessibility/event/form-required-changed.html
index 3b9b322..31ca159c 100644
--- a/content/test/data/accessibility/event/form-required-changed.html
+++ b/content/test/data/accessibility/event/form-required-changed.html
@@ -2,6 +2,8 @@
 <!--
 @MAC-ALLOW:AXRequired*
 @WIN-ALLOW:IA2_STATE_REQUIRED
+@UIA-WIN-DENY:*
+@UIA-WIN-ALLOW:IsRequiredForForm*
 -->
 <form>
   <input type="checkbox">
@@ -11,5 +13,9 @@
   function go() {
     document.querySelector('input[type=checkbox]').required = true;
     document.querySelector('input[type=radio]').required = false;
+    // Additional event needs to be fired here to prevent this test from
+    // time out for windows. We should fix it.
+    // http://crbug.com/719030
+    document.querySelector('input[type=radio]').click();
   }
 </script>
diff --git a/content/test/gpu/gpu_tests/context_lost_expectations.py b/content/test/gpu/gpu_tests/context_lost_expectations.py
deleted file mode 100644
index 2f260711..0000000
--- a/content/test/gpu/gpu_tests/context_lost_expectations.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from gpu_tests.gpu_test_expectations import GpuTestExpectations
-
-# See the GpuTestExpectations class for documentation.
-
-class ContextLostExpectations(GpuTestExpectations):
-  def __init__(self, is_asan=False):
-    super(ContextLostExpectations, self).__init__(is_asan=is_asan)
-
-  def SetExpectations(self):
-    # Sample Usage:
-    # self.Fail('ContextLost_WebGLContextLostFromGPUProcessExit',
-    #     ['mac', 'amd', ('nvidia', 0x1234)], bug=123)
-
-    # AMD Radeon 6450
-    self.Fail('ContextLost_WebGLContextLostFromGPUProcessExit',
-        ['linux', ('amd', 0x6779)], bug=479975)
-
-    # Win7 bots
-    self.Flaky('ContextLost_WebGLContextLostFromGPUProcessExit',
-               ['win7'], bug=603329)
-
-    # Win8 Release and Debug NVIDIA bots.
-    self.Skip('ContextLost_WebGLContextLostFromSelectElement',
-              ['win8', 'nvidia'], bug=524808)
-
-    # Flakily timing out on Win x64 Debug bot.
-    # Unfortunately we can't identify this separately from the 32-bit bots.
-    # Also unfortunately, the flaky retry mechanism doesn't work well in
-    # this harness if the test times out. Skip it on this configuration for
-    # now.
-    self.Skip('ContextLost_WebGLContextLostFromQuantity',
-              ['win', 'debug'], bug=628697)
-
-    # Flaky on Mac 10.7 and 10.8 resulting in crashes during browser
-    # startup, so skip this test in those configurations.
-    self.Skip('ContextLost_WebGLContextLostFromSelectElement',
-              ['mountainlion', 'debug'], bug=497411)
-    self.Skip('ContextLost_WebGLContextLostFromSelectElement',
-              ['lion', 'debug'], bug=498149)
-
-    # Too difficult to make this test work on Mac and Android for now.
-    # Disabling GLES3 support at the GL bindings level doesn't work
-    # there yet.
-    self.Skip('ContextLost_WebGL2Blocked', ['mac'], bug=923134)
-    self.Skip('ContextLost_WebGL2Blocked', ['android'], bug=923134)
-
-    # 'Browser must support tab control' raised on Android
-    self.Skip('GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash',
-              ['android'], bug=609629)
-    self.Skip('ContextLost_WebGLContextLostFromGPUProcessExit',
-              ['android'], bug=609629)
-    self.Skip('ContextLost_WebGLContextLostInHiddenTab',
-              ['android'], bug=609629)
-
-    # Flaking on Nexus 5X
-    self.Flaky('ContextLost_WebGLUnblockedAfterUserInitiatedReload',
-              ['android', ('qualcomm', 'Adreno (TM) 418')], bug=879423)
-    self.Fail('ContextLost_WorkerRAFAfterGPUCrash',
-              ['android'], bug=880078)
-    self.Fail('ContextLost_WorkerRAFAfterGPUCrash_OOPD',
-              ['android'], bug=880078)
-
-    # Nexus 6
-    # The Nexus 6 times out on these tests while waiting for the JS to complete
-    self.Fail('ContextLost_WebGLContextLostFromLoseContextExtension',
-              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=611906)
-    self.Fail('ContextLost_WebGLContextLostFromQuantity',
-              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=611906)
diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py
index 73369889..a29d1c981 100644
--- a/content/test/gpu/gpu_tests/context_lost_integration_test.py
+++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py
@@ -7,7 +7,6 @@
 import time
 
 from gpu_tests import gpu_integration_test
-from gpu_tests import context_lost_expectations
 from gpu_tests import path_util
 
 from telemetry.core import exceptions
@@ -63,7 +62,7 @@
     super(ContextLostIntegrationTest, cls).AddCommandlineArgs(parser)
     parser.add_option('--is-asan',
         help='Indicates whether currently running an ASAN build',
-        action='store_true')
+        action='store_true', default=False)
 
   @staticmethod
   def _AddDefaultArgs(browser_args):
@@ -110,8 +109,7 @@
 
   @classmethod
   def _CreateExpectations(cls):
-    return context_lost_expectations.ContextLostExpectations(
-      is_asan=cls._is_asan)
+    raise NotImplementedError
 
   @classmethod
   def SetUpProcess(cls):
@@ -363,6 +361,21 @@
     # blacklisted should not cause the GPU process to crash.
     self._CheckCrashCount(tab, 0)
 
+  @classmethod
+  def GetPlatformTags(cls, browser):
+    tags = super(ContextLostIntegrationTest, cls).GetPlatformTags(browser)
+    tags.extend(
+        [['no-asan', 'asan'][cls._is_asan]])
+    return tags
+
+  @classmethod
+  def ExpectationsFiles(cls):
+    return [
+        os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                     'test_expectations',
+                     'context_lost_expectations.txt')]
+
+
 def load_tests(loader, tests, pattern):
   del loader, tests, pattern  # Unused.
   return gpu_integration_test.LoadAllTestsInModule(sys.modules[__name__])
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py
index 10e87bac..67298a5 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -382,7 +382,8 @@
     # an exception.
     if not cls.ExpectationsFiles():
       return []
-    with possible_browser.BrowserSession(finder_options) as browser:
+    with possible_browser.BrowserSession(
+        finder_options.browser_options) as browser:
       return cls.GetPlatformTags(browser)
 
   @classmethod
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py b/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py
index 45fa00a..4c616697 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py
@@ -16,8 +16,9 @@
 from telemetry.testing import browser_test_runner
 from telemetry.internal.platform import system_info
 
-from gpu_tests import path_util
+from gpu_tests import context_lost_integration_test
 from gpu_tests import gpu_integration_test
+from gpu_tests import path_util
 from gpu_tests import webgl_conformance_integration_test
 
 path_util.AddDirToPathIfNeeded(path_util.GetChromiumSrcDir(), 'tools', 'perf')
@@ -78,6 +79,7 @@
     self.is_asan = is_asan
     self.webgl_conformance_version = webgl_version
     self.webgl2_only = False
+    self.browser_options = []
 
 
 class MockAbstractGpuTestClass(gpu_integration_test.GpuIntegrationTest):
@@ -136,26 +138,52 @@
     self._test_state = {}
     self._test_result = {}
 
-  def testTestNamePrefixGenerationInRunGpuIntegrationTests(self):
+  def _RunGpuIntegrationTests(self, test_name, extra_args=None):
+    extra_args = extra_args or []
     temp_file = tempfile.NamedTemporaryFile(delete=False)
     temp_file.close()
     try:
       sys.argv = [
-          run_gpu_integration_test.__file__, 'simple_integration_unittest',
-          '--write-full-results-to=%s' % temp_file.name]
+          run_gpu_integration_test.__file__,
+          test_name,
+          '--write-full-results-to=%s' % temp_file.name,
+          ] + extra_args
       gpu_project_config.CONFIG = chromium_config.ChromiumConfig(
           top_level_dir=path_util.GetGpuTestDir(),
           benchmark_dirs=[
               os.path.join(path_util.GetGpuTestDir(), 'unittest_data')])
       run_gpu_integration_test.main()
       with open(temp_file.name) as f:
-        results = json.load(f)
-      self.assertIn('expected_failure', results['tests'])
-      self.assertEqual(results['test_name_prefix'],
-                       'unittest_data.integration_tests.SimpleTest.')
+        self._test_result = json.load(f)
     finally:
       temp_file.close()
 
+  def testOverrideDefaultRetryArgumentsinRunGpuIntegrationTests(self):
+    self._RunGpuIntegrationTests(
+        'run_tests_with_expectations_files', ['--retry-limit=1'])
+    self.assertEqual(
+        self._test_result['tests']['unexpected_test_failure']['actual'],
+        'FAIL FAIL')
+    self.assertEqual(
+        self._test_result['test_name_prefix'],
+          'unittest_data.integration_tests.RunTestsWithExpectationsFiles.')
+
+  def testDefaultRetryArgumentsinRunGpuIntegrationTests(self):
+    self._RunGpuIntegrationTests('run_tests_with_expectations_files')
+    self.assertEqual(
+        self._test_result['tests']['expected_flaky']['actual'],
+        'FAIL FAIL FAIL')
+    self.assertEqual(
+        self._test_result['test_name_prefix'],
+        'unittest_data.integration_tests.RunTestsWithExpectationsFiles.')
+
+  def testTestNamePrefixGenerationInRunGpuIntegrationTests(self):
+    self._RunGpuIntegrationTests('simple_integration_unittest')
+    self.assertIn('expected_failure', self._test_result['tests'])
+    self.assertEqual(
+        self._test_result['test_name_prefix'],
+        'unittest_data.integration_tests.SimpleTest.')
+
   def testWithoutExpectationsFilesGenerateTagsReturnsEmptyList(self):
     # we need to make sure that GenerateTags() returns an empty list if
     # there are no expectations files returned from ExpectationsFiles() or
@@ -165,9 +193,34 @@
     self.assertFalse(MockTestCaseWithoutExpectationsFile.GenerateTags(
         args, possible_browser))
 
+  def _TestTagGenerationForMockPlatform(self, test_class, args):
+    tag_set = _generateNvidiaExampleTagsForTestClassAndArgs(
+        webgl_conformance_integration_test.WebGLConformanceIntegrationTest,
+        args)
+    self.assertTrue(
+        set(['win', 'win10', 'd3d9', 'release',
+             'nvidia', 'nvidia-0x1cb3', 'no-passthrough']).issubset(tag_set))
+    return tag_set
+
+  def testGenerateContextLostExampleTagsForAsan(self):
+    args = MockArgs(is_asan=True)
+    tag_set = self._TestTagGenerationForMockPlatform(
+        context_lost_integration_test.ContextLostIntegrationTest,
+        args)
+    self.assertIn('asan', tag_set)
+    self.assertNotIn('no-asan', tag_set)
+
+  def testGenerateContextLostExampleTagsForNoAsan(self):
+    args = MockArgs()
+    tag_set = self._TestTagGenerationForMockPlatform(
+        context_lost_integration_test.ContextLostIntegrationTest,
+        args)
+    self.assertIn('no-asan', tag_set)
+    self.assertNotIn('asan', tag_set)
+
   def testGenerateWebglConformanceExampleTagsForWebglVersion1andAsan(self):
     args = MockArgs(is_asan=True, webgl_version='1.0.0')
-    tag_set = _generateNvidiaExampleTagsForTestClassAndArgs(
+    tag_set = self._TestTagGenerationForMockPlatform(
         webgl_conformance_integration_test.WebGLConformanceIntegrationTest,
         args)
     self.assertTrue(set(['asan', 'webgl-version-1']).issubset(tag_set))
@@ -175,7 +228,7 @@
 
   def testGenerateWebglConformanceExampleTagsForWebglVersion2andNoAsan(self):
     args = MockArgs(is_asan=False, webgl_version='2.0.0')
-    tag_set = _generateNvidiaExampleTagsForTestClassAndArgs(
+    tag_set = self._TestTagGenerationForMockPlatform(
         webgl_conformance_integration_test.WebGLConformanceIntegrationTest,
         args)
     self.assertTrue(set(['no-asan', 'webgl-version-2']) .issubset(tag_set))
@@ -267,44 +320,38 @@
   def _RunTestsWithExpectationsFiles(self):
     self._RunIntegrationTest(
       'run_tests_with_expectations_files',
-      [('unittest_data.integration_tests'
-        '.RunTestsWithExpectationsFiles.unexpected_test_failure')],
-      [('unittest_data.integration_tests'
-        '.RunTestsWithExpectationsFiles.expected_failure'),
-       ('unittest_data.integration_tests'
-        '.RunTestsWithExpectationsFiles.expected_flaky')],
-      [('unittest_data.integration_tests'
-        '.RunTestsWithExpectationsFiles.expected_skip')],
-      ['--retry-limit=3', '--retry-only-retry-on-failure-tests'])
+      [('unexpected_test_failure')],
+      [('expected_failure'),
+       ('expected_flaky')],
+      [('expected_skip')],
+      ['--retry-limit=3', '--retry-only-retry-on-failure-tests',
+       ('--test-name-prefix=unittest_data.integration_tests.'
+        'RunTestsWithExpectationsFiles.')])
 
   def testUseTestExpectationsFileToHandleExpectedSkip(self):
     self._RunTestsWithExpectationsFiles()
-    results = (self._test_result['tests']['unittest_data']['integration_tests']
-               ['RunTestsWithExpectationsFiles']['expected_skip'])
+    results = self._test_result['tests']['expected_skip']
     self.assertEqual(results['expected'], 'SKIP')
     self.assertEqual(results['actual'], 'SKIP')
     self.assertNotIn('is_regression', results)
 
   def testUseTestExpectationsFileToHandleUnexpectedTestFailure(self):
     self._RunTestsWithExpectationsFiles()
-    results = (self._test_result['tests']['unittest_data']['integration_tests']
-               ['RunTestsWithExpectationsFiles']['unexpected_test_failure'])
+    results = self._test_result['tests']['unexpected_test_failure']
     self.assertEqual(results['expected'], 'PASS')
     self.assertEqual(results['actual'], 'FAIL')
     self.assertIn('is_regression', results)
 
   def testUseTestExpectationsFileToHandleExpectedFailure(self):
     self._RunTestsWithExpectationsFiles()
-    results = (self._test_result['tests']['unittest_data']['integration_tests']
-               ['RunTestsWithExpectationsFiles']['expected_failure'])
+    results = self._test_result['tests']['expected_failure']
     self.assertEqual(results['expected'], 'FAIL')
     self.assertEqual(results['actual'], 'FAIL')
     self.assertNotIn('is_regression', results)
 
   def testUseTestExpectationsFileToHandleExpectedFlakyTest(self):
     self._RunTestsWithExpectationsFiles()
-    results = (self._test_result['tests']['unittest_data']['integration_tests']
-               ['RunTestsWithExpectationsFiles']['expected_flaky'])
+    results = self._test_result['tests']['expected_flaky']
     self.assertEqual(results['expected'], 'PASS')
     self.assertEqual(results['actual'], 'FAIL FAIL FAIL PASS')
     self.assertNotIn('is_regression', results)
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index 0c8f85b..31bd718 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -44,6 +44,39 @@
     self.Skip('Pixel_Canvas2DRedBox_NoGpuProcess', ['android', 'chromeos'])
     self.Skip('Pixel_CSS3DBlueBox_NoGpuProcess', ['android', 'chromeos'])
 
+    # Skip tests on Android WebView that requires embedding viz clients. This
+    # includes offscreen canvas and other features. crbug.com/805739 tracks
+    # making this work.
+    self.Skip('Pixel_OffscreenCanvas2DResizeOnWorker',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_OffscreenCanvasAccelerated2D',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_OffscreenCanvasAccelerated2DWorker',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_OffscreenCanvasTransferAfterStyleResize',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_OffscreenCanvasTransferBeforeStyleResize',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_OffscreenCanvasWebGLDefault',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_OffscreenCanvasWebGLDefaultWorker',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_OffscreenCanvasWebGLPaintAfterResize',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_OffscreenCanvasWebglResizeOnWorker',
+              ['android-webview-instrumentation'], bug=805739)
+    self.Skip('Pixel_CanvasLowLatencyWebGL',
+              ['android-webview-instrumentation'], bug=805739)
+    # Skip test that kills GPU process since Android Webview only supports
+    # in-process GPU.
+    # Uncomment this when crbug.com/575305 is fixed and conflicting
+    # expectation below is removed.
+    # self.Skip('Pixel_WebGLSadCanvas', ['android-webview-instrumentation'])
+    # Uncomment this when crbug.com/925744 is fixed and conflicting
+    # expectation below is removed.
+    # self.SKip('Pixel_Video_Context_Loss_VP9',
+    #           ['android-webview-instrumentation'])
+
     self.Fail('Pixel_ScissorTestWithPreserveDrawingBuffer',
         ['android'], bug=521588)
 
@@ -99,7 +132,7 @@
     # TODO(kbr): temporary suppression for new test.
     self.Flaky('Pixel_WebGLSadCanvas', ['linux', 'win'], bug=575305)
     self.Fail('Pixel_WebGLSadCanvas', ['mac'], bug=872423)
-    self.Fail('Pixel_WebGLSadCanvas', ['android'], bug=575305)
+    self.Skip('Pixel_WebGLSadCanvas', ['android'], bug=575305)
 
     self.Fail('Pixel_CanvasLowLatencyWebGL', ['android', 'nvidia'], bug=868596)
     self.Fail('Pixel_OffscreenCanvasWebGLPaintAfterResize',
@@ -115,7 +148,7 @@
 
     # Flakes on Nexus 5X.
     self.Flaky('Pixel_BackgroundImage',
-        ['android', ('qualcomm', 'Adreno (TM) 418')], bug=883500)
+        ['android-chromium', ('qualcomm', 'Adreno (TM) 418')], bug=883500)
 
     # We do not have software H.264 decoding on Android, so it can't survive a
     # context loss which results in hardware decoder loss.
@@ -145,7 +178,7 @@
     self.Fail('Pixel_Video_MP4_FourColors_Rot_270', ['android'], bug=925744)
     self.Fail('Pixel_Video_MP4_FourColors_Rot_90', ['android'], bug=925744)
     self.Fail('Pixel_Video_VP9', ['android'], bug=925744)
-    self.Fail('Pixel_Video_Context_Loss_VP9', ['android'], bug=925744)
+    self.Skip('Pixel_Video_Context_Loss_VP9', ['android'], bug=925744)
 
     # Skip on platforms where DXVA vs D3D11 decoder doesn't matter.
     self.Skip('Pixel_Video_MP4_DXVA', ['linux', 'android', 'mac', 'chromeos'],
@@ -156,3 +189,46 @@
     # Complex overlays test is flaky on Nvidia probably due to its small size.
     self.Flaky('Pixel_DirectComposition_ComplexOverlays', ['win', 'nvidia'],
                bug=929425)
+
+    # Mark as fail all pixel tests on Android WebView before refimgs are
+    # generated
+    self.Fail('Pixel_Canvas2DUntagged', ['android-webview-instrumentation'],
+        bug=907935)
+    self.Fail('Pixel_GpuRasterization_BlueBox',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_GpuRasterization_ConcavePaths',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_OffscreenCanvasTransferToImageBitmap',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_OffscreenCanvasTransferToImageBitmapWorker',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_RepeatedWebGLTo2D', ['android-webview-instrumentation'],
+        bug=907935)
+    self.Fail('Pixel_WebGL_PremultipliedAlpha_False',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_2DCanvasWebGL', ['android-webview-instrumentation'],
+        bug=907935)
+    # Uncomment this when crbug.com/927107 is fixed and conflicting expectation
+    # above is removed.
+    # self.Fail('Pixel_CSS3DBlueBox', ['android-webview-instrumentation'],
+    #     bug=907935)
+    self.Fail('Pixel_Canvas2DRedBox', ['android-webview-instrumentation'],
+        bug=907935)
+    self.Fail('Pixel_CanvasDisplayLinearRGBAccelerated2D',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_CanvasLowLatency2D', ['android-webview-instrumentation'],
+        bug=907935)
+    self.Fail('Pixel_CanvasDisplayLinearRGBUnaccelerated2DGPUCompositing',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_WebGLGreenTriangle_AA_Alpha',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_WebGLGreenTriangle_AA_NoAlpha',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_WebGLGreenTriangle_NoAA_Alpha',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_WebGLGreenTriangle_NoAA_NoAlpha',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_WebGLTransparentGreenTriangle_NoAlpha_ImplicitClear',
+              ['android-webview-instrumentation'], bug=907935)
+    self.Fail('Pixel_BackgroundImage',
+              ['android-webview-instrumentation'], bug=907935)
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
new file mode 100644
index 0000000..23481cb
--- /dev/null
+++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -0,0 +1,45 @@
+# tags: [ android linux lion mac mountainlion win win7 win8 ]
+# tags: [ debug ]
+# tags: [ amd-0x6779 nvidia qualcomm-Adreno-(TM)-418 qualcomm-Adreno-(TM)-420 ]
+# tags: [ asan no-asan ]
+
+# AMD Radeon 6450
+crbug.com/479975 [ linux amd-0x6779 ] ContextLost_WebGLContextLostFromGPUProcessExit [ Failure ]
+
+# Win7 bots
+crbug.com/603329 [ win7 ] ContextLost_WebGLContextLostFromGPUProcessExit [ RetryOnFailure ]
+
+# Win8 Release and Debug NVIDIA bots.
+crbug.com/524808 [ win8 nvidia ] ContextLost_WebGLContextLostFromSelectElement [ Skip ]
+
+# Flakily timing out on Win x64 Debug bot. Unfortunately we can't identify this
+# separately from the 32-bit bots. Also unfortunately, the flaky retry mechanism
+# doesn't work well in this harness if the test times out. Skip it on this
+# configuration for now.
+crbug.com/628697 [ win debug ] ContextLost_WebGLContextLostFromQuantity [ Skip ]
+
+# Flaky on Mac 10.7 and 10.8 resulting in crashes during browser
+# startup, so skip this test in those configurations.
+crbug.com/497411 [ mountainlion debug ] ContextLost_WebGLContextLostFromSelectElement [ Skip ]
+crbug.com/498149 [ lion debug ] ContextLost_WebGLContextLostFromSelectElement [ Skip ]
+
+# Too difficult to make this test work on Mac and Android for now. Disabling
+# GLES3 support at the GL bindings level doesn't work there yet.
+crbug.com/923134 [ mac ] ContextLost_WebGL2Blocked [ Skip ]
+crbug.com/923134 [ android ] ContextLost_WebGL2Blocked [ Skip ]
+
+# 'Browser must support tab control' raised on Android
+crbug.com/609629 [ android ] GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash [ Skip ]
+crbug.com/609629 [ android ] ContextLost_WebGLContextLostFromGPUProcessExit [ Skip ]
+crbug.com/609629 [ android ] ContextLost_WebGLContextLostInHiddenTab [ Skip ]
+
+# Flaking on Nexus 5X
+crbug.com/879423 [ android qualcomm-Adreno-(TM)-418 ] ContextLost_WebGLUnblockedAfterUserInitiatedReload [ RetryOnFailure ]
+crbug.com/880078 [ android ] ContextLost_WorkerRAFAfterGPUCrash [ Failure ]
+crbug.com/880078 [ android ] ContextLost_WorkerRAFAfterGPUCrash_OOPD [ Failure ]
+
+# Nexus 6
+# The Nexus 6 times out on these tests while waiting for the JS to complete
+crbug.com/611906 [ android qualcomm-Adreno-(TM)-420 ] ContextLost_WebGLContextLostFromLoseContextExtension [ Failure ]
+crbug.com/611906 [ android qualcomm-Adreno-(TM)-420 ] ContextLost_WebGLContextLostFromQuantity [ Failure ]
+
diff --git a/content/test/gpu/run_gpu_integration_test.py b/content/test/gpu/run_gpu_integration_test.py
index 87b6fe7..68d78d9 100755
--- a/content/test/gpu/run_gpu_integration_test.py
+++ b/content/test/gpu/run_gpu_integration_test.py
@@ -45,7 +45,7 @@
   if current_session.get('CGSSessionScreenIsLocked'):
     raise RuntimeError('Mac lockscreen detected, aborting.')
 
-def FindTestCase(options):
+def FindTestCase(test_name):
   for start_dir in gpu_project_config.CONFIG.start_dirs:
     modules_to_classes = discover.DiscoverClasses(
         start_dir,
@@ -53,7 +53,7 @@
         base_class=serially_executed_browser_test_case.
         SeriallyExecutedBrowserTestCase)
     for cl in modules_to_classes.values():
-      if cl.Name() == options.test:
+      if cl.Name() == test_name:
           return cl
 
 def main():
@@ -68,14 +68,24 @@
     help=('Write the test script arguments to the results file.'))
   option, rest_args_filtered = parser.parse_known_args(rest_args)
 
-  parser.add_argument('test', type=str, help='Name of the test suite to run')
+  parser.add_argument(
+      'test', nargs='*', type=str, help=argparse.SUPPRESS)
   option, _ = parser.parse_known_args(rest_args_filtered)
 
-  test_class = FindTestCase(option)
-  assert test_class
-  rest_args_filtered.extend(
-      ['--test-name-prefix=%s.%s.' %
-       (test_class.__module__, test_class.__name__)])
+  if option.test:
+    test_class = FindTestCase(option.test[0])
+  else:
+    test_class = None
+
+  if test_class:
+    rest_args_filtered.extend(
+        ['--test-name-prefix=%s.%s.' %
+         (test_class.__module__, test_class.__name__)])
+
+  if not any(arg.startswith('--retry-limit') for arg in rest_args_filtered):
+    if '--retry-only-retry-on-failure-tests' not in rest_args_filtered:
+      rest_args_filtered.append('--retry-only-retry-on-failure-tests')
+    rest_args_filtered.append('--retry-limit=2')
 
   retval = browser_test_runner.Run(
       gpu_project_config.CONFIG, rest_args_filtered)
diff --git a/content/test/gpu/unittest_data/test_expectations.txt b/content/test/gpu/unittest_data/test_expectations.txt
index 5c66035..1c390558 100644
--- a/content/test/gpu/unittest_data/test_expectations.txt
+++ b/content/test/gpu/unittest_data/test_expectations.txt
@@ -1,5 +1,5 @@
 # tags: [foo bar honda]
 
-crbug.com/124 [ foo ] unittest_data.integration_tests.RunTestsWithExpectationsFiles.expected_failure [ Failure ]
-crbug.com/125 [ foo ] unittest_data.integration_tests.RunTestsWithExpectationsFiles.expected_flaky [ RetryOnFailure ]
-crbug.com/125 [ foo ] unittest_data.integration_tests.RunTestsWithExpectationsFiles.expected_skip [ Skip ]
\ No newline at end of file
+crbug.com/124 [ foo ] expected_failure [ Failure ]
+crbug.com/125 [ foo ] expected_flaky [ RetryOnFailure ]
+crbug.com/125 [ foo ] expected_skip [ Skip ]
\ No newline at end of file
diff --git a/content/utility/utility_service_factory.cc b/content/utility/utility_service_factory.cc
index a122c03..17f3d126 100644
--- a/content/utility/utility_service_factory.cc
+++ b/content/utility/utility_service_factory.cc
@@ -49,6 +49,7 @@
 #endif
 
 #if defined(OS_MACOSX)
+#include "base/mac/mach_logging.h"
 #include "sandbox/mac/system_services.h"
 #include "services/service_manager/sandbox/features.h"
 #endif
@@ -212,6 +213,28 @@
           service_manager::features::kAudioServiceSandbox)) {
     sandbox::DisableLaunchServices();
   }
+
+  // Set the audio process to run with similar scheduling parameters as the
+  // browser process.
+  task_category_policy category;
+  category.role = TASK_FOREGROUND_APPLICATION;
+  kern_return_t result = task_policy_set(
+      mach_task_self(), TASK_CATEGORY_POLICY,
+      reinterpret_cast<task_policy_t>(&category), TASK_CATEGORY_POLICY_COUNT);
+
+  MACH_LOG_IF(ERROR, result != KERN_SUCCESS, result)
+      << "task_policy_set TASK_CATEGORY_POLICY";
+
+  task_qos_policy qos;
+  qos.task_latency_qos_tier = LATENCY_QOS_TIER_0;
+  qos.task_throughput_qos_tier = THROUGHPUT_QOS_TIER_0;
+  result = task_policy_set(mach_task_self(), TASK_BASE_QOS_POLICY,
+                           reinterpret_cast<task_policy_t>(&qos),
+                           TASK_QOS_POLICY_COUNT);
+
+  MACH_LOG_IF(ERROR, result != KERN_SUCCESS, result)
+      << "task_policy_set TASK_QOS_POLICY";
+
 #endif
 
   return audio::CreateStandaloneService(std::move(audio_registry_),
diff --git a/crypto/signature_creator_unittest.cc b/crypto/signature_creator_unittest.cc
index 1048170a..676b67d5 100644
--- a/crypto/signature_creator_unittest.cc
+++ b/crypto/signature_creator_unittest.cc
@@ -10,7 +10,7 @@
 #include <string>
 #include <vector>
 
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "crypto/rsa_private_key.h"
 #include "crypto/sha2.h"
 #include "crypto/signature_verifier.h"
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 9d6e114..138cae4 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -421,7 +421,7 @@
       "//components/location/android:location_java",
       "//device/bluetooth:java",
       "//third_party/android_deps:com_android_support_support_annotations_java",
-      "//third_party/android_tools:android_test_mock_java",
+      "//third_party/android_sdk:android_test_mock_java",
     ]
 
     srcjar_deps = [ ":bluetooth_test_javagen" ]
diff --git a/device/bluetooth/bluetooth_classic_device_mac.mm b/device/bluetooth/bluetooth_classic_device_mac.mm
index 433fbca..e15ae74 100644
--- a/device/bluetooth/bluetooth_classic_device_mac.mm
+++ b/device/bluetooth/bluetooth_classic_device_mac.mm
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "base/bind.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/mac/sdk_forward_declarations.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/device/fido/ble_adapter_manager_unittest.cc b/device/fido/ble_adapter_manager_unittest.cc
index 1c8d773..7358421 100644
--- a/device/fido/ble_adapter_manager_unittest.cc
+++ b/device/fido/ble_adapter_manager_unittest.cc
@@ -14,6 +14,7 @@
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
+#include "device/fido/fido_authenticator.h"
 #include "device/fido/fido_request_handler_base.h"
 #include "device/fido/test_callback_receiver.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -48,6 +49,7 @@
                     std::string new_authenticator_id));
   MOCK_METHOD2(FidoAuthenticatorPairingModeChanged,
                void(base::StringPiece, bool));
+  MOCK_CONST_METHOD0(SupportsPIN, bool());
   MOCK_METHOD2(CollectPIN,
                void(base::Optional<int>,
                     base::OnceCallback<void(std::string)>));
diff --git a/device/fido/fido_authenticator.cc b/device/fido/fido_authenticator.cc
index 194c93b0..05b6f47b 100644
--- a/device/fido/fido_authenticator.cc
+++ b/device/fido/fido_authenticator.cc
@@ -50,15 +50,17 @@
   NOTREACHED();
 }
 
-AuthenticatorSupportedOptions::ClientPinAvailability
-FidoAuthenticator::WillNeedPINToMakeCredential(const CtapMakeCredentialRequest&
-    request) {
-  return AuthenticatorSupportedOptions::ClientPinAvailability::kNotSupported;
+FidoAuthenticator::MakeCredentialPINDisposition
+FidoAuthenticator::WillNeedPINToMakeCredential(
+    const CtapMakeCredentialRequest& request,
+    const FidoRequestHandlerBase::Observer* observer) {
+  return MakeCredentialPINDisposition::kNoPIN;
 }
 
 FidoAuthenticator::GetAssertionPINDisposition
 FidoAuthenticator::WillNeedPINToGetAssertion(
-    const CtapGetAssertionRequest& request) {
+    const CtapGetAssertionRequest& request,
+    const FidoRequestHandlerBase::Observer* observer) {
   return GetAssertionPINDisposition::kNoPIN;
 }
 
diff --git a/device/fido/fido_authenticator.h b/device/fido/fido_authenticator.h
index aef5326..cbe9cad6 100644
--- a/device/fido/fido_authenticator.h
+++ b/device/fido/fido_authenticator.h
@@ -17,6 +17,7 @@
 #include "device/fido/authenticator_get_assertion_response.h"
 #include "device/fido/authenticator_make_credential_response.h"
 #include "device/fido/authenticator_supported_options.h"
+#include "device/fido/fido_request_handler_base.h"
 #include "device/fido/fido_transport_protocol.h"
 
 namespace device {
@@ -103,14 +104,28 @@
                          const std::string& new_pin,
                          pin::KeyAgreementResponse& peer_key,
                          SetPINCallback callback);
+
+  // MakeCredentialPINDisposition enumerates the possible interactions between
+  // a user-verification level, the PIN configuration of an authenticator, and
+  // whether the embedder is capable of collecting PINs from the user.
+  enum class MakeCredentialPINDisposition {
+    // kNoPIN means that a PIN will not be needed to make this credential.
+    kNoPIN,
+    // kUsePIN means that a PIN must be gathered and used to make this
+    // credential.
+    kUsePIN,
+    // kSetPIN means that the operation should set and then use a PIN to
+    // make this credential.
+    kSetPIN,
+    // kUnsatisfiable means that the request cannot be satisfied by this
+    // authenticator.
+    kUnsatisfiable,
+  };
   // WillNeedPINToMakeCredential returns what type of PIN intervention will be
-  // needed to serve
-  // the given request on this authenticator.
-  //   |kNotSupported|: no PIN involved.
-  //   |kSupportedButPinNotSet|: will need to set a new PIN.
-  //   |kSupportedAndPinSet|: will need to prompt for an existing PIN.
-  virtual AuthenticatorSupportedOptions::ClientPinAvailability
-    WillNeedPINToMakeCredential( const CtapMakeCredentialRequest& request);
+  // needed to serve the given request on this authenticator.
+  virtual MakeCredentialPINDisposition WillNeedPINToMakeCredential(
+      const CtapMakeCredentialRequest& request,
+      const FidoRequestHandlerBase::Observer* observer);
 
   // GetAssertionPINDisposition enumerates the possible interactions between
   // a user-verification level and the PIN support of an authenticator when
@@ -127,7 +142,8 @@
   // WillNeedPINToGetAssertion returns whether a PIN prompt will be needed to
   // serve the given request on this authenticator.
   virtual GetAssertionPINDisposition WillNeedPINToGetAssertion(
-      const CtapGetAssertionRequest& request);
+      const CtapGetAssertionRequest& request,
+      const FidoRequestHandlerBase::Observer* observer);
 
   // Reset triggers a reset operation on the authenticator. This erases all
   // stored resident keys and any configured PIN.
diff --git a/device/fido/fido_constants.h b/device/fido/fido_constants.h
index f5a4eea0..96f710f99 100644
--- a/device/fido/fido_constants.h
+++ b/device/fido/fido_constants.h
@@ -33,6 +33,9 @@
   kSoftPINBlock,
   kHardPINBlock,
   kAuthenticatorMissingResidentKeys,
+  // TODO(agl): kAuthenticatorMissingUserVerification can also be returned when
+  // the authenticator supports UV, but there's no UI support for collecting
+  // a PIN. This could be clearer.
   kAuthenticatorMissingUserVerification,
 };
 
diff --git a/device/fido/fido_device_authenticator.cc b/device/fido/fido_device_authenticator.cc
index 7297886..0812ee7 100644
--- a/device/fido/fido_device_authenticator.cc
+++ b/device/fido/fido_device_authenticator.cc
@@ -183,9 +183,10 @@
   operation_->Start();
 }
 
-AuthenticatorSupportedOptions::ClientPinAvailability
-FidoDeviceAuthenticator::WillNeedPINToMakeCredential(const
-    CtapMakeCredentialRequest& request) {
+FidoAuthenticator::MakeCredentialPINDisposition
+FidoDeviceAuthenticator::WillNeedPINToMakeCredential(
+    const CtapMakeCredentialRequest& request,
+    const FidoRequestHandlerBase::Observer* observer) {
   using ClientPinAvailability =
       AuthenticatorSupportedOptions::ClientPinAvailability;
 
@@ -194,53 +195,66 @@
   if (Options()->user_verification_availability ==
       AuthenticatorSupportedOptions::UserVerificationAvailability::
           kSupportedAndConfigured) {
-    return ClientPinAvailability::kNotSupported;
+    return MakeCredentialPINDisposition::kNoPIN;
   }
 
+  const auto device_support = Options()->client_pin_availability;
+  const bool can_collect_pin = observer && observer->SupportsPIN();
+
   // CTAP 2.0 requires a PIN for credential creation once a PIN has been set.
   // Thus, if fallback to U2F isn't possible, a PIN will be needed if set.
   const bool supports_u2f =
       device()->device_info() &&
       device()->device_info()->versions().contains(ProtocolVersion::kU2f);
-  if (Options()->client_pin_availability ==
-          ClientPinAvailability::kSupportedAndPinSet &&
+  if (device_support == ClientPinAvailability::kSupportedAndPinSet &&
       !supports_u2f) {
-    return ClientPinAvailability::kSupportedAndPinSet;
+    if (can_collect_pin) {
+      return MakeCredentialPINDisposition::kUsePIN;
+    } else {
+      return MakeCredentialPINDisposition::kUnsatisfiable;
+    }
+  }
+
+  // If a PIN cannot be collected, and UV is required, then this request cannot
+  // be met.
+  if (request.user_verification() == UserVerificationRequirement::kRequired &&
+      (!can_collect_pin ||
+       device_support == ClientPinAvailability::kNotSupported)) {
+    return MakeCredentialPINDisposition::kUnsatisfiable;
   }
 
   // If UV is required and a PIN can be set, set it during the MakeCredential
   // process.
-  if (Options()->client_pin_availability ==
-          ClientPinAvailability::kSupportedButPinNotSet &&
+  if (device_support == ClientPinAvailability::kSupportedButPinNotSet &&
       request.user_verification() == UserVerificationRequirement::kRequired) {
-    return ClientPinAvailability::kSupportedButPinNotSet;
+    return MakeCredentialPINDisposition::kSetPIN;
   }
 
   // If discouraged, then either a PIN isn't set (thus we don't use one), or
   // else the device supports U2F (because the alternative was handled above)
   // and we'll use a U2F fallback to create a credential without a PIN.
-  DCHECK(Options()->client_pin_availability !=
-             ClientPinAvailability::kSupportedAndPinSet ||
+  DCHECK(device_support != ClientPinAvailability::kSupportedAndPinSet ||
          supports_u2f);
   // TODO(agl): perhaps CTAP2 is indicated when, for example, hmac-secret is
   // requested?
   if (request.user_verification() ==
       UserVerificationRequirement::kDiscouraged) {
-    return ClientPinAvailability::kNotSupported;
+    return MakeCredentialPINDisposition::kNoPIN;
   }
 
   // Otherwise, a PIN will be used only if set.
-  if (Options()->client_pin_availability ==
-      ClientPinAvailability::kSupportedAndPinSet) {
-    return ClientPinAvailability::kSupportedAndPinSet;
+  if (device_support == ClientPinAvailability::kSupportedAndPinSet &&
+      can_collect_pin) {
+    return MakeCredentialPINDisposition::kUsePIN;
   }
 
-  return ClientPinAvailability::kNotSupported;
+  return MakeCredentialPINDisposition::kNoPIN;
 }
 
 FidoAuthenticator::GetAssertionPINDisposition
 FidoDeviceAuthenticator::WillNeedPINToGetAssertion(
-    const CtapGetAssertionRequest& request) {
+    const CtapGetAssertionRequest& request,
+    const FidoRequestHandlerBase::Observer* observer) {
   // Authenticators with built-in UV can use that. (Fallback to PIN is not yet
   // implemented.)
   if (Options()->user_verification_availability ==
@@ -249,24 +263,26 @@
     return GetAssertionPINDisposition::kNoPIN;
   }
 
-  const bool pin_set = (Options()->client_pin_availability ==
-                        AuthenticatorSupportedOptions::ClientPinAvailability::
-                            kSupportedAndPinSet);
+  const bool can_use_pin = (Options()->client_pin_availability ==
+                            AuthenticatorSupportedOptions::
+                                ClientPinAvailability::kSupportedAndPinSet) &&
+                           // The PIN is effectively unavailable if there's no
+                           // UI support for collecting it.
+                           observer && observer->SupportsPIN();
   const bool resident_key_request =
       !request.allow_list() || request.allow_list()->empty();
 
   if (resident_key_request) {
-    if (pin_set) {
+    if (can_use_pin) {
       return GetAssertionPINDisposition::kUsePIN;
-    } else {
-      return GetAssertionPINDisposition::kUnsatisfiable;
     }
+    return GetAssertionPINDisposition::kUnsatisfiable;
   }
 
   // If UV is required then the PIN must be used if set, or else this request
   // cannot be satisfied.
   if (request.user_verification() == UserVerificationRequirement::kRequired) {
-    if (pin_set) {
+    if (can_use_pin) {
       return GetAssertionPINDisposition::kUsePIN;
     }
     return GetAssertionPINDisposition::kUnsatisfiable;
@@ -274,10 +290,9 @@
 
   // If UV is preferred and a PIN is set, use it.
   if (request.user_verification() == UserVerificationRequirement::kPreferred &&
-      pin_set) {
+      can_use_pin) {
     return GetAssertionPINDisposition::kUsePIN;
   }
-
   return GetAssertionPINDisposition::kNoPIN;
 }
 
diff --git a/device/fido/fido_device_authenticator.h b/device/fido/fido_device_authenticator.h
index d884eef..a62a0e91 100644
--- a/device/fido/fido_device_authenticator.h
+++ b/device/fido/fido_device_authenticator.h
@@ -17,6 +17,7 @@
 #include "build/build_config.h"
 #include "device/fido/ctap2_device_operation.h"
 #include "device/fido/fido_authenticator.h"
+#include "device/fido/fido_request_handler_base.h"
 
 namespace device {
 
@@ -59,14 +60,15 @@
                  const std::string& new_pin,
                  pin::KeyAgreementResponse& peer_key,
                  SetPINCallback callback) override;
-  AuthenticatorSupportedOptions::ClientPinAvailability
-    WillNeedPINToMakeCredential(
-      const CtapMakeCredentialRequest& request) override;
+  MakeCredentialPINDisposition WillNeedPINToMakeCredential(
+      const CtapMakeCredentialRequest& request,
+      const FidoRequestHandlerBase::Observer* observer) override;
 
   // WillNeedPINToGetAssertion returns whether a PIN prompt will be needed to
   // serve the given request on this authenticator.
   GetAssertionPINDisposition WillNeedPINToGetAssertion(
-      const CtapGetAssertionRequest& request) override;
+      const CtapGetAssertionRequest& request,
+      const FidoRequestHandlerBase::Observer* observer) override;
 
   void Reset(ResetCallback callback) override;
   void Cancel() override;
diff --git a/device/fido/fido_request_handler_base.cc b/device/fido/fido_request_handler_base.cc
index 1987e50..2738d86 100644
--- a/device/fido/fido_request_handler_base.cc
+++ b/device/fido/fido_request_handler_base.cc
@@ -14,6 +14,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
 #include "device/fido/ble_adapter_manager.h"
+#include "device/fido/fido_authenticator.h"
 #include "device/fido/fido_discovery_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
 
diff --git a/device/fido/fido_request_handler_base.h b/device/fido/fido_request_handler_base.h
index 93525cd..964b01ef 100644
--- a/device/fido/fido_request_handler_base.h
+++ b/device/fido/fido_request_handler_base.h
@@ -20,7 +20,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_piece_forward.h"
 #include "build/build_config.h"
-#include "device/fido/fido_device_authenticator.h"
 #include "device/fido/fido_discovery_base.h"
 #include "device/fido/fido_transport_protocol.h"
 
@@ -141,6 +140,11 @@
         base::StringPiece authenticator_id,
         bool is_in_pairing_mode) = 0;
 
+    // SupportsPIN returns true if this observer supports collecting a PIN from
+    // the user. If this function returns false, |CollectPIN| and
+    // |FinishCollectPIN| will not be called.
+    virtual bool SupportsPIN() const = 0;
+
     // CollectPIN is called when a PIN is needed to complete a request. The
     // |retries| parameter is either |nullopt| to indicate that the user needs
     // to set a PIN, or contains the number of PIN attempts remaining before a
diff --git a/device/fido/fido_request_handler_unittest.cc b/device/fido/fido_request_handler_unittest.cc
index 521d0e7..00bec24 100644
--- a/device/fido/fido_request_handler_unittest.cc
+++ b/device/fido/fido_request_handler_unittest.cc
@@ -16,6 +16,7 @@
 #include "device/fido/fake_fido_discovery.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/fido_device.h"
+#include "device/fido/fido_device_authenticator.h"
 #include "device/fido/fido_request_handler.h"
 #include "device/fido/fido_task.h"
 #include "device/fido/fido_test_data.h"
@@ -126,6 +127,8 @@
   void FidoAuthenticatorPairingModeChanged(base::StringPiece authenticator_id,
                                            bool is_in_pairing_mode) override {}
 
+  bool SupportsPIN() const override { return false; }
+
   void CollectPIN(
       base::Optional<int> attempts,
       base::OnceCallback<void(std::string)> provide_pin_cb) override {
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc
index b7c71770..ed42af0 100644
--- a/device/fido/get_assertion_handler_unittest.cc
+++ b/device/fido/get_assertion_handler_unittest.cc
@@ -17,6 +17,7 @@
 #include "device/fido/device_response_converter.h"
 #include "device/fido/fake_fido_discovery.h"
 #include "device/fido/fido_constants.h"
+#include "device/fido/fido_device_authenticator.h"
 #include "device/fido/fido_parsing_utils.h"
 #include "device/fido/fido_test_data.h"
 #include "device/fido/fido_transport_protocol.h"
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc
index e08f5f8..71bfc74d2 100644
--- a/device/fido/get_assertion_request_handler.cc
+++ b/device/fido/get_assertion_request_handler.cc
@@ -223,7 +223,7 @@
   }
 
   if (base::FeatureList::IsEnabled(device::kWebAuthPINSupport)) {
-    switch (authenticator->WillNeedPINToGetAssertion(request_)) {
+    switch (authenticator->WillNeedPINToGetAssertion(request_, observer())) {
       case FidoAuthenticator::GetAssertionPINDisposition::kUsePIN:
         // A PIN will be needed. Just request a touch to let the user select
         // this authenticator if they wish.
@@ -306,7 +306,7 @@
   // Requests that require a PIN should follow the |GetTouch| path initially.
   DCHECK(state_ == State::kWaitingForSecondTouch ||
          !base::FeatureList::IsEnabled(device::kWebAuthPINSupport) ||
-         authenticator->WillNeedPINToGetAssertion(request_) ==
+         authenticator->WillNeedPINToGetAssertion(request_, observer()) ==
              FidoAuthenticator::GetAssertionPINDisposition::kNoPIN);
 
   state_ = State::kFinished;
@@ -400,7 +400,7 @@
   }
 
   DCHECK(base::FeatureList::IsEnabled(device::kWebAuthPINSupport) &&
-         authenticator->WillNeedPINToGetAssertion(request_) !=
+         authenticator->WillNeedPINToGetAssertion(request_, observer()) !=
              FidoAuthenticator::GetAssertionPINDisposition::kNoPIN);
 
   DCHECK(observer());
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc
index 44fe635..dee7783 100644
--- a/device/fido/make_credential_handler_unittest.cc
+++ b/device/fido/make_credential_handler_unittest.cc
@@ -459,6 +459,8 @@
   auto device = std::make_unique<VirtualCtap2Device>();
   AuthenticatorSupportedOptions option;
   option.supports_resident_key = true;
+  option.user_verification_availability = AuthenticatorSupportedOptions::
+      UserVerificationAvailability::kSupportedAndConfigured;
   device->SetAuthenticatorSupportedOptions(std::move(option));
 
   auto request_handler =
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc
index ece8f9c7..e61a0ee 100644
--- a/device/fido/make_credential_request_handler.cc
+++ b/device/fido/make_credential_request_handler.cc
@@ -25,6 +25,8 @@
 
 using ClientPinAvailability =
     AuthenticatorSupportedOptions::ClientPinAvailability;
+using MakeCredentialPINDisposition =
+    FidoAuthenticator::MakeCredentialPINDisposition;
 
 namespace {
 
@@ -56,14 +58,10 @@
 // IsCandidateAuthenticatorPostTouch returns a value other than |kSuccess| if
 // the given authenticator cannot handle a request.
 FidoReturnCode IsCandidateAuthenticatorPostTouch(
+    const CtapMakeCredentialRequest& request,
     FidoAuthenticator* authenticator,
     const AuthenticatorSelectionCriteria& authenticator_selection_criteria,
-    bool have_observer) {
-  using UvAvailability =
-      AuthenticatorSupportedOptions::UserVerificationAvailability;
-  const bool pin_support =
-      base::FeatureList::IsEnabled(device::kWebAuthPINSupport) && have_observer;
-
+    const FidoRequestHandlerBase::Observer* observer) {
   const auto& opt_options = authenticator->Options();
   if (!opt_options) {
     // This authenticator doesn't know its capabilities yet, so we need
@@ -77,12 +75,8 @@
     return FidoReturnCode::kAuthenticatorMissingResidentKeys;
   }
 
-  if (authenticator_selection_criteria.user_verification_requirement() ==
-          UserVerificationRequirement::kRequired &&
-      opt_options->user_verification_availability !=
-          UvAvailability::kSupportedAndConfigured &&
-      (!pin_support || opt_options->client_pin_availability ==
-                           ClientPinAvailability::kNotSupported)) {
+  if (authenticator->WillNeedPINToMakeCredential(request, observer) ==
+      MakeCredentialPINDisposition::kUnsatisfiable) {
     return FidoReturnCode::kAuthenticatorMissingUserVerification;
   }
 
@@ -166,8 +160,8 @@
   }
 
   if (IsCandidateAuthenticatorPostTouch(
-          authenticator, authenticator_selection_criteria_, observer()) !=
-      FidoReturnCode::kSuccess) {
+          request_, authenticator, authenticator_selection_criteria_,
+          observer()) != FidoReturnCode::kSuccess) {
     if (!base::FeatureList::IsEnabled(device::kWebAuthPINSupport)) {
       // Don't flash authenticator without PIN support. This maintains previous
       // behaviour and avoids adding UI unprotected by a feature flag without
@@ -177,6 +171,7 @@
                          "support is not enabled";
       return;
     }
+
     // This authenticator does not meet requirements, but make it flash anyway
     // so the user understands that it's functional. A descriptive error message
     // will be shown if the user selects it.
@@ -186,22 +181,38 @@
     return;
   }
 
-  if (base::FeatureList::IsEnabled(device::kWebAuthPINSupport) &&
-      authenticator->WillNeedPINToMakeCredential(request_) !=
-          ClientPinAvailability::kNotSupported) {
-    // A PIN will be needed. Just request a touch to let the user select this
-    // authenticator if they wish.
-    authenticator->GetTouch(
-        base::BindOnce(&MakeCredentialRequestHandler::HandleTouch,
-                       weak_factory_.GetWeakPtr(), authenticator));
-    return;
+  if (base::FeatureList::IsEnabled(device::kWebAuthPINSupport)) {
+    switch (authenticator->WillNeedPINToMakeCredential(request_, observer())) {
+      case MakeCredentialPINDisposition::kUsePIN:
+      case MakeCredentialPINDisposition::kSetPIN:
+        // A PIN will be needed. Just request a touch to let the user select
+        // this authenticator if they wish.
+        authenticator->GetTouch(
+            base::BindOnce(&MakeCredentialRequestHandler::HandleTouch,
+                           weak_factory_.GetWeakPtr(), authenticator));
+        return;
+
+      case MakeCredentialPINDisposition::kNoPIN:
+        break;
+
+      case MakeCredentialPINDisposition::kUnsatisfiable:
+        // |IsCandidateAuthenticatorPostTouch| should have handled this case.
+        NOTREACHED();
+        return;
+    }
   }
 
   CtapMakeCredentialRequest request(request_);
   if (authenticator->Options()) {
+    // If the authenticator has UV configured then UV will be required in
+    // order to create a credential (as specified by CTAP 2.0), even if
+    // user-verification is "discouraged". However, if the request is U2F-only
+    // then that doesn't apply and UV must be set to discouraged so that the
+    // request can be translated to U2F.
     if (authenticator->Options()->user_verification_availability ==
-        AuthenticatorSupportedOptions::UserVerificationAvailability::
-            kSupportedAndConfigured) {
+            AuthenticatorSupportedOptions::UserVerificationAvailability::
+                kSupportedAndConfigured &&
+        !request_.is_u2f_only()) {
       request.SetUserVerification(UserVerificationRequirement::kRequired);
     } else {
       request.SetUserVerification(UserVerificationRequirement::kDiscouraged);
@@ -246,8 +257,8 @@
   // Requests that require a PIN should follow the |GetTouch| path initially.
   DCHECK(state_ == State::kWaitingForSecondTouch ||
          !base::FeatureList::IsEnabled(device::kWebAuthPINSupport) ||
-         authenticator->WillNeedPINToMakeCredential(request_) ==
-             ClientPinAvailability::kNotSupported);
+         authenticator->WillNeedPINToMakeCredential(request_, observer()) ==
+             MakeCredentialPINDisposition::kNoPIN);
 
   state_ = State::kFinished;
   if (response_code != CtapDeviceResponseCode::kSuccess) {
@@ -275,8 +286,8 @@
 
   DCHECK(base::FeatureList::IsEnabled(device::kWebAuthPINSupport));
 
-  switch (authenticator->WillNeedPINToMakeCredential(request_)) {
-    case ClientPinAvailability::kSupportedAndPinSet:
+  switch (authenticator->WillNeedPINToMakeCredential(request_, observer())) {
+    case MakeCredentialPINDisposition::kUsePIN:
       // Will need to get PIN to handle this request.
       DCHECK(observer());
       CancelActiveAuthenticators(authenticator->GetId());
@@ -287,7 +298,7 @@
                          weak_factory_.GetWeakPtr()));
       return;
 
-    case ClientPinAvailability::kSupportedButPinNotSet:
+    case MakeCredentialPINDisposition::kSetPIN:
       // Will need to set a PIN to handle this request.
       DCHECK(observer());
       CancelActiveAuthenticators(authenticator->GetId());
@@ -299,7 +310,8 @@
                          weak_factory_.GetWeakPtr()));
       return;
 
-    case ClientPinAvailability::kNotSupported:
+    case MakeCredentialPINDisposition::kNoPIN:
+    case MakeCredentialPINDisposition::kUnsatisfiable:
       // No PIN needed for this request.
       NOTREACHED();
       break;
@@ -310,7 +322,7 @@
     FidoAuthenticator* authenticator) {
   // User touched an authenticator that cannot handle this request.
   const FidoReturnCode capability_error = IsCandidateAuthenticatorPostTouch(
-      authenticator, authenticator_selection_criteria_, observer());
+      request_, authenticator, authenticator_selection_criteria_, observer());
   DCHECK_NE(capability_error, FidoReturnCode::kSuccess);
   std::move(completion_callback_)
       .Run(capability_error, base::nullopt, base::nullopt);
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc
index cba57e3..5cff379 100644
--- a/device/fido/virtual_ctap2_device.cc
+++ b/device/fido/virtual_ctap2_device.cc
@@ -25,6 +25,7 @@
 #include "device/fido/opaque_attestation_statement.h"
 #include "device/fido/pin.h"
 #include "device/fido/pin_internal.h"
+#include "device/fido/virtual_u2f_device.h"
 #include "third_party/boringssl/src/include/openssl/aes.h"
 #include "third_party/boringssl/src/include/openssl/digest.h"
 #include "third_party/boringssl/src/include/openssl/ec.h"
@@ -412,8 +413,13 @@
     : VirtualFidoDevice(std::move(state)),
       config_(config),
       weak_factory_(this) {
+  std::vector<ProtocolVersion> versions = {ProtocolVersion::kCtap};
+  if (config.u2f_support) {
+    versions.emplace_back(ProtocolVersion::kU2f);
+    u2f_device_.reset(new VirtualU2fDevice(NewReferenceToState()));
+  }
   device_info_ =
-      AuthenticatorGetInfoResponse({ProtocolVersion::kCtap}, kDeviceAaguid);
+      AuthenticatorGetInfoResponse(std::move(versions), kDeviceAaguid);
 
   AuthenticatorSupportedOptions options;
   bool options_updated = false;
@@ -464,6 +470,13 @@
   }
 
   auto cmd_type = command[0];
+  // The CTAP2 commands start at one, so a "command" of zero indicates that this
+  // is a U2F message.
+  if (cmd_type == 0 && config_.u2f_support) {
+    u2f_device_->DeviceTransact(std::move(command), std::move(cb));
+    return;
+  }
+
   const auto request_bytes = base::make_span(command).subspan(1);
   CtapDeviceResponseCode response_code = CtapDeviceResponseCode::kCtap2ErrOther;
   std::vector<uint8_t> response_data;
diff --git a/device/fido/virtual_ctap2_device.h b/device/fido/virtual_ctap2_device.h
index be24a041..3c38fa64 100644
--- a/device/fido/virtual_ctap2_device.h
+++ b/device/fido/virtual_ctap2_device.h
@@ -26,12 +26,17 @@
 
 namespace device {
 
+class VirtualU2fDevice;
+
 class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device
     : public VirtualFidoDevice {
  public:
   struct COMPONENT_EXPORT(DEVICE_FIDO) Config {
     Config();
 
+    // u2f_support, if true, makes this device a dual-protocol (i.e. CTAP2 and
+    // U2F) device.
+    bool u2f_support = false;
     bool pin_support = false;
     bool internal_uv_support = false;
     bool resident_key_support = false;
@@ -77,6 +82,8 @@
       base::Optional<AttestedCredentialData> attested_credential_data,
       base::Optional<cbor::Value> extensions);
 
+  std::unique_ptr<VirtualU2fDevice> u2f_device_;
+
   const Config config_;
   base::WeakPtrFactory<FidoDevice> weak_factory_;
 
diff --git a/device/fido/virtual_fido_device.h b/device/fido/virtual_fido_device.h
index a8ad6068..9875634b 100644
--- a/device/fido/virtual_fido_device.h
+++ b/device/fido/virtual_fido_device.h
@@ -52,6 +52,8 @@
     std::array<uint8_t, kRpIdHashLength> application_parameter;
     uint32_t counter = 0;
     bool is_resident = false;
+    // is_u2f is true if the credential was created via a U2F interface.
+    bool is_u2f = false;
 
     // user is only valid if |is_resident| is true.
     base::Optional<device::PublicKeyCredentialUserEntity> user;
@@ -157,11 +159,13 @@
 
   ~VirtualFidoDevice() override;
 
-  State* mutable_state() { return state_.get(); }
+  State* mutable_state() const { return state_.get(); }
 
  protected:
   static std::vector<uint8_t> GetAttestationKey();
 
+  scoped_refptr<State> NewReferenceToState() const { return state_; }
+
   static bool Sign(crypto::ECPrivateKey* private_key,
                    base::span<const uint8_t> sign_buffer,
                    std::vector<uint8_t>* signature);
diff --git a/device/fido/virtual_u2f_device.cc b/device/fido/virtual_u2f_device.cc
index b5cdc41..8cf933e 100644
--- a/device/fido/virtual_u2f_device.cc
+++ b/device/fido/virtual_u2f_device.cc
@@ -176,9 +176,10 @@
   Append(&response, *attestation_cert);
   Append(&response, sig);
 
-  StoreNewKey(key_handle,
-              RegistrationData(std::move(private_key), application_parameter,
-                               1 /* signature counter */));
+  RegistrationData registration_data(
+      std::move(private_key), application_parameter, 1 /* signature counter */);
+  registration_data.is_u2f = true;
+  StoreNewKey(key_handle, std::move(registration_data));
   return apdu::ApduResponse(std::move(response),
                             apdu::ApduResponse::Status::SW_NO_ERROR)
       .GetEncodedResponse();
diff --git a/device/usb/usb_device_handle_usbfs.cc b/device/usb/usb_device_handle_usbfs.cc
index e768e2f..7fc1b19 100644
--- a/device/usb/usb_device_handle_usbfs.cc
+++ b/device/usb/usb_device_handle_usbfs.cc
@@ -127,12 +127,13 @@
 
 }  // namespace
 
-class UsbDeviceHandleUsbfs::BlockingTaskHelper {
+class UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper {
  public:
-  BlockingTaskHelper(base::ScopedFD fd,
-                     scoped_refptr<UsbDeviceHandleUsbfs> device_handle,
-                     scoped_refptr<base::SequencedTaskRunner> task_runner);
-  ~BlockingTaskHelper();
+  BlockingTaskRunnerHelper(
+      base::ScopedFD fd,
+      scoped_refptr<UsbDeviceHandleUsbfs> device_handle,
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
+  ~BlockingTaskRunnerHelper();
 
   void Start();
   void ReleaseFileDescriptor();
@@ -156,7 +157,7 @@
   std::unique_ptr<base::FileDescriptorWatcher::Controller> watch_controller_;
   base::SequenceChecker sequence_checker_;
 
-  DISALLOW_COPY_AND_ASSIGN(BlockingTaskHelper);
+  DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunnerHelper);
 };
 
 struct UsbDeviceHandleUsbfs::Transfer {
@@ -195,7 +196,7 @@
   usbdevfs_urb urb;
 };
 
-UsbDeviceHandleUsbfs::BlockingTaskHelper::BlockingTaskHelper(
+UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::BlockingTaskRunnerHelper(
     base::ScopedFD fd,
     scoped_refptr<UsbDeviceHandleUsbfs> device_handle,
     scoped_refptr<base::SequencedTaskRunner> task_runner)
@@ -203,30 +204,30 @@
       device_handle_(std::move(device_handle)),
       task_runner_(std::move(task_runner)) {}
 
-UsbDeviceHandleUsbfs::BlockingTaskHelper::~BlockingTaskHelper() {
+UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::~BlockingTaskRunnerHelper() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::Start() {
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::Start() {
   sequence_checker_.DetachFromSequence();
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   // Linux indicates that URBs are available to reap by marking the file
   // descriptor writable.
   watch_controller_ = base::FileDescriptorWatcher::WatchWritable(
-      fd_.get(),
-      base::BindRepeating(&BlockingTaskHelper::OnFileCanWriteWithoutBlocking,
-                          base::Unretained(this)));
+      fd_.get(), base::BindRepeating(
+                     &BlockingTaskRunnerHelper::OnFileCanWriteWithoutBlocking,
+                     base::Unretained(this)));
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::ReleaseFileDescriptor() {
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::ReleaseFileDescriptor() {
   // This method intentionally leaks the file descriptor.
   DCHECK(sequence_checker_.CalledOnValidSequence());
   watch_controller_.reset();
   ignore_result(fd_.release());
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::SetConfiguration(
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::SetConfiguration(
     int configuration_value,
     ResultCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
@@ -243,7 +244,7 @@
                                 std::move(callback)));
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::ReleaseInterface(
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::ReleaseInterface(
     int interface_number,
     ResultCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
@@ -264,7 +265,7 @@
   }
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::SetInterface(
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::SetInterface(
     int interface_number,
     int alternate_setting,
     ResultCallback callback) {
@@ -285,7 +286,7 @@
                          base::BindOnce(std::move(callback), rc == 0));
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::ResetDevice(
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::ResetDevice(
     ResultCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
@@ -301,7 +302,7 @@
                          base::BindOnce(std::move(callback), rc == 0));
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::ClearHalt(
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::ClearHalt(
     uint8_t endpoint_address,
     ResultCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
@@ -318,7 +319,8 @@
                          base::BindOnce(std::move(callback), rc == 0));
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::DiscardUrb(Transfer* transfer) {
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::DiscardUrb(
+    Transfer* transfer) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
@@ -330,7 +332,8 @@
                                         device_handle_, transfer));
 }
 
-void UsbDeviceHandleUsbfs::BlockingTaskHelper::OnFileCanWriteWithoutBlocking() {
+void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::
+    OnFileCanWriteWithoutBlocking() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   const size_t MAX_URBS_PER_EVENT = 10;
@@ -418,9 +421,10 @@
   DCHECK(fd.is_valid());
   DCHECK(blocking_task_runner_);
 
-  helper_.reset(new BlockingTaskHelper(std::move(fd), this, task_runner_));
+  helper_.reset(
+      new BlockingTaskRunnerHelper(std::move(fd), this, task_runner_));
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::Start,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Start,
                                 base::Unretained(helper_.get())));
 }
 
@@ -466,7 +470,7 @@
   blocking_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(
-          &UsbDeviceHandleUsbfs::BlockingTaskHelper::SetConfiguration,
+          &UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::SetConfiguration,
           base::Unretained(helper_.get()), configuration_value,
           std::move(callback)));
 }
@@ -514,7 +518,7 @@
   blocking_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(
-          &UsbDeviceHandleUsbfs::BlockingTaskHelper::ReleaseInterface,
+          &UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::ReleaseInterface,
           base::Unretained(helper_.get()), interface_number,
           std::move(callback)));
 }
@@ -535,9 +539,10 @@
   // to block.
   blocking_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(&UsbDeviceHandleUsbfs::BlockingTaskHelper::SetInterface,
-                     base::Unretained(helper_.get()), interface_number,
-                     alternate_setting, std::move(callback)));
+      base::BindOnce(
+          &UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::SetInterface,
+          base::Unretained(helper_.get()), interface_number, alternate_setting,
+          std::move(callback)));
 }
 
 void UsbDeviceHandleUsbfs::ResetDevice(ResultCallback callback) {
@@ -553,8 +558,9 @@
   // is okay to block.
   blocking_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(&UsbDeviceHandleUsbfs::BlockingTaskHelper::ResetDevice,
-                     base::Unretained(helper_.get()), std::move(callback)));
+      base::BindOnce(
+          &UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::ResetDevice,
+          base::Unretained(helper_.get()), std::move(callback)));
 }
 
 void UsbDeviceHandleUsbfs::ClearHalt(uint8_t endpoint_address,
@@ -571,7 +577,7 @@
   // to block.
   blocking_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(&UsbDeviceHandleUsbfs::BlockingTaskHelper::ClearHalt,
+      base::BindOnce(&UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::ClearHalt,
                      base::Unretained(helper_.get()), endpoint_address,
                      std::move(callback)));
 }
@@ -931,8 +937,9 @@
 
   blocking_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(&UsbDeviceHandleUsbfs::BlockingTaskHelper::DiscardUrb,
-                     base::Unretained(helper_.get()), transfer));
+      base::BindOnce(
+          &UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::DiscardUrb,
+          base::Unretained(helper_.get()), transfer));
 
   // Cancelling |timeout_closure| and running completion callbacks may free
   // |this| so these operations must be performed at the end of this function.
diff --git a/device/usb/usb_device_handle_usbfs.h b/device/usb/usb_device_handle_usbfs.h
index 5f20ed1..c0e36a02 100644
--- a/device/usb/usb_device_handle_usbfs.h
+++ b/device/usb/usb_device_handle_usbfs.h
@@ -88,7 +88,7 @@
   virtual void CloseBlocking();
 
  private:
-  class BlockingTaskHelper;
+  class BlockingTaskRunnerHelper;
   struct Transfer;
   struct InterfaceInfo {
     uint8_t alternate_setting;
@@ -138,7 +138,7 @@
 
   // Helper object exists on the blocking task thread and all calls to it and
   // its destruction must be posted there.
-  std::unique_ptr<BlockingTaskHelper> helper_;
+  std::unique_ptr<BlockingTaskRunnerHelper> helper_;
 
   std::list<std::unique_ptr<Transfer>> transfers_;
   base::SequenceChecker sequence_checker_;
diff --git a/device/usb/usb_service_linux.cc b/device/usb/usb_service_linux.cc
index 28a78181..7c5c0b84 100644
--- a/device/usb/usb_service_linux.cc
+++ b/device/usb/usb_service_linux.cc
@@ -64,10 +64,10 @@
 
 }  // namespace
 
-class UsbServiceLinux::BlockingTaskHelper : public UdevWatcher::Observer {
+class UsbServiceLinux::BlockingTaskRunnerHelper : public UdevWatcher::Observer {
  public:
-  BlockingTaskHelper(base::WeakPtr<UsbServiceLinux> service);
-  ~BlockingTaskHelper() override;
+  BlockingTaskRunnerHelper(base::WeakPtr<UsbServiceLinux> service);
+  ~BlockingTaskRunnerHelper() override;
 
   void Start();
 
@@ -84,10 +84,10 @@
 
   base::SequenceChecker sequence_checker_;
 
-  DISALLOW_COPY_AND_ASSIGN(BlockingTaskHelper);
+  DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunnerHelper);
 };
 
-UsbServiceLinux::BlockingTaskHelper::BlockingTaskHelper(
+UsbServiceLinux::BlockingTaskRunnerHelper::BlockingTaskRunnerHelper(
     base::WeakPtr<UsbServiceLinux> service)
     : service_(service), task_runner_(base::SequencedTaskRunnerHandle::Get()) {
   // Detaches from the sequence on which this object was created. It will be
@@ -95,11 +95,11 @@
   sequence_checker_.DetachFromSequence();
 }
 
-UsbServiceLinux::BlockingTaskHelper::~BlockingTaskHelper() {
+UsbServiceLinux::BlockingTaskRunnerHelper::~BlockingTaskRunnerHelper() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 }
 
-void UsbServiceLinux::BlockingTaskHelper::Start() {
+void UsbServiceLinux::BlockingTaskRunnerHelper::Start() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
@@ -114,7 +114,7 @@
       FROM_HERE, base::BindOnce(&UsbServiceLinux::HelperStarted, service_));
 }
 
-void UsbServiceLinux::BlockingTaskHelper::OnDeviceAdded(
+void UsbServiceLinux::BlockingTaskRunnerHelper::OnDeviceAdded(
     ScopedUdevDevicePtr device) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
@@ -187,7 +187,7 @@
                      active_configuration, bus_number, port_number));
 }
 
-void UsbServiceLinux::BlockingTaskHelper::OnDeviceRemoved(
+void UsbServiceLinux::BlockingTaskRunnerHelper::OnDeviceRemoved(
     ScopedUdevDevicePtr device) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
@@ -205,9 +205,10 @@
     : UsbService(),
       blocking_task_runner_(CreateBlockingTaskRunner()),
       weak_factory_(this) {
-  helper_ = std::make_unique<BlockingTaskHelper>(weak_factory_.GetWeakPtr());
+  helper_ =
+      std::make_unique<BlockingTaskRunnerHelper>(weak_factory_.GetWeakPtr());
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::Start,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Start,
                                 base::Unretained(helper_.get())));
 }
 
diff --git a/device/usb/usb_service_linux.h b/device/usb/usb_service_linux.h
index 514ec00..df1f7ed 100644
--- a/device/usb/usb_service_linux.h
+++ b/device/usb/usb_service_linux.h
@@ -30,7 +30,7 @@
   using DeviceMap =
       std::unordered_map<std::string, scoped_refptr<UsbDeviceLinux>>;
 
-  class BlockingTaskHelper;
+  class BlockingTaskRunnerHelper;
 
   void OnDeviceAdded(const std::string& device_path,
                      const UsbDeviceDescriptor& descriptor,
@@ -57,7 +57,7 @@
   std::list<GetDevicesCallback> enumeration_callbacks_;
 
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  std::unique_ptr<BlockingTaskHelper> helper_;
+  std::unique_ptr<BlockingTaskRunnerHelper> helper_;
   DeviceMap devices_by_path_;
 
   base::WeakPtrFactory<UsbServiceLinux> weak_factory_;
diff --git a/device/usb/usb_service_win.cc b/device/usb/usb_service_win.cc
index ccba0aa..5eb314e 100644
--- a/device/usb/usb_service_win.cc
+++ b/device/usb/usb_service_win.cc
@@ -179,12 +179,12 @@
 
 }  // namespace
 
-class UsbServiceWin::BlockingTaskHelper {
+class UsbServiceWin::BlockingTaskRunnerHelper {
  public:
-  explicit BlockingTaskHelper(base::WeakPtr<UsbServiceWin> service)
+  explicit BlockingTaskRunnerHelper(base::WeakPtr<UsbServiceWin> service)
       : service_task_runner_(base::ThreadTaskRunnerHandle::Get()),
         service_(service) {}
-  ~BlockingTaskHelper() {}
+  ~BlockingTaskRunnerHelper() {}
 
   void EnumerateDevices() {
     ScopedDevInfo dev_info(
@@ -297,9 +297,10 @@
   if (device_monitor)
     device_observer_.Add(device_monitor);
 
-  helper_ = std::make_unique<BlockingTaskHelper>(weak_factory_.GetWeakPtr());
+  helper_ =
+      std::make_unique<BlockingTaskRunnerHelper>(weak_factory_.GetWeakPtr());
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::EnumerateDevices,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::EnumerateDevices,
                                 base::Unretained(helper_.get())));
 }
 
@@ -318,7 +319,7 @@
 void UsbServiceWin::OnDeviceAdded(const GUID& class_guid,
                                   const std::string& device_path) {
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::EnumerateDevicePath,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::EnumerateDevicePath,
                                 base::Unretained(helper_.get()), device_path));
 }
 
diff --git a/device/usb/usb_service_win.h b/device/usb/usb_service_win.h
index 1d0703d..f7d4e44 100644
--- a/device/usb/usb_service_win.h
+++ b/device/usb/usb_service_win.h
@@ -24,7 +24,7 @@
   ~UsbServiceWin() override;
 
  private:
-  class BlockingTaskHelper;
+  class BlockingTaskRunnerHelper;
 
   // device::UsbService implementation
   void GetDevices(const GetDevicesCallback& callback) override;
@@ -54,7 +54,7 @@
   std::list<GetDevicesCallback> enumeration_callbacks_;
 
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  std::unique_ptr<BlockingTaskHelper> helper_;
+  std::unique_ptr<BlockingTaskRunnerHelper> helper_;
   std::unordered_map<std::string, scoped_refptr<UsbDeviceWin>> devices_by_path_;
 
   ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index be44a5b..6332064d 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -253,9 +253,11 @@
   android_library("java") {
     java_files = java_sources_needing_jni
     deps = [
+      "//third_party/gvr-android-sdk:gvr_common_java",
+    ]
+    classpath_deps = [
       "//base:base_java",
       "//ui/android:ui_java",
     ]
-    classpath_deps = [ "//third_party/gvr-android-sdk:gvr_common_java" ]
   }
 }
diff --git a/docs/callback.md b/docs/callback.md
index 3f441b9..36a6b2e 100644
--- a/docs/callback.md
+++ b/docs/callback.md
@@ -1,5 +1,7 @@
 # Callback<> and Bind()
 
+[TOC]
+
 ## Introduction
 
 The templated `base::Callback<>` class is a generalized function object.
@@ -107,6 +109,20 @@
 LOG(INFO) << std::move(lambda_cb2).Run();  // Print 3.
 ```
 
+### Binding A Capturing Lambda (In Tests)
+
+When writing tests, it is often useful to capture arguments that need to be
+modified in a callback.
+
+``` cpp
+#include "base/test/bind_test_util.h"
+
+int i = 2;
+base::Callback<void()> lambda_cb = base::BindLambdaForTesting([&]() { i++; });
+lambda_cb.Run();
+LOG(INFO) << i;  // Print 3;
+```
+
 ### Binding A Class Method
 
 The first argument to bind is the member function to call, the second is the
diff --git a/docs/speed/OWNERS b/docs/speed/OWNERS
index 26af919..495e268 100644
--- a/docs/speed/OWNERS
+++ b/docs/speed/OWNERS
@@ -1,4 +1,4 @@
 sullivan@chromium.org
 benhenry@chromium.org
-rschoen@chromium.org
+ushesh@chromium.org
 per-file apk_size_regressions.md=agrieve@chromium.org
diff --git a/docs/speed/adding_tests_bots.md b/docs/speed/adding_tests_bots.md
index 259a34f0..68260fb3 100644
--- a/docs/speed/adding_tests_bots.md
+++ b/docs/speed/adding_tests_bots.md
@@ -8,4 +8,4 @@
 ## Adding hardware
 
 This documentation is under construction. In the meantime, please reach out to
-benchmarking-dev@chromium.org.
\ No newline at end of file
+crouleau@chromium.org.
diff --git a/docs/speed/chrome_speed_services.md b/docs/speed/chrome_speed_services.md
index cf5f0e7..6c6a5c7 100644
--- a/docs/speed/chrome_speed_services.md
+++ b/docs/speed/chrome_speed_services.md
@@ -1,9 +1,8 @@
 # Speed Operations: Services
 
-TL: simonhatch@<br>
-Team: simonhatch@ benjhayden@, dtu@, eakuefner@<br>
-TPM: benhenry@<br>
-Mailing List: speed-services-dev@chromium.org<br>
+TL: simonhatch@chromium.org<br>
+Team: simonhatch@chromium.org, dberris@chromium.org, benjhayden@chromium.org<br>
+TPM: benhenry@chromium.org, ushesh@chromium.org<br>
 **[go/chrome-speed-services](https://goto.google.com/chrome-speed-services)**
 
 ## Mission
diff --git a/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.cc b/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.cc
index 9c6ad42..742c5711 100644
--- a/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.cc
+++ b/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.cc
@@ -9,7 +9,7 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/metrics/histogram_functions.h"
 #include "content/public/browser/browser_context.h"
 #include "device/bluetooth/bluetooth_adapter.h"
diff --git a/extensions/browser/api/declarative_net_request/utils.cc b/extensions/browser/api/declarative_net_request/utils.cc
index 0833146..4533edd 100644
--- a/extensions/browser/api/declarative_net_request/utils.cc
+++ b/extensions/browser/api/declarative_net_request/utils.cc
@@ -11,7 +11,7 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "components/url_pattern_index/url_pattern_index.h"
diff --git a/extensions/browser/api/metrics_private/metrics_private_api.cc b/extensions/browser/api/metrics_private/metrics_private_api.cc
index bb6bc6f..267fdb1e 100644
--- a/extensions/browser/api/metrics_private/metrics_private_api.cc
+++ b/extensions/browser/api/metrics_private/metrics_private_api.cc
@@ -10,7 +10,7 @@
 #include <memory>
 #include <utility>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 2b0433c..53dd9d1 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -626,7 +626,8 @@
   //
   // Note that details.event_name is actually the sub_event_name!
   ExtensionWebRequestEventRouter::EventListener::ID id(
-      details.browser_context, details.extension_id, details.event_name, 0, 0);
+      details.browser_context, details.extension_id, details.event_name, 0, 0,
+      details.worker_thread_id, details.service_worker_version_id);
 
   // This Unretained is safe because the ExtensionWebRequestEventRouter
   // singleton is leaked.
@@ -1584,10 +1585,10 @@
         listener->id.extension_id, crosses_incognito));
 
     EventRouter::DispatchEventToSender(
-        listener->ipc_sender.get(), browser_context,
-        listener->id.render_process_id, listener->id.extension_id,
+        listener->ipc_sender.get(), browser_context, listener->id.extension_id,
         listener->histogram_value, listener->id.sub_event_name,
-        blink::mojom::kInvalidServiceWorkerVersionId, std::move(args_filtered),
+        listener->id.render_process_id, listener->id.worker_thread_id,
+        listener->id.service_worker_version_id, std::move(args_filtered),
         EventRouter::USER_GESTURE_UNKNOWN, EventFilteringInfo());
   }
 }
@@ -1600,10 +1601,13 @@
     uint64_t request_id,
     int render_process_id,
     int web_view_instance_id,
+    int worker_thread_id,
+    int64_t service_worker_version_id,
     EventResponse* response) {
   Listeners& listeners = listeners_[browser_context][event_name];
   EventListener::ID id(browser_context, extension_id, sub_event_name,
-                       render_process_id, web_view_instance_id);
+                       render_process_id, web_view_instance_id,
+                       worker_thread_id, service_worker_version_id);
   EventListener* listener = FindEventListenerInContainer(id, listeners);
 
   // This might happen, for example, if the extension has been unloaded.
@@ -1626,6 +1630,8 @@
     int extra_info_spec,
     int render_process_id,
     int web_view_instance_id,
+    int worker_thread_id,
+    int64_t service_worker_version_id,
     base::WeakPtr<IPC::Sender> ipc_sender) {
   if (!IsWebRequestEvent(event_name))
     return false;
@@ -1634,7 +1640,8 @@
     return false;
 
   EventListener::ID id(browser_context, extension_id, sub_event_name,
-                       render_process_id, web_view_instance_id);
+                       render_process_id, web_view_instance_id,
+                       worker_thread_id, service_worker_version_id);
   if (FindEventListener(id) != nullptr) {
     // This is likely an abuse of the API by a malicious extension.
     return false;
@@ -2588,7 +2595,7 @@
           profile_id(), extension_id_safe(), extension_name,
           GetEventHistogramValue(event_name), event_name, sub_event_name,
           filter, extra_info_spec, render_process_id, web_view_instance_id,
-          ipc_sender_weak());
+          worker_thread_id(), service_worker_version_id(), ipc_sender_weak());
   EXTENSION_FUNCTION_VALIDATE(success);
 
   helpers::ClearCacheOnNavigation();
@@ -2605,7 +2612,8 @@
     std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response) {
   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
       profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
-      render_process_id, web_view_instance_id, response.release());
+      render_process_id, web_view_instance_id, worker_thread_id(),
+      service_worker_version_id(), response.release());
 }
 
 ExtensionFunction::ResponseAction
@@ -2751,7 +2759,8 @@
 
   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
       profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
-      render_process_id, web_view_instance_id, response.release());
+      render_process_id, web_view_instance_id, worker_thread_id(),
+      service_worker_version_id(), response.release());
 
   return RespondNow(NoArguments());
 }
@@ -2793,12 +2802,19 @@
     const std::string& extension_id,
     const std::string& sub_event_name,
     int render_process_id,
-    int web_view_instance_id)
+    int web_view_instance_id,
+    int worker_thread_id,
+    int64_t service_worker_version_id)
     : browser_context(browser_context),
       extension_id(extension_id),
       sub_event_name(sub_event_name),
       render_process_id(render_process_id),
-      web_view_instance_id(web_view_instance_id) {}
+      web_view_instance_id(web_view_instance_id),
+      worker_thread_id(worker_thread_id),
+      service_worker_version_id(service_worker_version_id) {}
+
+ExtensionWebRequestEventRouter::EventListener::ID::ID(const ID& source) =
+    default;
 
 bool ExtensionWebRequestEventRouter::EventListener::ID::LooselyMatches(
     const ID& that) const {
@@ -2807,6 +2823,8 @@
     // last, as it is exceedingly unlikely to be different.
     return extension_id == that.extension_id &&
            sub_event_name == that.sub_event_name &&
+           worker_thread_id == that.worker_thread_id &&
+           service_worker_version_id == that.service_worker_version_id &&
            browser_context == that.browser_context;
   }
 
@@ -2821,6 +2839,8 @@
          sub_event_name == that.sub_event_name &&
          web_view_instance_id == that.web_view_instance_id &&
          render_process_id == that.render_process_id &&
+         worker_thread_id == that.worker_thread_id &&
+         service_worker_version_id == that.service_worker_version_id &&
          browser_context == that.browser_context;
 }
 
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index 57281dc8..d13caea5 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -449,6 +449,8 @@
                       uint64_t request_id,
                       int render_process_id,
                       int web_view_instance_id,
+                      int worker_thread_id,
+                      int64_t service_worker_version_id,
                       EventResponse* response);
 
   // Adds a listener to the given event. |event_name| specifies the event being
@@ -465,6 +467,8 @@
                         int extra_info_spec,
                         int render_process_id,
                         int web_view_instance_id,
+                        int worker_thread_id,
+                        int64_t service_worker_version_id,
                         base::WeakPtr<IPC::Sender> ipc_sender);
 
   // Removes the listeners for a given <webview>.
@@ -514,10 +518,9 @@
                            TestModifications);
 
   struct EventListener {
-    // An EventListener is uniquely defined by five properties.
     // TODO(rdevlin.cronin): There are two types of EventListeners - those
     // associated with WebViews and those that are not. The ones associated with
-    // WebViews are always identified by all five properties. The other ones
+    // WebViews are always identified by all seven properties. The other ones
     // will always have web_view_instance_id = 0. Unfortunately, the
     // callbacks/interfaces for these ones don't specify render_process_id.
     // This is why we need the LooselyMatches method, and the need for a
@@ -527,7 +530,11 @@
          const std::string& extension_id,
          const std::string& sub_event_name,
          int render_process_id,
-         int web_view_instance_id);
+         int web_view_instance_id,
+         int worker_thread_id,
+         int64_t service_worker_version_id);
+
+      ID(const ID& source);
 
       // If web_view_instance_id is 0, then ignore render_process_id.
       // TODO(rdevlin.cronin): In a more sane world, LooselyMatches wouldn't be
@@ -535,12 +542,18 @@
       bool LooselyMatches(const ID& that) const;
 
       bool operator==(const ID& that) const;
+
       void* browser_context;
       std::string extension_id;
       std::string sub_event_name;
       // In the case of a webview, this is the process ID of the embedder.
       int render_process_id;
       int web_view_instance_id;
+      // The worker_thread_id and service_worker_version_id members are only
+      // meaningful for event listeners for ServiceWorker events. Otherwise,
+      // they are initialized to sentinel values.
+      int worker_thread_id;
+      int64_t service_worker_version_id;
     };
 
     EventListener(ID id);
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.cc b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
index d630a42..4a9255e4 100644
--- a/extensions/browser/api/web_request/web_request_proxying_websocket.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
@@ -44,12 +44,10 @@
   binding_as_websocket_.Bind(std::move(proxied_request));
   binding_as_auth_handler_.Bind(std::move(auth_request));
 
-  binding_as_websocket_.set_connection_error_handler(
-      base::BindRepeating(&WebRequestProxyingWebSocket::OnError,
-                          base::Unretained(this), net::ERR_FAILED));
-  binding_as_auth_handler_.set_connection_error_handler(
-      base::BindRepeating(&WebRequestProxyingWebSocket::OnError,
-                          base::Unretained(this), net::ERR_FAILED));
+  binding_as_websocket_.set_connection_error_handler(base::BindOnce(
+      &WebRequestProxyingWebSocket::OnMojoError, base::Unretained(this)));
+  binding_as_auth_handler_.set_connection_error_handler(base::BindOnce(
+      &WebRequestProxyingWebSocket::OnMojoError, base::Unretained(this)));
 
   if (header_client_request)
     binding_as_header_client_.Bind(std::move(header_client_request));
@@ -122,7 +120,7 @@
   DCHECK(!should_collapse_initiator);
 
   if (result == net::ERR_BLOCKED_BY_CLIENT) {
-    OnError(result);
+    HandleErrorDuringHandshake(result);
     return;
   }
 
@@ -164,7 +162,8 @@
     rv = net::ERR_ABORTED;
   }
 
-  OnError(rv);
+  DoErrorOccurredIfNeeded(rv);
+  // Wait for the render process to delete us to avoid race conditions.
 }
 
 void WebRequestProxyingWebSocket::OnStartOpeningHandshake(
@@ -175,6 +174,11 @@
 
 void WebRequestProxyingWebSocket::OnFinishOpeningHandshake(
     network::mojom::WebSocketHandshakeResponsePtr response) {
+  if (is_handshake_done_) {
+    LOG(WARNING) << "Network service called OnFinishOpeningHandshake too late";
+    return;
+  }
+
   DCHECK(forwarding_client_);
 
   // response_.headers will be set in OnBeforeSendHeaders if
@@ -213,7 +217,7 @@
       response_.headers.get(), &override_headers_, &redirect_url_);
 
   if (result == net::ERR_BLOCKED_BY_CLIENT) {
-    OnError(result);
+    HandleErrorDuringHandshake(result);
     return;
   }
 
@@ -229,8 +233,13 @@
     const std::string& selected_protocol,
     const std::string& extensions) {
   DCHECK(forwarding_client_);
-  DCHECK(!is_done_);
-  is_done_ = true;
+  if (is_handshake_done_) {
+    DLOG(WARNING)
+        << "Multiple OnAddChannelResponse messages from network service";
+    return;
+  }
+  is_handshake_done_ = true;
+
   ExtensionWebRequestEventRouter::GetInstance()->OnCompleted(
       browser_context_, info_map_, &info_.value(), net::ERR_WS_UPGRADE);
 
@@ -257,7 +266,7 @@
   forwarding_client_->OnDropChannel(was_clean, code, reason);
 
   forwarding_client_ = nullptr;
-  OnError(net::ERR_FAILED);
+  // Wait for the render process to delete us to do cleanup.
 }
 
 void WebRequestProxyingWebSocket::OnClosingHandshake() {
@@ -270,8 +279,13 @@
     const scoped_refptr<net::HttpResponseHeaders>& headers,
     const net::IPEndPoint& remote_endpoint,
     OnAuthRequiredCallback callback) {
+  if (is_handshake_done_) {
+    LOG(WARNING) << "Unexpected call to OnAuthRequired from network service";
+    return;
+  }
+
   if (!auth_info || !callback) {
-    OnError(net::ERR_FAILED);
+    HandleErrorDuringHandshake(net::ERR_FAILED);
     return;
   }
 
@@ -287,7 +301,7 @@
       response_.headers.get(), &override_headers_, &redirect_url_);
 
   if (result == net::ERR_BLOCKED_BY_CLIENT) {
-    OnError(result);
+    HandleErrorDuringHandshake(result);
     return;
   }
 
@@ -357,7 +371,7 @@
   DCHECK(binding_as_header_client_ || !binding_as_client_.is_bound());
   DCHECK(request_.url.SchemeIsWSOrWSS());
   if (error_code != net::OK) {
-    OnError(error_code);
+    HandleErrorDuringHandshake(error_code);
     return;
   }
 
@@ -371,7 +385,7 @@
           &request_.headers);
 
   if (result == net::ERR_BLOCKED_BY_CLIENT) {
-    OnError(result);
+    HandleErrorDuringHandshake(result);
     return;
   }
 
@@ -385,7 +399,7 @@
 void WebRequestProxyingWebSocket::OnBeforeSendHeadersComplete(int error_code) {
   DCHECK(binding_as_header_client_ || !binding_as_client_.is_bound());
   if (error_code != net::OK) {
-    OnError(error_code);
+    HandleErrorDuringHandshake(error_code);
     return;
   }
 
@@ -412,9 +426,8 @@
   }
 
   binding_as_client_.Bind(mojo::MakeRequest(&proxy));
-  binding_as_client_.set_connection_error_handler(
-      base::BindOnce(&WebRequestProxyingWebSocket::OnError,
-                     base::Unretained(this), net::ERR_FAILED));
+  binding_as_client_.set_connection_error_handler(base::BindOnce(
+      &WebRequestProxyingWebSocket::OnMojoError, base::Unretained(this)));
   proxied_socket_->AddChannelRequest(
       request_.url, websocket_protocols_, request_.site_for_cookies,
       std::move(additional_headers), std::move(proxy));
@@ -422,7 +435,7 @@
 
 void WebRequestProxyingWebSocket::OnHeadersReceivedComplete(int error_code) {
   if (error_code != net::OK) {
-    OnError(error_code);
+    HandleErrorDuringHandshake(error_code);
     return;
   }
 
@@ -467,7 +480,7 @@
     scoped_refptr<net::AuthChallengeInfo> auth_info,
     int rv) {
   if (rv != net::OK) {
-    OnError(rv);
+    HandleErrorDuringHandshake(rv);
     return;
   }
   ResumeIncomingMethodCallProcessing();
@@ -500,13 +513,26 @@
     binding_as_header_client_.ResumeIncomingMethodCallProcessing();
 }
 
-void WebRequestProxyingWebSocket::OnError(int error_code) {
-  if (!is_done_ && info_.has_value()) {
-    is_done_ = true;
+void WebRequestProxyingWebSocket::DoErrorOccurredIfNeeded(int error_code) {
+  if (!is_handshake_done_ && info_.has_value()) {
+    is_handshake_done_ = true;
     ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
         browser_context_, info_map_, &info_.value(), true /* started */,
         error_code);
   }
+}
+
+void WebRequestProxyingWebSocket::OnMojoError() {
+  HandleGenericError(net::ERR_FAILED);
+}
+
+void WebRequestProxyingWebSocket::HandleErrorDuringHandshake(int error_code) {
+  DCHECK(!is_handshake_done_);
+  HandleGenericError(error_code);
+}
+
+void WebRequestProxyingWebSocket::HandleGenericError(int error_code) {
+  DoErrorOccurredIfNeeded(error_code);
   if (forwarding_client_)
     forwarding_client_->OnFailChannel(net::ErrorToString(error_code));
 
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.h b/extensions/browser/api/web_request/web_request_proxying_websocket.h
index cac917d..3251fdd 100644
--- a/extensions/browser/api/web_request/web_request_proxying_websocket.h
+++ b/extensions/browser/api/web_request/web_request_proxying_websocket.h
@@ -123,7 +123,10 @@
 
   void PauseIncomingMethodCallProcessing();
   void ResumeIncomingMethodCallProcessing();
-  void OnError(int result);
+  void DoErrorOccurredIfNeeded(int error_code);
+  void OnMojoError();
+  void HandleErrorDuringHandshake(int error_code);
+  void HandleGenericError(int error_code);
 
   const int process_id_;
   const int render_frame_id_;
@@ -150,7 +153,7 @@
   OnHeadersReceivedCallback on_headers_received_callback_;
 
   GURL redirect_url_;
-  bool is_done_ = false;
+  bool is_handshake_done_ = false;
   bool waiting_for_header_client_headers_received_ = false;
 
   base::Optional<WebRequestInfo> info_;
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc
index c554abd..cd287abb 100644
--- a/extensions/browser/event_router.cc
+++ b/extensions/browser/event_router.cc
@@ -105,7 +105,6 @@
                                            const EventFilteringInfo& info) {
   NotifyEventDispatched(browser_context_id, extension_id, event_name,
                         *event_args);
-
   ExtensionMsg_DispatchEvent_Params params;
   params.worker_thread_id = worker_thread_id;
   params.extension_id = extension_id;
@@ -131,10 +130,11 @@
 // static
 void EventRouter::DispatchEventToSender(IPC::Sender* ipc_sender,
                                         void* browser_context_id,
-                                        int render_process_id,
                                         const std::string& extension_id,
                                         events::HistogramValue histogram_value,
                                         const std::string& event_name,
+                                        int render_process_id,
+                                        int worker_thread_id,
                                         int64_t service_worker_version_id,
                                         std::unique_ptr<ListValue> event_args,
                                         UserGestureState user_gesture,
@@ -143,7 +143,7 @@
 
   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     DoDispatchEventToSenderBookkeepingOnUI(
-        browser_context_id, render_process_id, extension_id, event_id,
+        browser_context_id, extension_id, event_id, render_process_id,
         service_worker_version_id, histogram_value, event_name);
   } else {
     // This is called from WebRequest API.
@@ -151,17 +151,14 @@
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::UI},
         base::BindOnce(&EventRouter::DoDispatchEventToSenderBookkeepingOnUI,
-                       browser_context_id, render_process_id, extension_id,
-                       event_id, service_worker_version_id, histogram_value,
-                       event_name));
+                       browser_context_id, extension_id, event_id,
+                       render_process_id, service_worker_version_id,
+                       histogram_value, event_name));
   }
 
-  DispatchExtensionMessage(ipc_sender,
-                           // TODO(lazyboy): |kMainThreadId| means these
-                           // will not work for extension SW.
-                           kMainThreadId, browser_context_id, extension_id,
-                           event_id, event_name, event_args.get(), user_gesture,
-                           info);
+  DispatchExtensionMessage(ipc_sender, worker_thread_id, browser_context_id,
+                           extension_id, event_id, event_name, event_args.get(),
+                           user_gesture, info);
 }
 
 // static.
@@ -275,10 +272,10 @@
 }
 
 void EventRouter::OnListenerAdded(const EventListener* listener) {
-  const EventListenerInfo details(listener->event_name(),
-                                  listener->extension_id(),
-                                  listener->listener_url(),
-                                  listener->GetBrowserContext());
+  const EventListenerInfo details(
+      listener->event_name(), listener->extension_id(),
+      listener->listener_url(), listener->GetBrowserContext(),
+      listener->worker_thread_id(), listener->service_worker_version_id());
   std::string base_event_name = GetBaseEventName(listener->event_name());
   auto observer = observers_.find(base_event_name);
   if (observer != observers_.end())
@@ -293,10 +290,10 @@
 }
 
 void EventRouter::OnListenerRemoved(const EventListener* listener) {
-  const EventListenerInfo details(listener->event_name(),
-                                  listener->extension_id(),
-                                  listener->listener_url(),
-                                  listener->GetBrowserContext());
+  const EventListenerInfo details(
+      listener->event_name(), listener->extension_id(),
+      listener->listener_url(), listener->GetBrowserContext(),
+      listener->worker_thread_id(), listener->service_worker_version_id());
   std::string base_event_name = GetBaseEventName(listener->event_name());
   auto observer = observers_.find(base_event_name);
   if (observer != observers_.end())
@@ -713,9 +710,9 @@
 // static
 void EventRouter::DoDispatchEventToSenderBookkeepingOnUI(
     void* browser_context_id,
-    int render_process_id,
     const std::string& extension_id,
     int event_id,
+    int render_process_id,
     int64_t service_worker_version_id,
     events::HistogramValue histogram_value,
     const std::string& event_name) {
@@ -1036,7 +1033,21 @@
     : event_name(event_name),
       extension_id(extension_id),
       listener_url(listener_url),
-      browser_context(browser_context) {
-}
+      browser_context(browser_context),
+      worker_thread_id(kMainThreadId),
+      service_worker_version_id(blink::mojom::kInvalidServiceWorkerVersionId) {}
+
+EventListenerInfo::EventListenerInfo(const std::string& event_name,
+                                     const std::string& extension_id,
+                                     const GURL& listener_url,
+                                     content::BrowserContext* browser_context,
+                                     int worker_thread_id,
+                                     int64_t service_worker_version_id)
+    : event_name(event_name),
+      extension_id(extension_id),
+      listener_url(listener_url),
+      browser_context(browser_context),
+      worker_thread_id(worker_thread_id),
+      service_worker_version_id(service_worker_version_id) {}
 
 }  // namespace extensions
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h
index 140d848..7bf6493 100644
--- a/extensions/browser/event_router.h
+++ b/extensions/browser/event_router.h
@@ -105,10 +105,11 @@
   // methods BroadcastEvent or DispatchEventToExtension.
   static void DispatchEventToSender(IPC::Sender* ipc_sender,
                                     void* browser_context_id,
-                                    int render_process_id,
                                     const std::string& extension_id,
                                     events::HistogramValue histogram_value,
                                     const std::string& event_name,
+                                    int render_process_id,
+                                    int worker_thread_id,
                                     int64_t service_worker_version_id,
                                     std::unique_ptr<base::ListValue> event_args,
                                     UserGestureState user_gesture,
@@ -349,9 +350,9 @@
   // static
   static void DoDispatchEventToSenderBookkeepingOnUI(
       void* browser_context_id,
-      int render_process_id,
       const std::string& extension_id,
       int event_id,
+      int render_process_id,
       int64_t service_worker_version_id,
       events::HistogramValue histogram_value,
       const std::string& event_name);
@@ -472,17 +473,29 @@
 };
 
 struct EventListenerInfo {
+  // Constructor for a listener from a non-ServiceWorker context (background
+  // page, popup, tab, etc)
   EventListenerInfo(const std::string& event_name,
                     const std::string& extension_id,
                     const GURL& listener_url,
                     content::BrowserContext* browser_context);
+
+  // Constructor for a listener from a ServiceWorker context.
+  EventListenerInfo(const std::string& event_name,
+                    const std::string& extension_id,
+                    const GURL& listener_url,
+                    content::BrowserContext* browser_context,
+                    int worker_thread_id,
+                    int64_t service_worker_version_id);
+
   // The event name including any sub-event, e.g. "runtime.onStartup" or
   // "webRequest.onCompleted/123".
   const std::string event_name;
-
   const std::string extension_id;
   const GURL listener_url;
   content::BrowserContext* const browser_context;
+  const int worker_thread_id;
+  const int64_t service_worker_version_id;
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc
index 01426c1..c80df7d 100644
--- a/extensions/browser/extension_function.cc
+++ b/extensions/browser/extension_function.cc
@@ -24,9 +24,11 @@
 #include "extensions/browser/extension_message_filter.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/io_thread_extension_message_filter.h"
+#include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension_api.h"
 #include "extensions/common/extension_messages.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h"
 
 using content::BrowserThread;
 using content::WebContents;
@@ -299,6 +301,7 @@
       histogram_value_(extensions::functions::UNKNOWN),
       source_context_type_(Feature::UNSPECIFIED_CONTEXT),
       source_process_id_(-1),
+      service_worker_version_id_(blink::mojom::kInvalidServiceWorkerVersionId),
       did_respond_(false) {}
 
 ExtensionFunction::~ExtensionFunction() {
@@ -485,10 +488,7 @@
 }
 
 UIThreadExtensionFunction::UIThreadExtensionFunction()
-    : context_(nullptr),
-      render_frame_host_(nullptr),
-      service_worker_version_id_(blink::mojom::kInvalidServiceWorkerVersionId) {
-}
+    : context_(nullptr), render_frame_host_(nullptr) {}
 
 UIThreadExtensionFunction::~UIThreadExtensionFunction() {
   if (dispatcher() && (render_frame_host() || is_from_service_worker())) {
@@ -594,7 +594,8 @@
       ->AddMessageToConsole(level, message);
 }
 
-IOThreadExtensionFunction::IOThreadExtensionFunction() {}
+IOThreadExtensionFunction::IOThreadExtensionFunction()
+    : worker_thread_id_(extensions::kMainThreadId) {}
 
 IOThreadExtensionFunction::~IOThreadExtensionFunction() {
 }
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 1c5ddeb..cb244c6 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -312,6 +312,18 @@
     return source_process_id_;
   }
 
+  void set_service_worker_version_id(int64_t service_worker_version_id) {
+    service_worker_version_id_ = service_worker_version_id;
+  }
+  int64_t service_worker_version_id() const {
+    return service_worker_version_id_;
+  }
+
+  bool is_from_service_worker() const {
+    return service_worker_version_id_ !=
+           blink::mojom::kInvalidServiceWorkerVersionId;
+  }
+
   ResponseType* response_type() const { return response_type_.get(); }
 
   bool did_respond() const { return did_respond_; }
@@ -493,6 +505,10 @@
   // if unknown.
   int source_process_id_;
 
+  // If this ExtensionFunction was called by an extension Service Worker, then
+  // this contains the worker's version id.
+  int64_t service_worker_version_id_;
+
   // The response type of the function, if the response has been sent.
   std::unique_ptr<ResponseType> response_type_;
 
@@ -538,10 +554,6 @@
     return dispatcher_.get();
   }
 
-  void set_service_worker_version_id(int64_t version_id) {
-    service_worker_version_id_ = version_id;
-  }
-
   // Returns the web contents associated with the sending |render_frame_host_|.
   // This can be null.
   content::WebContents* GetSenderWebContents();
@@ -571,21 +583,12 @@
 
   void Destruct() const override;
 
-  bool is_from_service_worker() const {
-    return service_worker_version_id_ !=
-           blink::mojom::kInvalidServiceWorkerVersionId;
-  }
-
   // The dispatcher that will service this extension function call.
   base::WeakPtr<extensions::ExtensionFunctionDispatcher> dispatcher_;
 
   // The RenderFrameHost we will send responses to.
   content::RenderFrameHost* render_frame_host_;
 
-  // If this ExtensionFunction was called by an extension Service Worker, then
-  // this contains the worker's version id.
-  int64_t service_worker_version_id_;
-
   std::unique_ptr<RenderFrameHostTracker> tracker_;
 
   // The blobs transferred to the renderer process.
@@ -618,6 +621,11 @@
     return ipc_sender_;
   }
 
+  void set_worker_thread_id(int worker_thread_id) {
+    worker_thread_id_ = worker_thread_id;
+  }
+  int worker_thread_id() const { return worker_thread_id_; }
+
   void set_extension_info_map(const extensions::InfoMap* extension_info_map) {
     extension_info_map_ = extension_info_map;
   }
@@ -636,6 +644,7 @@
 
  private:
   base::WeakPtr<extensions::IOThreadExtensionMessageFilter> ipc_sender_;
+  int worker_thread_id_;
 
   scoped_refptr<const extensions::InfoMap> extension_info_map_;
 
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc
index 52580af..2ed2e3c9 100644
--- a/extensions/browser/extension_function_dispatcher.cc
+++ b/extensions/browser/extension_function_dispatcher.cc
@@ -79,6 +79,7 @@
 
 void CommonResponseCallback(IPC::Sender* ipc_sender,
                             int routing_id,
+                            int worker_thread_id,
                             int request_id,
                             ExtensionFunction::ResponseType type,
                             const base::ListValue& results,
@@ -90,14 +91,23 @@
     return;
   }
 
-  ipc_sender->Send(new ExtensionMsg_Response(
-      routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results,
-      error));
+  if (routing_id != MSG_ROUTING_NONE) {
+    DCHECK_EQ(kMainThreadId, worker_thread_id);
+    ipc_sender->Send(new ExtensionMsg_Response(
+        routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results,
+        error));
+  } else {
+    DCHECK_NE(kMainThreadId, worker_thread_id);
+    ipc_sender->Send(new ExtensionMsg_ResponseWorker(
+        worker_thread_id, request_id, type == ExtensionFunction::SUCCEEDED,
+        results, error));
+  }
 }
 
 void IOThreadResponseCallback(
     const base::WeakPtr<IOThreadExtensionMessageFilter>& ipc_sender,
     int routing_id,
+    int worker_thread_id,
     int request_id,
     ExtensionFunction::ResponseType type,
     const base::ListValue& results,
@@ -106,8 +116,8 @@
   if (!ipc_sender.get())
     return;
 
-  CommonResponseCallback(ipc_sender.get(), routing_id, request_id, type,
-                         results, error);
+  CommonResponseCallback(ipc_sender.get(), routing_id, worker_thread_id,
+                         request_id, type, results, error);
 }
 
 }  // namespace
@@ -154,8 +164,8 @@
                                     const std::string& error,
                                     functions::HistogramValue histogram_value) {
     CommonResponseCallback(render_frame_host_,
-                           render_frame_host_->GetRoutingID(), request_id, type,
-                           results, error);
+                           render_frame_host_->GetRoutingID(), kMainThreadId,
+                           request_id, type, results, error);
   }
 
   base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_;
@@ -269,20 +279,16 @@
 }
 
 // static
-void ExtensionFunctionDispatcher::DispatchOnIOThread(
+void ExtensionFunctionDispatcher::DoDispatchOnIOThread(
     InfoMap* extension_info_map,
     void* profile_id,
     int render_process_id,
     base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender,
-    int routing_id,
-    const ExtensionHostMsg_Request_Params& params) {
+    const ExtensionHostMsg_Request_Params& params,
+    const ExtensionFunction::ResponseCallback& callback) {
   const Extension* extension =
       extension_info_map->extensions().GetByID(params.extension_id);
 
-  ExtensionFunction::ResponseCallback callback(
-      base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id,
-                 params.request_id));
-
   scoped_refptr<ExtensionFunction> function(
       CreateExtensionFunction(params,
                               extension,
@@ -301,6 +307,8 @@
     return;
   }
   function_io->set_ipc_sender(ipc_sender);
+  function_io->set_worker_thread_id(params.worker_thread_id);
+  function_io->set_service_worker_version_id(params.service_worker_version_id);
   function_io->set_extension_info_map(extension_info_map);
   if (extension) {
     function->set_include_incognito_information(
@@ -342,6 +350,37 @@
   }
 }
 
+// static
+void ExtensionFunctionDispatcher::DispatchOnIOThread(
+    InfoMap* extension_info_map,
+    void* profile_id,
+    int render_process_id,
+    base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender,
+    int routing_id,
+    const ExtensionHostMsg_Request_Params& params) {
+  ExtensionFunction::ResponseCallback callback(
+      base::BindRepeating(&IOThreadResponseCallback, ipc_sender, routing_id,
+                          kMainThreadId, params.request_id));
+
+  DoDispatchOnIOThread(extension_info_map, profile_id, render_process_id,
+                       ipc_sender, params, callback);
+}
+
+// static
+void ExtensionFunctionDispatcher::DispatchOnIOThreadForServiceWorker(
+    InfoMap* extension_info_map,
+    void* profile_id,
+    int render_process_id,
+    base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender,
+    const ExtensionHostMsg_Request_Params& params) {
+  ExtensionFunction::ResponseCallback callback(base::BindRepeating(
+      &IOThreadResponseCallback, ipc_sender, MSG_ROUTING_NONE,
+      params.worker_thread_id, params.request_id));
+
+  DoDispatchOnIOThread(extension_info_map, profile_id, render_process_id,
+                       ipc_sender, params, callback);
+}
+
 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
     content::BrowserContext* browser_context)
     : browser_context_(browser_context), delegate_(nullptr) {}
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h
index ca99b6f..9ace6e7a 100644
--- a/extensions/browser/extension_function_dispatcher.h
+++ b/extensions/browser/extension_function_dispatcher.h
@@ -80,6 +80,15 @@
       int routing_id,
       const ExtensionHostMsg_Request_Params& params);
 
+  // Dispatches an IO-thread extension function for a Service Worker. Only
+  // used for specific functions that must be handled on the IO-thread.
+  static void DispatchOnIOThreadForServiceWorker(
+      InfoMap* extension_info_map,
+      void* profile_id,
+      int render_process_id,
+      base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender,
+      const ExtensionHostMsg_Request_Params& params);
+
   // Public constructor. Callers must ensure that:
   // - This object outlives any RenderFrameHost's passed to created
   //   ExtensionFunctions.
@@ -128,6 +137,14 @@
   // |ui_thread_response_callback_wrappers_for_worker_|.
   struct WorkerResponseCallbackMapKey;
 
+  static void DoDispatchOnIOThread(
+      InfoMap* extension_info_map,
+      void* profile_id,
+      int render_process_id,
+      base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender,
+      const ExtensionHostMsg_Request_Params& params,
+      const ExtensionFunction::ResponseCallback& callback);
+
   // Helper to check whether an ExtensionFunction has the required permissions.
   // This should be called after the function is fully initialized.
   // If the check fails, |callback| is run with an access-denied error and false
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index 9fa89cf..b52b0205 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -19,6 +19,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -27,7 +28,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc b/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
index 019c445..c3d46820 100644
--- a/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
+++ b/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
@@ -26,6 +26,7 @@
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/process_map.h"
 #include "extensions/browser/view_type_utils.h"
+#include "extensions/common/constants.h"
 #include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h"
@@ -73,9 +74,9 @@
     return;  // Could happen at tab shutdown.
 
   EventRouter::DispatchEventToSender(
-      owner->GetRenderViewHost(), guest->browser_context(),
-      content::ChildProcessHost::kInvalidUniqueID, guest->owner_host(),
-      histogram_value, event_name, blink::mojom::kInvalidServiceWorkerVersionId,
+      owner->GetRenderViewHost(), guest->browser_context(), guest->owner_host(),
+      histogram_value, event_name, content::ChildProcessHost::kInvalidUniqueID,
+      extensions::kMainThreadId, blink::mojom::kInvalidServiceWorkerVersionId,
       std::move(event_args), EventRouter::USER_GESTURE_UNKNOWN, info);
 }
 
diff --git a/extensions/browser/io_thread_extension_message_filter.cc b/extensions/browser/io_thread_extension_message_filter.cc
index 81e2fab..a08f11b1 100644
--- a/extensions/browser/io_thread_extension_message_filter.cc
+++ b/extensions/browser/io_thread_extension_message_filter.cc
@@ -46,6 +46,8 @@
                       OnExtensionGenerateUniqueID)
   IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestForIOThread,
                       OnExtensionRequestForIOThread)
+  IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestWorkerForIOThread,
+                      OnExtensionRequestWorkerForIOThread)
   IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -66,4 +68,12 @@
       weak_ptr_factory_.GetWeakPtr(), routing_id, params);
 }
 
+void IOThreadExtensionMessageFilter::OnExtensionRequestWorkerForIOThread(
+    const ExtensionHostMsg_Request_Params& params) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  ExtensionFunctionDispatcher::DispatchOnIOThreadForServiceWorker(
+      extension_info_map_.get(), browser_context_id_, render_process_id_,
+      weak_ptr_factory_.GetWeakPtr(), params);
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/io_thread_extension_message_filter.h b/extensions/browser/io_thread_extension_message_filter.h
index e8547ff..a8bb1e6 100644
--- a/extensions/browser/io_thread_extension_message_filter.h
+++ b/extensions/browser/io_thread_extension_message_filter.h
@@ -45,6 +45,8 @@
   void OnExtensionRequestForIOThread(
       int routing_id,
       const ExtensionHostMsg_Request_Params& params);
+  void OnExtensionRequestWorkerForIOThread(
+      const ExtensionHostMsg_Request_Params& params);
 
   const int render_process_id_;
 
diff --git a/extensions/browser/script_executor.cc b/extensions/browser/script_executor.cc
index 5537dc6..c0b7f5c6 100644
--- a/extensions/browser/script_executor.cc
+++ b/extensions/browser/script_executor.cc
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/bind.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/pickle.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/extensions/browser/url_loader_factory_manager.cc b/extensions/browser/url_loader_factory_manager.cc
index 42f1686db..8d15799c 100644
--- a/extensions/browser/url_loader_factory_manager.cc
+++ b/extensions/browser/url_loader_factory_manager.cc
@@ -13,9 +13,9 @@
 #include "base/command_line.h"
 #include "base/containers/flat_set.h"
 #include "base/feature_list.h"
+#include "base/hash/sha1.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/no_destructor.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "content/public/browser/browser_context.h"
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 65a5e108..ae2501b 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -585,12 +585,12 @@
   },
   "webRequest": {
     "dependencies": ["permission:webRequest"],
-    "contexts": ["blessed_extension"]
+    "contexts": ["blessed_extension", "extension_service_worker"]
   },
   "webRequestInternal": [{
     "internal": true,
     "channel": "stable",
-    "contexts": ["blessed_extension"]
+    "contexts": ["blessed_extension", "extension_service_worker"]
   }, {
     // webview uses webRequestInternal API.
     "channel": "stable",
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h
index dd37b8c..5cee00c 100644
--- a/extensions/common/extension_messages.h
+++ b/extensions/common/extension_messages.h
@@ -118,11 +118,12 @@
   IPC_STRUCT_MEMBER(bool, user_gesture)
 
   // If this API call is for a service worker, then this is the worker thread
-  // id. Otherwise, this is -1.
+  // id. Otherwise, this is kMainThreadId.
   IPC_STRUCT_MEMBER(int, worker_thread_id)
 
   // If this API call is for a service worker, then this is the service
-  // worker version id. Otherwise, this is -1.
+  // worker version id. Otherwise, this is set to
+  // blink::mojom::kInvalidServiceWorkerVersionId.
   IPC_STRUCT_MEMBER(int64_t, service_worker_version_id)
 IPC_STRUCT_END()
 
@@ -743,6 +744,14 @@
                      int /* routing_id */,
                      ExtensionHostMsg_Request_Params)
 
+// A service worker thread sends this message when an extension service worker
+// starts an API request. The browser will always respond with a
+// ExtensionMsg_ResponseWorker. This message is for API requests that run on
+// the IO thread. It is defined here so it's handled by the same message
+// filter as ExtensionHostMsg_RequestForIOThread.
+IPC_MESSAGE_CONTROL1(ExtensionHostMsg_RequestWorkerForIOThread,
+                     ExtensionHostMsg_Request_Params)
+
 // Notify the browser that the given extension added a listener to an event.
 IPC_MESSAGE_CONTROL5(ExtensionHostMsg_AddListener,
                      std::string /* extension_id */,
diff --git a/extensions/renderer/bindings/api_request_handler.cc b/extensions/renderer/bindings/api_request_handler.cc
index 586f97e..eaf470a 100644
--- a/extensions/renderer/bindings/api_request_handler.cc
+++ b/extensions/renderer/bindings/api_request_handler.cc
@@ -10,6 +10,7 @@
 #include "base/values.h"
 #include "content/public/common/content_features.h"
 #include "content/public/renderer/v8_value_converter.h"
+#include "extensions/renderer/bindings/api_binding_util.h"
 #include "extensions/renderer/bindings/api_response_validator.h"
 #include "extensions/renderer/bindings/exception_handler.h"
 #include "extensions/renderer/bindings/js_runner.h"
@@ -301,6 +302,12 @@
   JSRunner::Get(context)->RunJSFunction(pending_request.callback->Get(isolate),
                                         context, full_args.size(),
                                         full_args.data());
+
+  // Since arbitrary JS has ran, the context may have been invalidated. If it
+  // was, bail.
+  if (!binding::IsContextValid(context))
+    return;
+
   if (try_catch.HasCaught()) {
     v8::Local<v8::Message> v8_message = try_catch.Message();
     base::Optional<std::string> message;
diff --git a/extensions/renderer/ipc_message_sender.cc b/extensions/renderer/ipc_message_sender.cc
index b3216455..6d2fd75 100644
--- a/extensions/renderer/ipc_message_sender.cc
+++ b/extensions/renderer/ipc_message_sender.cc
@@ -230,7 +230,6 @@
                       binding::RequestThread thread) override {
     DCHECK(!context->GetRenderFrame());
     DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
-    DCHECK_EQ(binding::RequestThread::UI, thread);
     DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
 
     int worker_thread_id = content::WorkerThread::GetCurrentId();
@@ -245,7 +244,15 @@
     dispatcher_->Send(new ExtensionHostMsg_IncrementServiceWorkerActivity(
         service_worker_version_id_, guid));
 
-    dispatcher_->Send(new ExtensionHostMsg_RequestWorker(*params));
+    switch (thread) {
+      case binding::RequestThread::UI:
+        dispatcher_->Send(new ExtensionHostMsg_RequestWorker(*params));
+        break;
+      case binding::RequestThread::IO:
+        dispatcher_->Send(
+            new ExtensionHostMsg_RequestWorkerForIOThread(*params));
+        break;
+    }
   }
 
   void SendOnRequestResponseReceivedIPC(int request_id) override {
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index de84e52..ef9561c 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -752,7 +752,7 @@
   params->has_callback = request->has_callback;
   params->user_gesture = request->has_user_gesture;
   // The IPC sender will update these members, if appropriate.
-  params->worker_thread_id = -1;
+  params->worker_thread_id = kMainThreadId;
   params->service_worker_version_id =
       blink::mojom::kInvalidServiceWorkerVersionId;
 
diff --git a/extensions/renderer/web_request_hooks.cc b/extensions/renderer/web_request_hooks.cc
index b1f9af5..2b8ac2ff 100644
--- a/extensions/renderer/web_request_hooks.cc
+++ b/extensions/renderer/web_request_hooks.cc
@@ -11,6 +11,7 @@
 #include "extensions/common/extension_api.h"
 #include "extensions/renderer/bindings/api_binding_hooks.h"
 #include "extensions/renderer/bindings/js_runner.h"
+#include "extensions/renderer/get_script_context.h"
 #include "extensions/renderer/module_system.h"
 #include "extensions/renderer/script_context.h"
 #include "extensions/renderer/script_context_set.h"
@@ -31,8 +32,7 @@
 
   v8::Isolate* isolate = context->GetIsolate();
 
-  ScriptContext* script_context =
-      ScriptContextSet::GetContextByV8Context(context);
+  ScriptContext* script_context = GetScriptContextFromV8Context(context);
   v8::Local<v8::Object> internal_bindings;
   {
     ModuleSystem::NativesEnabledScope enable_natives(
diff --git a/google_apis/gcm/engine/gservices_settings.cc b/google_apis/gcm/engine/gservices_settings.cc
index d5fef7f..6de0e1c 100644
--- a/google_apis/gcm/engine/gservices_settings.cc
+++ b/google_apis/gcm/engine/gservices_settings.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgba.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgba.txt
index d52bab851..991c4e5f 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgba.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgba.txt
@@ -8,7 +8,7 @@
 
 Version
 
-    Last Modifed Date: February 7, 2014
+    Last Modifed Date: March 27, 2019
 
 Dependencies
 
@@ -23,8 +23,8 @@
     This extension implements a subset of EXT_color_buffer_float on top of
     OpenGL ES 2.0.
 
-    This extension enables rendering to floating point RGBA textures. When
-    this extension is enabled:
+    This extension enables rendering to floating point RGBA textures and
+    renderbuffers. When this extension is enabled:
 
     * The 32-bit floating point type GL_RGBA32F becomes available as a
       color-renderable internal format. Textures created with type = FLOAT,
@@ -36,13 +36,16 @@
       OpenGL ES 2.0 spec that the internalformat parameter and format parameter
       of TexImage2D must match is lifted for this case.
 
+    * GL_RGBA32F becomes an available internalformat for RenderbufferStorage.
+
     Floating point RGBA textures may still be created also with the unsized
     GL_RGBA internal format, but whether such textures are renderable is not
     guaranteed.
 
 New Tokens
 
-    Accepted by the <internalformat> parameter of TexImage2D:
+    Accepted by the <internalformat> parameter of RenderbufferStorage and
+    TexImage2D:
 
     GL_RGBA32F      0x8814
 
@@ -61,4 +64,4 @@
 Revision History
 
     2/7/2014    Documented the extension
-
+    3/27/2019   Add support for renderbuffers
diff --git a/gpu/command_buffer/client/webgpu_implementation.cc b/gpu/command_buffer/client/webgpu_implementation.cc
index 8f038c4..c71787c 100644
--- a/gpu/command_buffer/client/webgpu_implementation.cc
+++ b/gpu/command_buffer/client/webgpu_implementation.cc
@@ -173,8 +173,11 @@
 void WebGPUImplementation::OnGpuControlReturnData(
     base::span<const uint8_t> data) {
 #if BUILDFLAG(USE_DAWN)
-  wire_client_->HandleCommands(reinterpret_cast<const char*>(data.data()),
-                               data.size());
+  if (!wire_client_->HandleCommands(
+      reinterpret_cast<const char*>(data.data()), data.size())) {
+    // TODO(enga): Lose the context.
+    NOTREACHED();
+  }
 #endif
 }
 
diff --git a/gpu/command_buffer/service/gr_shader_cache.h b/gpu/command_buffer/service/gr_shader_cache.h
index 96fe05f..a05cbed9 100644
--- a/gpu/command_buffer/service/gr_shader_cache.h
+++ b/gpu/command_buffer/service/gr_shader_cache.h
@@ -7,7 +7,7 @@
 
 #include "base/containers/flat_set.h"
 #include "base/containers/mru_cache.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/memory/memory_pressure_listener.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "gpu/gpu_gles2_export.h"
diff --git a/gpu/command_buffer/service/program_cache.h b/gpu/command_buffer/service/program_cache.h
index d5b0a7dc..cdb6eba 100644
--- a/gpu/command_buffer/service/program_cache.h
+++ b/gpu/command_buffer/service/program_cache.h
@@ -11,9 +11,9 @@
 #include <string>
 #include <unordered_map>
 
+#include "base/hash/sha1.h"
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
-#include "base/sha1.h"
 #include "gpu/command_buffer/common/gl2_types.h"
 #include "gpu/gpu_gles2_export.h"
 
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index bb89b1e..6ae8475 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -471,7 +471,10 @@
   }
 
   std::vector<char> commands(shm_commands, shm_commands + size);
-  wire_server_->HandleCommands(commands.data(), size);
+  if (!wire_server_->HandleCommands(commands.data(), size)) {
+    NOTREACHED();
+    return error::kLostContext;
+  }
   wire_serializer_->Flush();
   return error::kNoError;
 }
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc
index b5387c1..53b343b 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.cc
+++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -4,7 +4,7 @@
 
 #include "gpu/command_buffer/service/wrapped_sk_image.h"
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/process_memory_dump.h"
diff --git a/gpu/ipc/host/gpu_memory_buffer_support.h b/gpu/ipc/host/gpu_memory_buffer_support.h
index b35087a..3003eec7 100644
--- a/gpu/ipc/host/gpu_memory_buffer_support.h
+++ b/gpu/ipc/host/gpu_memory_buffer_support.h
@@ -5,11 +5,12 @@
 #ifndef GPU_IPC_HOST_GPU_MEMORY_BUFFER_SUPPORT_H_
 #define GPU_IPC_HOST_GPU_MEMORY_BUFFER_SUPPORT_H_
 
+#include <functional>
 #include <unordered_set>
 #include <utility>
 #include <vector>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "ui/gfx/buffer_types.h"
 
 namespace gpu {
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc
index 139f4f5c..125fe87 100644
--- a/gpu/ipc/service/command_buffer_stub.cc
+++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/json/json_writer.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
diff --git a/gpu/ipc/service/context_url.cc b/gpu/ipc/service/context_url.cc
index 16b597b6..a02b182 100644
--- a/gpu/ipc/service/context_url.cc
+++ b/gpu/ipc/service/context_url.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "components/crash/core/common/crash_key.h"
 
 namespace gpu {
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc
index 58f18ae66..2559626 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.cc
+++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -9,7 +9,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/json/json_writer.h"
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
index c9486a0..f9d7730 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
@@ -8,7 +8,7 @@
 #include <unordered_map>
 #include <utility>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/synchronization/lock.h"
 #include "gpu/command_buffer/service/image_factory.h"
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc
index 1a0dd1b..040ccad 100644
--- a/gpu/ipc/service/shared_image_stub.cc
+++ b/gpu/ipc/service/shared_image_stub.cc
@@ -278,6 +278,7 @@
   auto* context = context_state_->real_context();
   if (context->IsCurrent(nullptr) ||
       context_state_->real_context()->MakeCurrent(context_state_->surface())) {
+    CHECK(gl::GLContext::GetCurrent());
     return true;
   } else {
     context_state_->MarkContextLost();
diff --git a/headless/lib/browser/protocol/headless_devtools_session.cc b/headless/lib/browser/protocol/headless_devtools_session.cc
index c5ec413..ff4b901 100644
--- a/headless/lib/browser/protocol/headless_devtools_session.cc
+++ b/headless/lib/browser/protocol/headless_devtools_session.cc
@@ -4,8 +4,10 @@
 
 #include "headless/lib/browser/protocol/headless_devtools_session.h"
 
+#include "base/command_line.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_agent_host_client.h"
+#include "content/public/common/content_switches.h"
 #include "headless/lib/browser/protocol/browser_handler.h"
 #include "headless/lib/browser/protocol/headless_handler.h"
 #include "headless/lib/browser/protocol/page_handler.h"
@@ -13,6 +15,11 @@
 
 namespace headless {
 namespace protocol {
+static bool EnableInternalDevToolsBinaryProtocol() {
+  static bool enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      ::switches::kEnableInternalDevToolsBinaryProtocol);
+  return enabled;
+}
 
 HeadlessDevToolsSession::HeadlessDevToolsSession(
     base::WeakPtr<HeadlessBrowserImpl> browser,
@@ -53,7 +60,8 @@
   std::string unused;
   std::unique_ptr<protocol::DictionaryValue> value =
       protocol::DictionaryValue::cast(protocol::StringUtil::parseMessage(
-          message, client_->UsesBinaryProtocol()));
+          message, client_->UsesBinaryProtocol() ||
+                       EnableInternalDevToolsBinaryProtocol()));
   if (!dispatcher_->parseCommand(value.get(), &call_id, &unused))
     return;
   pending_commands_[call_id] = std::move(callback);
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index b8760f3d..6bddd41f 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -111,6 +111,30 @@
   }
 }
 
+# This is for load testing of the execution backend.
+builder_mixins {
+  name: "goma-j1000"
+  recipe {
+    properties_j: <<END
+    $build/goma: {
+      "jobs": 1000
+    }
+    END
+  }
+}
+
+# This is for load testing of the execution backend.
+builder_mixins {
+  name: "goma-j2000"
+  recipe {
+    properties_j: <<END
+    $build/goma: {
+      "jobs": 2000
+    }
+    END
+  }
+}
+
 # This is for 4 cores mac. -j40 is too small, especially for clobber builder.
 builder_mixins {
   name: "goma-j80"
diff --git a/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc b/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc
index ec64526..9f87a1a 100644
--- a/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc
+++ b/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc
@@ -11,7 +11,6 @@
 #include "components/signin/core/browser/test_signin_client.h"
 #include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/signin/account_fetcher_service_factory.h"
 #include "ios/chrome/browser/signin/account_tracker_service_factory.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -120,10 +119,4 @@
     IdentityTestEnvironmentChromeBrowserStateAdaptor(
         ios::ChromeBrowserState* browser_state)
     : identity_test_env_(
-          browser_state->GetPrefs(),
-          ios::AccountTrackerServiceFactory::GetForBrowserState(browser_state),
-          ios::AccountFetcherServiceFactory::GetForBrowserState(browser_state),
-          static_cast<FakeProfileOAuth2TokenService*>(
-              ProfileOAuth2TokenServiceFactory::GetForBrowserState(
-                  browser_state)),
           IdentityManagerFactory::GetForBrowserState(browser_state)) {}
diff --git a/ios/chrome/browser/snapshots/snapshot_generator.mm b/ios/chrome/browser/snapshots/snapshot_generator.mm
index 9dcf154c..6f4ace1 100644
--- a/ios/chrome/browser/snapshots/snapshot_generator.mm
+++ b/ios/chrome/browser/snapshots/snapshot_generator.mm
@@ -206,6 +206,8 @@
              frameInBaseView:(CGRect)frameInBaseView {
   DCHECK(baseView);
   DCHECK(!CGRectIsEmpty(frameInBaseView));
+  // Note: When not using device scale, the output image size may slightly
+  // differ from the input size due to rounding.
   const CGFloat kScale =
       std::max<CGFloat>(1.0, [self.snapshotCache snapshotScaleForDevice]);
   UIGraphicsBeginImageContextWithOptions(frameInBaseView.size, YES, kScale);
@@ -251,7 +253,9 @@
   DCHECK(!CGRectIsEmpty(frameInWindow));
   if (!baseImage)
     return nil;
-  DCHECK(CGSizeEqualToSize(baseImage.size, frameInWindow.size));
+  // Note: If the baseImage scale differs from device scale, the baseImage size
+  // may slightly differ from frameInWindow size due to rounding. Do not attempt
+  // to compare the baseImage size and frameInWindow size.
   if (overlays.count == 0)
     return baseImage;
   const CGFloat kScale =
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 452345e..0efbee9e 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -245,8 +245,8 @@
       history::HistoryService* history =
           ios::HistoryServiceFactory::GetForBrowserState(
               browser_state_, ServiceAccessType::EXPLICIT_ACCESS);
-      return history ? history->AsWeakPtr()
-                     : base::WeakPtr<history::HistoryService>();
+      return history ? history->GetDeleteDirectivesSyncableService()
+                     : base::WeakPtr<syncer::SyncableService>();
     }
     case syncer::FAVICON_IMAGES:
     case syncer::FAVICON_TRACKING: {
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index 547a6ed..82060ed 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -77,7 +77,6 @@
 #import "ios/web/public/serializable_user_data_manager.h"
 #include "ios/web/public/ssl_status.h"
 #include "ios/web/public/url_scheme_util.h"
-#include "ios/web/public/url_util.h"
 #include "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #import "ios/web/public/web_state/navigation_context.h"
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm
index a45e423..a046993 100644
--- a/ios/chrome/browser/translate/translate_egtest.mm
+++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/ios/ios_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -736,6 +737,10 @@
 // Tests that the infobar hides/shows as the browser enters/exits the fullscreen
 // mode as well as it can be dimissed.
 - (void)testInfobarShowHideDismiss {
+  // TODO (crbug.com/946894) Re-enable once fixed on iOS12.2
+  if (base::ios::IsRunningOnOrLater(12, 2, 0)) {
+    EARL_GREY_TEST_DISABLED(@"Disabled on iOS 12,2.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
index de16f51..7b239ac 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
@@ -9,7 +9,7 @@
 #include <memory>
 #include <vector>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/i18n/string_compare.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/stl_util.h"
diff --git a/ios/chrome/browser/ui/fullscreen/BUILD.gn b/ios/chrome/browser/ui/fullscreen/BUILD.gn
index 8604fc3..1804365 100644
--- a/ios/chrome/browser/ui/fullscreen/BUILD.gn
+++ b/ios/chrome/browser/ui/fullscreen/BUILD.gn
@@ -99,6 +99,7 @@
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/ui",
     "//ios/web",
+    "//ios/web/common",
     "//ui/gfx/geometry",
   ]
 }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
index 9a434e9..ec4924b 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
@@ -15,10 +15,10 @@
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/ui/fullscreen_provider.h"
+#include "ios/web/common/url_util.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/ssl_status.h"
-#include "ios/web/public/url_util.h"
 #import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/page_display_state.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
diff --git a/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm b/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
index dfa3a8a..08ec461 100644
--- a/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
+++ b/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
@@ -5,7 +5,7 @@
 #include "ios/chrome/browser/ui/ntp/ntp_tile_saver.h"
 
 #include "base/bind.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/scoped_blocking_call.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.h
index 69d9931..0fa9792 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.h
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.h
@@ -8,18 +8,31 @@
 #import <UIKit/UIKit.h>
 
 @protocol AutocompleteSuggestion;
+@class OmniboxPopupRowCell;
 
 namespace {
 NSString* OmniboxPopupRowCellReuseIdentifier = @"OmniboxPopupRowCell";
 }  // namespace
 
+// Protocol for informing delegate that the trailing button for this cell
+// was tapped
+@protocol OmniboxPopupRowCellDelegate
+
+// The trailing button was tapped.
+- (void)trailingButtonTappedForCell:(OmniboxPopupRowCell*)cell;
+
+@end
+
 // Table view cell to display an autocomplete suggestion in the omnibox popup.
 // It handles all the layout logic internally.
 @interface OmniboxPopupRowCell : UITableViewCell
 
+// Layout this cell with the given data before displaying.
 - (void)setupWithAutocompleteSuggestion:(id<AutocompleteSuggestion>)suggestion
                               incognito:(BOOL)incognito;
 
+@property(nonatomic, weak) id<OmniboxPopupRowCellDelegate> delegate;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_OMNIBOX_POPUP_ROW_CELL_H_
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
index 53ac8b46..98ef1a48 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
@@ -4,8 +4,16 @@
 
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.h"
 
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "components/omnibox/common/omnibox_features.h"
 #import "ios/chrome/browser/ui/omnibox/popup/autocomplete_suggestion.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_truncating_label.h"
+#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
+#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/chrome/grit/ios_theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -13,16 +21,46 @@
 
 namespace {
 const CGFloat kLeadingMargin = 24;
-const CGFloat kVerticalSpace = 6;
+const CGFloat kLeadingMarginIpad = 183;
+const CGFloat kTextTopMargin = 6;
+const CGFloat kTextLeadingMargin = 10;
+const CGFloat kTextTrailingMargin = -12;
+const CGFloat kImageViewSize = 28;
+const CGFloat kImageViewCornerRadius = 7;
+const CGFloat kTrailingButtonSize = 48;
+const CGFloat kTrailingButtonTrailingMargin = 4;
+const CGFloat kAnswerImageSize = 30;
+const CGFloat kAnswerImageLeadingMargin = -1;
+const CGFloat kAnswerImageViewTopMargin = 2;
+
+NSString* const kOmniboxPopupRowSwitchTabAccessibilityIdentifier =
+    @"OmniboxPopupRowSwitchTabAccessibilityIdentifier";
 }  // namespace
 
 @interface OmniboxPopupRowCell ()
 
-@property(nonatomic, strong) OmniboxPopupTruncatingLabel* textTruncatingLabel;
-@property(nonatomic, strong) OmniboxPopupTruncatingLabel* detailTruncatingLabel;
-
+// The suggestion that this cell is currently displaying.
+@property(nonatomic, strong) id<AutocompleteSuggestion> suggestion;
+// Whether the cell is currently dispalying in incognito mode or not.
 @property(nonatomic, assign) BOOL incognito;
 
+// Truncating label for the main text.
+@property(nonatomic, strong) OmniboxPopupTruncatingLabel* textTruncatingLabel;
+// Truncating label for the detail text.
+@property(nonatomic, strong) OmniboxPopupTruncatingLabel* detailTruncatingLabel;
+// Regular UILabel for the detail text when the suggestion is an answer.
+// Answers have slightly different display requirements, like possibility of
+// multiple lines and truncating with ellipses instead of a fade gradient.
+@property(nonatomic, strong) UILabel* detailAnswerLabel;
+// Image view for the image in an answer (e.g. weather image).
+@property(nonatomic, strong) UIImageView* detailAnswerImageView;
+// Image view for the leading image (only appears on iPad).
+@property(nonatomic, strong) UIImageView* leadingImageView;
+// Trailing button for appending suggestion into omnibox.
+@property(nonatomic, strong) UIButton* trailingButton;
+// Layout guide encapsulating everything related to the detail section.
+@property(nonatomic, strong) UILayoutGuide* detailLayoutGuide;
+
 @end
 
 @implementation OmniboxPopupRowCell
@@ -33,9 +71,40 @@
   if (self) {
     _textTruncatingLabel =
         [[OmniboxPopupTruncatingLabel alloc] initWithFrame:CGRectZero];
+    _textTruncatingLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    _textTruncatingLabel.userInteractionEnabled = NO;
+
     _detailTruncatingLabel =
         [[OmniboxPopupTruncatingLabel alloc] initWithFrame:CGRectZero];
+    _detailTruncatingLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    _detailTruncatingLabel.userInteractionEnabled = NO;
 
+    // Answers use a UILabel with NSLineBreakByTruncatingTail to produce a
+    // truncation with an ellipse instead of fading on multi-line text.
+    _detailAnswerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+    _detailAnswerLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    _detailAnswerLabel.userInteractionEnabled = NO;
+    _detailAnswerLabel.lineBreakMode = NSLineBreakByTruncatingTail;
+
+    _detailAnswerImageView = [[UIImageView alloc] initWithImage:nil];
+    _detailAnswerImageView.translatesAutoresizingMaskIntoConstraints = NO;
+    _detailAnswerImageView.userInteractionEnabled = NO;
+    _detailAnswerImageView.contentMode = UIViewContentModeScaleAspectFit;
+
+    _leadingImageView = [[UIImageView alloc] initWithImage:nil];
+    _leadingImageView.translatesAutoresizingMaskIntoConstraints = NO;
+    _leadingImageView.userInteractionEnabled = NO;
+    _leadingImageView.contentMode = UIViewContentModeCenter;
+    _leadingImageView.layer.cornerRadius = kImageViewCornerRadius;
+
+    _trailingButton = [UIButton buttonWithType:UIButtonTypeCustom];
+    _trailingButton.translatesAutoresizingMaskIntoConstraints = NO;
+    [_trailingButton addTarget:self
+                        action:@selector(trailingButtonTapped)
+              forControlEvents:UIControlEventTouchUpInside];
+    [_trailingButton setContentMode:UIViewContentModeRight];
+
+    _detailLayoutGuide = [[UILayoutGuide alloc] init];
     _incognito = NO;
 
     self.backgroundColor = [UIColor clearColor];
@@ -43,53 +112,274 @@
   return self;
 }
 
-- (void)setupLayout {
-  self.textTruncatingLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  [self.contentView addSubview:self.textTruncatingLabel];
-  self.detailTruncatingLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  [self.contentView addSubview:self.detailTruncatingLabel];
+#pragma mark - Layout
 
-  UILayoutGuide* safeAreaLayoutGuide = self.contentView.safeAreaLayoutGuide;
+// Setup the layout of the cell initially. This only adds the elements that are
+// always in the cell.
+- (void)setupLayout {
+  [self.contentView addSubview:self.textTruncatingLabel];
+  [self.contentView addSubview:self.detailTruncatingLabel];
+  [self.contentView addSubview:self.detailAnswerLabel];
+  [self.contentView addLayoutGuide:self.detailLayoutGuide];
 
   [NSLayoutConstraint activateConstraints:@[
-    [self.textTruncatingLabel.leadingAnchor
-        constraintEqualToAnchor:safeAreaLayoutGuide.leadingAnchor
-                       constant:kLeadingMargin],
-    [self.textTruncatingLabel.trailingAnchor
-        constraintEqualToAnchor:safeAreaLayoutGuide.trailingAnchor],
-    [self.textTruncatingLabel.topAnchor
-        constraintEqualToAnchor:safeAreaLayoutGuide.topAnchor
-                       constant:kVerticalSpace],
+    // Use greater/less than or equal constraints to allow for when any optional
+    // elements are added (leadingImageView, trailingButton, etc.)
 
+    // Position textTruncatingLabel
+    [self.textTruncatingLabel.leadingAnchor
+        constraintGreaterThanOrEqualToAnchor:self.contentView.leadingAnchor
+                                    constant:kLeadingMargin],
+    [self.contentView.trailingAnchor
+        constraintGreaterThanOrEqualToAnchor:self.textTruncatingLabel
+                                                 .trailingAnchor],
+    [self.textTruncatingLabel.topAnchor
+        constraintEqualToAnchor:self.contentView.topAnchor
+                       constant:kTextTopMargin],
+
+    // Position detailLayoutGuide
+    [self.detailLayoutGuide.leadingAnchor
+        constraintGreaterThanOrEqualToAnchor:self.contentView.leadingAnchor
+                                    constant:kLeadingMargin],
+    [self.contentView.trailingAnchor
+        constraintGreaterThanOrEqualToAnchor:self.detailLayoutGuide
+                                                 .trailingAnchor],
+    [self.detailLayoutGuide.topAnchor
+        constraintEqualToAnchor:self.textTruncatingLabel.bottomAnchor],
+    [self.detailLayoutGuide.bottomAnchor
+        constraintEqualToAnchor:self.contentView.bottomAnchor],
+
+    // Position detailTruncatingLabel in detailLayoutGuide.
     [self.detailTruncatingLabel.leadingAnchor
-        constraintEqualToAnchor:safeAreaLayoutGuide.leadingAnchor
-                       constant:kLeadingMargin],
+        constraintGreaterThanOrEqualToAnchor:self.detailLayoutGuide
+                                                 .leadingAnchor],
     [self.detailTruncatingLabel.trailingAnchor
-        constraintEqualToAnchor:safeAreaLayoutGuide.trailingAnchor],
+        constraintEqualToAnchor:self.detailLayoutGuide.trailingAnchor],
     [self.detailTruncatingLabel.topAnchor
-        constraintEqualToAnchor:self.textTruncatingLabel.bottomAnchor
-                       constant:kVerticalSpace],
+        constraintEqualToAnchor:self.detailLayoutGuide.topAnchor],
     [self.detailTruncatingLabel.bottomAnchor
-        constraintEqualToAnchor:safeAreaLayoutGuide.bottomAnchor],
+        constraintEqualToAnchor:self.detailLayoutGuide.bottomAnchor],
+
+    // Position detailAnswerLabel exactly equal to detailTruncatingLabel.
+    [self.detailAnswerLabel.topAnchor
+        constraintEqualToAnchor:self.detailTruncatingLabel.topAnchor],
+    [self.detailAnswerLabel.bottomAnchor
+        constraintEqualToAnchor:self.detailTruncatingLabel.bottomAnchor],
+    [self.detailAnswerLabel.leadingAnchor
+        constraintEqualToAnchor:self.detailTruncatingLabel.leadingAnchor],
+    [self.detailAnswerLabel.trailingAnchor
+        constraintEqualToAnchor:self.detailTruncatingLabel.trailingAnchor],
+  ]];
+
+  // To prevent ambiguity when there is no leading image view, add a
+  // non-required leading space 0 constraint to force the "Greater than or
+  // equal" to become as small as possible.
+  NSLayoutConstraint* textConstraint = [self.textTruncatingLabel.leadingAnchor
+      constraintEqualToAnchor:self.contentView.leadingAnchor];
+  textConstraint.priority = UILayoutPriorityDefaultHigh;
+
+  NSLayoutConstraint* detailConstraint = [self.detailLayoutGuide.leadingAnchor
+      constraintEqualToAnchor:self.contentView.leadingAnchor];
+  detailConstraint.priority = UILayoutPriorityDefaultHigh;
+
+  NSLayoutConstraint* detailTextConstraint =
+      [self.detailTruncatingLabel.leadingAnchor
+          constraintEqualToAnchor:self.self.detailLayoutGuide.leadingAnchor];
+  detailTextConstraint.priority = UILayoutPriorityDefaultHigh;
+  [NSLayoutConstraint activateConstraints:@[
+    textConstraint, detailConstraint, detailTextConstraint
+  ]];
+}
+
+// Add the trailing button as a subview and setup its constraints.
+- (void)setupTrailingButtonLayout {
+  [self.contentView addSubview:self.trailingButton];
+  [NSLayoutConstraint activateConstraints:@[
+    [self.trailingButton.heightAnchor
+        constraintEqualToConstant:kTrailingButtonSize],
+    [self.trailingButton.widthAnchor
+        constraintEqualToConstant:kTrailingButtonSize],
+    [self.trailingButton.centerYAnchor
+        constraintEqualToAnchor:self.contentView.centerYAnchor],
+    [self.contentView.trailingAnchor
+        constraintEqualToAnchor:self.trailingButton.trailingAnchor
+                       constant:kTrailingButtonTrailingMargin],
+    [self.trailingButton.leadingAnchor
+        constraintEqualToAnchor:self.textTruncatingLabel.trailingAnchor
+                       constant:kTextTrailingMargin],
+    [self.trailingButton.leadingAnchor
+        constraintEqualToAnchor:self.detailLayoutGuide.trailingAnchor
+                       constant:kTextTrailingMargin],
+  ]];
+}
+
+// Add the leading image view as a subview and setup its constraints.
+- (void)setupLeadingImageViewLayout {
+  [self.contentView addSubview:self.leadingImageView];
+  [NSLayoutConstraint activateConstraints:@[
+    [self.leadingImageView.heightAnchor
+        constraintEqualToConstant:kImageViewSize],
+    [self.leadingImageView.widthAnchor
+        constraintEqualToConstant:kImageViewSize],
+    [self.leadingImageView.centerYAnchor
+        constraintEqualToAnchor:self.contentView.centerYAnchor],
+    [self.leadingImageView.leadingAnchor
+        constraintEqualToAnchor:self.contentView.leadingAnchor
+                       constant:kLeadingMarginIpad],
+    [self.textTruncatingLabel.leadingAnchor
+        constraintEqualToAnchor:self.leadingImageView.trailingAnchor
+                       constant:kTextLeadingMargin],
+    [self.detailLayoutGuide.leadingAnchor
+        constraintEqualToAnchor:self.leadingImageView.trailingAnchor
+                       constant:kTextLeadingMargin],
+  ]];
+}
+
+// Add the detail answer image view as a subview and setup its constraints.
+- (void)setupDetailAnswerImageViewLayout {
+  [self.contentView addSubview:self.detailAnswerImageView];
+  [NSLayoutConstraint activateConstraints:@[
+    [self.detailAnswerImageView.heightAnchor
+        constraintEqualToConstant:kAnswerImageSize],
+    [self.detailAnswerImageView.widthAnchor
+        constraintEqualToConstant:kAnswerImageSize],
+    [self.detailAnswerImageView.leadingAnchor
+        constraintEqualToAnchor:self.detailLayoutGuide.leadingAnchor
+                       constant:kAnswerImageLeadingMargin],
+    [self.detailAnswerImageView.topAnchor
+        constraintEqualToAnchor:self.detailLayoutGuide.topAnchor
+                       constant:kAnswerImageViewTopMargin],
+    [self.detailAnswerImageView.trailingAnchor
+        constraintEqualToAnchor:self.detailTruncatingLabel.leadingAnchor],
   ]];
 }
 
 - (void)prepareForReuse {
   [super prepareForReuse];
 
+  self.suggestion = nil;
   self.incognito = NO;
+
+  // Remove optional views
+  [self.trailingButton removeFromSuperview];
+  [self.leadingImageView removeFromSuperview];
+  [self.detailAnswerImageView removeFromSuperview];
+
+  self.trailingButton.accessibilityIdentifier = nil;
+
+  self.accessibilityCustomActions = nil;
 }
 
+#pragma mark - Cell setup with data
+
+// Use the given autocomplete suggestion and whether incognito is enabled to
+// layout the cell correctly for that data.
 - (void)setupWithAutocompleteSuggestion:(id<AutocompleteSuggestion>)suggestion
                               incognito:(BOOL)incognito {
   // Setup the view layout the first time the cell is setup.
   if (self.contentView.subviews.count == 0) {
     [self setupLayout];
   }
+  self.suggestion = suggestion;
   self.incognito = incognito;
 
-  self.textTruncatingLabel.attributedText = suggestion.text;
-  self.detailTruncatingLabel.attributedText = suggestion.detailText;
+  self.textTruncatingLabel.attributedText = self.suggestion.text;
+
+  self.detailAnswerLabel.hidden = !self.suggestion.hasAnswer;
+  self.detailTruncatingLabel.hidden = self.suggestion.hasAnswer;
+  // URLs have have special layout requirements.
+  self.detailTruncatingLabel.displayAsURL = suggestion.isURL;
+  UILabel* detailLabel = self.suggestion.hasAnswer ? self.detailAnswerLabel
+                                                   : self.detailTruncatingLabel;
+  detailLabel.attributedText = self.suggestion.detailText;
+  if (self.suggestion.hasAnswer) {
+    detailLabel.numberOfLines = self.suggestion.numberOfLines;
+  }
+
+  // Show append button for search history/search suggestions as the right
+  // control element (aka an accessory element of a table view cell).
+  if (self.suggestion.isAppendable || self.suggestion.isTabMatch) {
+    [self setupTrailingButtonLayout];
+
+    NSString* trailingButtonActionName =
+        suggestion.isTabMatch
+            ? l10n_util::GetNSString(IDS_IOS_OMNIBOX_POPUP_SWITCH_TO_OPEN_TAB)
+            : l10n_util::GetNSString(IDS_IOS_OMNIBOX_POPUP_APPEND);
+    UIAccessibilityCustomAction* trailingButtonAction =
+        [[UIAccessibilityCustomAction alloc]
+            initWithName:trailingButtonActionName
+                  target:self
+                selector:@selector(trailingButtonTapped)];
+
+    self.accessibilityCustomActions = @[ trailingButtonAction ];
+
+    UIImage* trailingButtonImage = nil;
+    if (self.suggestion.isTabMatch) {
+      trailingButtonImage = [UIImage imageNamed:@"omnibox_popup_tab_match"];
+      trailingButtonImage =
+          trailingButtonImage.imageFlippedForRightToLeftLayoutDirection;
+      self.trailingButton.accessibilityIdentifier =
+          kOmniboxPopupRowSwitchTabAccessibilityIdentifier;
+    } else {
+      int trailingButtonResourceID = 0;
+      if (base::FeatureList::IsEnabled(omnibox::kOmniboxTabSwitchSuggestions)) {
+        trailingButtonResourceID = IDR_IOS_OMNIBOX_KEYBOARD_VIEW_APPEND;
+      } else {
+        trailingButtonResourceID =
+            self.incognito ? IDR_IOS_OMNIBOX_KEYBOARD_VIEW_APPEND_INCOGNITO
+                           : IDR_IOS_OMNIBOX_KEYBOARD_VIEW_APPEND;
+      }
+      trailingButtonImage =
+          NativeReversableImage(trailingButtonResourceID, YES);
+    }
+    trailingButtonImage = [trailingButtonImage
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+
+    [self.trailingButton setImage:trailingButtonImage
+                         forState:UIControlStateNormal];
+    if (base::FeatureList::IsEnabled(omnibox::kOmniboxTabSwitchSuggestions)) {
+      self.trailingButton.tintColor =
+          self.incognito ? [UIColor whiteColor]
+                         : UIColorFromRGB(kLocationBarTintBlue);
+    } else {
+      self.trailingButton.tintColor =
+          self.incognito ? [UIColor colorWithWhite:1 alpha:0.5]
+                         : [UIColor colorWithWhite:0 alpha:0.3];
+    }
+  }
+
+  if ([self showsLeadingIcons]) {
+    self.leadingImageView.image = self.suggestion.suggestionTypeIcon;
+    self.leadingImageView.backgroundColor =
+        self.incognito ? [UIColor colorWithWhite:1 alpha:0.05]
+                       : [UIColor colorWithWhite:0 alpha:0.03];
+    self.leadingImageView.tintColor =
+        self.incognito ? [UIColor colorWithWhite:1 alpha:0.4]
+                       : [UIColor colorWithWhite:0 alpha:0.33];
+    [self setupLeadingImageViewLayout];
+  }
+
+  if (suggestion.hasImage) {
+    [self setupDetailAnswerImageViewLayout];
+  }
+}
+
+- (NSString*)accessibilityLabel {
+  return self.textTruncatingLabel.attributedText.string;
+}
+
+- (NSString*)accessibilityValue {
+  return self.detailTruncatingLabel.hidden
+             ? self.detailAnswerLabel.attributedText.string
+             : self.detailTruncatingLabel.attributedText.string;
+}
+
+- (BOOL)showsLeadingIcons {
+  return IsRegularXRegularSizeClass();
+}
+
+- (void)trailingButtonTapped {
+  [self.delegate trailingButtonTappedForCell:self];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
index 9d8de219..7c5b475 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
@@ -12,6 +12,9 @@
 #error "This file requires ARC support."
 #endif
 
+@interface OmniboxPopupViewController () <OmniboxPopupRowCellDelegate>
+@end
+
 @implementation OmniboxPopupViewController
 
 - (void)viewDidLoad {
@@ -61,8 +64,17 @@
                            forIndexPath:indexPath];
   [cell setupWithAutocompleteSuggestion:self.currentResult[indexPath.row]
                               incognito:self.incognito];
+  cell.delegate = self;
 
   return cell;
 }
 
+#pragma mark - OmniboxPopupRowCellDelegate
+
+- (void)trailingButtonTappedForCell:(OmniboxPopupRowCell*)cell {
+  NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
+  [self.delegate autocompleteResultConsumer:self
+                 didTapTrailingButtonForRow:indexPath.row];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
index 535039e..24746c321 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
@@ -1234,9 +1234,7 @@
 
 // Check that stored entries are shown no matter what the preference for saving
 // passwords is.
-// TODO(crbug.com/944561): Disabled due to failing on first try consistently and
-// only passing on the retry.
-- (void)DISABLED_testStoredEntriesAlwaysShown {
+- (void)testStoredEntriesAlwaysShown {
   SaveExamplePasswordForm();
 
   PasswordForm blacklisted;
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.h b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.h
index 6489a44..111a324d 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.h
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.h
@@ -6,6 +6,7 @@
 #define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORDS_TABLE_VIEW_CONTROLLER_H_
 
 #import "ios/chrome/browser/ui/settings/password/password_details_table_view_controller_delegate.h"
+#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
 
 namespace ios {
@@ -21,7 +22,8 @@
 @protocol ReauthenticationProtocol;
 @class PasswordExporter;
 
-@interface PasswordsTableViewController : SettingsRootTableViewController
+@interface PasswordsTableViewController
+    : SettingsRootTableViewController <SettingsControllerProtocol>
 
 // The designated initializer. |browserState| must not be nil.
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
index 9898d0f..a97a6ac7 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -404,6 +404,17 @@
   return !savedForms_.empty() || !blacklistedForms_.empty();
 }
 
+#pragma mark - SettingsControllerProtocol
+
+- (void)settingsWillBeDismissed {
+  // Dismiss the search bar if presented, otherwise the VC will be retained by
+  // UIKit thus cause a memory leak.
+  // TODO(crbug.com/947417): Remove this once the memory leak issue is fixed.
+  if (self.navigationItem.searchController.active == YES) {
+    self.navigationItem.searchController.active = NO;
+  }
+}
+
 #pragma mark - Items
 
 - (TableViewLinkHeaderFooterItem*)manageAccountLinkItem {
diff --git a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.h b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.h
index a970f82f..1ebf442 100644
--- a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.h
+++ b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.h
@@ -131,6 +131,15 @@
               targetContentOffset:(inout CGPoint*)targetContentOffset
     NS_REQUIRES_SUPER;
 
+#pragma mark - UITableViewDelegate
+
+// Prevents non-editable (i.e. returns NO in |tableView:canEditRowAtIndexPath:|)
+// items from being selected in editing mode, otherwise they will not have radio
+// buttons ahead but still be selectable, which may cause a crash when trying to
+// delete items based on |self.tableView.indexPathsForSelectedRows|.
+- (NSIndexPath*)tableView:(UITableView*)tableView
+    willSelectRowAtIndexPath:(NSIndexPath*)indexPath NS_REQUIRES_SUPER;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CHROME_TABLE_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm
index 00dfc5a44..5dd6cb2 100644
--- a/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm
+++ b/ios/chrome/browser/ui/table_view/chrome_table_view_controller.mm
@@ -56,6 +56,44 @@
                           appBarStyle:ChromeTableViewControllerStyleNoAppBar];
 }
 
+#pragma mark - UIViewController
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+
+  [self.tableView setBackgroundColor:self.styler.tableViewBackgroundColor];
+  [self.tableView setSeparatorColor:self.styler.cellSeparatorColor];
+  [self.tableView
+      setSeparatorInset:UIEdgeInsetsMake(0, kTableViewSeparatorInsetWithIcon, 0,
+                                         0)];
+
+  // Configure the app bar if needed.
+  if (_appBarViewController) {
+    ConfigureAppBarViewControllerWithCardStyle(self.appBarViewController);
+    self.appBarViewController.headerView.trackingScrollView = self.tableView;
+    // Add the AppBar's views after all other views have been registered.
+    [self addChildViewController:_appBarViewController];
+    CGRect frame = self.appBarViewController.view.frame;
+    frame.origin.x = 0;
+    frame.size.width =
+        self.appBarViewController.parentViewController.view.bounds.size.width;
+    self.appBarViewController.view.frame = frame;
+    [self.view addSubview:self.appBarViewController.view];
+    [self.appBarViewController didMoveToParentViewController:self];
+  }
+}
+
+#pragma mark - UITableViewDelegate
+
+- (NSIndexPath*)tableView:(UITableView*)tableView
+    willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
+  if (self.editing && ![self tableView:tableView
+                          canEditRowAtIndexPath:indexPath]) {
+    return nil;
+  }
+  return indexPath;
+}
+
 #pragma mark - Accessors
 
 - (void)setStyler:(ChromeTableViewStyler*)styler {
@@ -86,31 +124,6 @@
   self.emptyView.scrollViewContentInsets = self.view.safeAreaInsets;
 }
 
-- (void)viewDidLoad {
-  [super viewDidLoad];
-
-  [self.tableView setBackgroundColor:self.styler.tableViewBackgroundColor];
-  [self.tableView setSeparatorColor:self.styler.cellSeparatorColor];
-  [self.tableView
-      setSeparatorInset:UIEdgeInsetsMake(0, kTableViewSeparatorInsetWithIcon, 0,
-                                         0)];
-
-  // Configure the app bar if needed.
-  if (_appBarViewController) {
-    ConfigureAppBarViewControllerWithCardStyle(self.appBarViewController);
-    self.appBarViewController.headerView.trackingScrollView = self.tableView;
-    // Add the AppBar's views after all other views have been registered.
-    [self addChildViewController:_appBarViewController];
-    CGRect frame = self.appBarViewController.view.frame;
-    frame.origin.x = 0;
-    frame.size.width =
-        self.appBarViewController.parentViewController.view.bounds.size.width;
-    self.appBarViewController.view.frame = frame;
-    [self.view addSubview:self.appBarViewController.view];
-    [self.appBarViewController didMoveToParentViewController:self];
-  }
-}
-
 - (void)startLoadingIndicatorWithLoadingMessage:(NSString*)loadingMessage {
   if (!self.loadingView) {
     self.loadingView =
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index 7ace51908..5763592 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -17,8 +17,11 @@
 const base::Feature kOmniboxPopupShortcutIconsInZeroState{
     "OmniboxPopupShortcutIconsInZeroState", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// TODO(crbug.com/945811): Using |-drawViewHierarchyInRect:afterScreenUpdates:|
+// has adverse flickering when taking a snapshot of the NTP while in the app
+// switcher.
 const base::Feature kSnapshotDrawView{"SnapshotDrawView",
-                                      base::FEATURE_ENABLED_BY_DEFAULT};
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kCopiedContentBehavior{"CopiedContentBehavior",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.mm b/ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.mm
index f37322c..43c3e4e 100644
--- a/ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.mm
+++ b/ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.mm
@@ -4,7 +4,7 @@
 
 #include "ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.h"
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "components/grit/components_resources.h"
 #include "components/password_manager/core/browser/password_manager_internals_service.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
diff --git a/ios/chrome/browser/ui/webui/signin_internals_ui_ios.cc b/ios/chrome/browser/ui/webui/signin_internals_ui_ios.cc
index eaee199..5cf165a0 100644
--- a/ios/chrome/browser/ui/webui/signin_internals_ui_ios.cc
+++ b/ios/chrome/browser/ui/webui/signin_internals_ui_ios.cc
@@ -4,7 +4,7 @@
 
 #include "ios/chrome/browser/ui/webui/signin_internals_ui_ios.h"
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "components/grit/components_resources.h"
 #include "components/signin/core/browser/about_signin_internals.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn
index f936550..519f816f 100644
--- a/ios/testing/BUILD.gn
+++ b/ios/testing/BUILD.gn
@@ -72,6 +72,7 @@
     "data/http_server_files/chromium_logo_page.html",
     "data/http_server_files/console.html",
     "data/http_server_files/console_with_iframe.html",
+    "data/http_server_files/context_menu.html",
     "data/http_server_files/destination.html",
     "data/http_server_files/fullscreen.html",
     "data/http_server_files/generic.pkpass",
@@ -94,6 +95,7 @@
     "data/http_server_files/single_page_wide.pdf",
     "data/http_server_files/state_operations.html",
     "data/http_server_files/state_operations.js",
+    "data/http_server_files/tall_page.html",
     "data/http_server_files/testpage.pdf",
     "data/http_server_files/two_pages.pdf",
     "data/http_server_files/user_agent_test_page.html",
diff --git a/ios/testing/data/http_server_files/context_menu.html b/ios/testing/data/http_server_files/context_menu.html
new file mode 100644
index 0000000..fb091d1
--- /dev/null
+++ b/ios/testing/data/http_server_files/context_menu.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+
+<!-- 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.
+
+This file contains elements for context menu test. -->
+
+<html>
+<body>
+  <div>
+    <a id="normal-link" href="/destination.html">normal-link-text</a>
+  </div>
+  <!-- mirror elements above with style="-webkit-touch-callout: none" -->
+  <div style="-webkit-touch-callout: none">
+    <a id="no-webkit-link" href="/destination.html" style="-webkit-touch-callout: none">no-webkit-link-text</a>
+  </div>
+</body>
+</html>
+
diff --git a/ios/web/shell/test/http_server_files/tall_page.html b/ios/testing/data/http_server_files/tall_page.html
similarity index 100%
rename from ios/web/shell/test/http_server_files/tall_page.html
rename to ios/testing/data/http_server_files/tall_page.html
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index f38d15cea..ef60a30e 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -67,7 +67,6 @@
     "service_manager_context.h",
     "service_manager_context.mm",
     "url_scheme_util.mm",
-    "url_util.cc",
     "web_browser_manifest.h",
     "web_browser_manifest.mm",
     "web_client.mm",
@@ -175,6 +174,7 @@
     ":ios_web_webui_unittests",
     "//ios/testing:http_server_bundle_data",
     "//ios/web/browsing_data:browsing_data_unittests",
+    "//ios/web/common:unittests",
     "//ios/web/download:download_unittests",
     "//ios/web/find_in_page:find_in_page_unittests",
     "//ios/web/interstitials:interstitials_unittests",
@@ -216,7 +216,6 @@
     "service_manager_connection_impl_unittest.cc",
     "test/web_test_unittest.mm",
     "url_scheme_util_unittest.mm",
-    "url_util_unittest.cc",
     "web_client_unittest.mm",
     "web_thread_unittest.cc",
   ]
diff --git a/ios/web/browsing_data/browsing_data_remover_unittest.mm b/ios/web/browsing_data/browsing_data_remover_unittest.mm
index f7fcc50..1f6c17ed 100644
--- a/ios/web/browsing_data/browsing_data_remover_unittest.mm
+++ b/ios/web/browsing_data/browsing_data_remover_unittest.mm
@@ -32,7 +32,16 @@
     NSHTTPCookieValue : @"value",
     NSHTTPCookieOriginURL : @"http://chromium.org"
   }];
+
+  // This is needed to forces the DataStore to be created, otherwise the cookie
+  // isn't set in some cases.
   __block bool cookie_set = false;
+  NSSet* data_types = [NSSet setWithObject:WKWebsiteDataTypeCookies];
+  [[WKWebsiteDataStore defaultDataStore]
+      fetchDataRecordsOfTypes:data_types
+            completionHandler:^(NSArray<WKWebsiteDataRecord*>* records){
+            }];
+
   [data_store.httpCookieStore setCookie:cookie
                       completionHandler:^{
                         cookie_set = true;
@@ -49,6 +58,15 @@
 bool HasCookies(bool should_have_cookies) {
   __block bool has_cookies = false;
   __block bool completion_called = false;
+
+  // This is needed to forces the DataStore to be created, otherwise the cookie
+  // isn't fetched in some cases.
+  NSSet* data_types = [NSSet setWithObject:WKWebsiteDataTypeCookies];
+  [[WKWebsiteDataStore defaultDataStore]
+      fetchDataRecordsOfTypes:data_types
+            completionHandler:^(NSArray<WKWebsiteDataRecord*>* records){
+            }];
+
   [[WKWebsiteDataStore defaultDataStore].httpCookieStore
       getAllCookies:^(NSArray<NSHTTPCookie*>* cookies) {
         has_cookies = cookies.count > 0;
@@ -115,13 +133,7 @@
 }
 
 // Tests that removing the cookies remove them from the cookie store.
-// TODO(crbug.com/940880): Fix this test on devices.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_RemoveCookie RemoveCookie
-#else
-#define MAYBE_RemoveCookie DISABLED_RemoveCookie
-#endif
-TEST_F(BrowsingDataRemoverTest, MAYBE_RemoveCookie) {
+TEST_F(BrowsingDataRemoverTest, RemoveCookie) {
   ASSERT_TRUE(AddCookie());
   ASSERT_TRUE(HasCookies(true));
 
@@ -133,13 +145,7 @@
 }
 
 // Tests that removing the anything but cookies leave the cookies in the store.
-// TODO(crbug.com/940880): Fix this test for devices.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_RemoveNothing RemoveNothing
-#else
-#define MAYBE_RemoveNothing DISABLED_RemoveNothing
-#endif
-TEST_F(BrowsingDataRemoverTest, MAYBE_RemoveNothing) {
+TEST_F(BrowsingDataRemoverTest, RemoveNothing) {
   ASSERT_TRUE(AddCookie());
   ASSERT_TRUE(HasCookies(true));
 
diff --git a/ios/web/common/BUILD.gn b/ios/web/common/BUILD.gn
index 1766611..d146abf 100644
--- a/ios/web/common/BUILD.gn
+++ b/ios/web/common/BUILD.gn
@@ -9,14 +9,30 @@
     "crw_content_view.h",
     "crw_web_view_content_view.h",
     "crw_web_view_content_view.mm",
+    "url_util.cc",
+    "url_util.h",
   ]
 
   deps = [
     "//base",
     "//ios/web/public:features",
+    "//url",
   ]
 
   libs = [ "UIKit.framework" ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
 }
+
+source_set("unittests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  deps = [
+    ":common",
+    "//testing/gtest",
+  ]
+
+  sources = [
+    "url_util_unittest.cc",
+  ]
+}
diff --git a/ios/web/url_util.cc b/ios/web/common/url_util.cc
similarity index 91%
rename from ios/web/url_util.cc
rename to ios/web/common/url_util.cc
index 4bd2172..e9af3e0 100644
--- a/ios/web/url_util.cc
+++ b/ios/web/common/url_util.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/web/public/url_util.h"
+#include "ios/web/common/url_util.h"
 
 namespace web {
 
diff --git a/ios/web/public/url_util.h b/ios/web/common/url_util.h
similarity index 76%
rename from ios/web/public/url_util.h
rename to ios/web/common/url_util.h
index 30b8d76d..fd9c12d 100644
--- a/ios/web/public/url_util.h
+++ b/ios/web/common/url_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_URL_UTIL_H_
-#define IOS_WEB_PUBLIC_URL_UTIL_H_
+#ifndef IOS_WEB_COMMON_URL_UTIL_H_
+#define IOS_WEB_COMMON_URL_UTIL_H_
 
 #include "url/gurl.h"
 
@@ -14,4 +14,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_URL_UTIL_H_
+#endif  // IOS_WEB_COMMON_URL_UTIL_H_
diff --git a/ios/web/url_util_unittest.cc b/ios/web/common/url_util_unittest.cc
similarity index 92%
rename from ios/web/url_util_unittest.cc
rename to ios/web/common/url_util_unittest.cc
index 720c515..e98fce33 100644
--- a/ios/web/url_util_unittest.cc
+++ b/ios/web/common/url_util_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/web/public/url_util.h"
+#include "ios/web/common/url_util.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/ios/web/features.mm b/ios/web/features.mm
index 99d4a8e..99dfa50c 100644
--- a/ios/web/features.mm
+++ b/ios/web/features.mm
@@ -44,7 +44,7 @@
     "BlockUniversalLinksInOffTheRecord", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kWebUISchemeHandling{"WebUISchemeHandling",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
+                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kKeepsRenderProcessAlive{"KeepsRenderProcessAlive",
                                              base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/web/net/BUILD.gn b/ios/web/net/BUILD.gn
index 825526a..a5c74b69 100644
--- a/ios/web/net/BUILD.gn
+++ b/ios/web/net/BUILD.gn
@@ -9,6 +9,7 @@
     "//base",
     "//ios/net",
     "//ios/web:core",
+    "//ios/web/common",
     "//ios/web/navigation:core",
     "//ios/web/navigation:navigation_manager_util",
     "//ios/web/navigation:wk_navigation_util",
diff --git a/ios/web/net/request_tracker_impl.mm b/ios/web/net/request_tracker_impl.mm
index 57742a43..09e04092 100644
--- a/ios/web/net/request_tracker_impl.mm
+++ b/ios/web/net/request_tracker_impl.mm
@@ -15,10 +15,10 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/task/post_task.h"
+#include "ios/web/common/url_util.h"
 #include "ios/web/history_state_util.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/certificate_policy_cache.h"
-#include "ios/web/public/url_util.h"
 #include "ios/web/public/web_task_traits.h"
 #include "ios/web/public/web_thread.h"
 #import "net/base/mac/url_conversions.h"
diff --git a/ios/web/public/BUILD.gn b/ios/web/public/BUILD.gn
index de2e3b2..690ebbe 100644
--- a/ios/web/public/BUILD.gn
+++ b/ios/web/public/BUILD.gn
@@ -59,7 +59,6 @@
     "url_scheme_util.h",
     "url_schemes.h",
     "url_schemes.mm",
-    "url_util.h",
     "web_client.h",
     "web_state/context_menu_params.h",
     "web_state/global_web_state_observer.h",
diff --git a/ios/web/shell/test/BUILD.gn b/ios/web/shell/test/BUILD.gn
index a52d68d..59263ee 100644
--- a/ios/web/shell/test/BUILD.gn
+++ b/ios/web/shell/test/BUILD.gn
@@ -27,23 +27,21 @@
     ":earl_grey_test_support",
     "//base",
     "//base/test:test_support",
+    "//ios/testing:http_server_bundle_data",
     "//ios/testing/earl_grey:earl_grey_support",
     "//ios/web",
     "//ios/web:earl_grey_test_support",
     "//ios/web/public/test",
     "//ios/web/public/test/fakes",
-    "//ios/web/public/test/http_server",
     "//ios/web/shell",
     "//ios/web/shell:shell_interfaces",
-    "//net",
+    "//net:test_support",
     "//services/service_manager/public/cpp",
     "//services/test/echo/public/mojom",
     "//services/test/user_id/public/mojom",
     "//url",
   ]
 
-  bundle_deps = [ ":bundle" ]
-
   configs += [ "//build/config/compiler:enable_arc" ]
 
   assert_no_deps = ios_assert_no_deps
@@ -61,7 +59,6 @@
     "//ios/web",
     "//ios/web:earl_grey_test_support",
     "//ios/web/public/test",
-    "//ios/web/public/test/http_server",
     "//ios/web/shell",
     "//testing/gtest:gtest",
     "//url",
@@ -93,17 +90,6 @@
   configs += [ "//build/config/compiler:enable_arc" ]
 }
 
-bundle_data("bundle") {
-  visibility = [ ":*" ]
-  sources = [
-    "http_server_files/tall_page.html",
-  ]
-  outputs = [
-    "{{bundle_resources_dir}}/{{source_root_relative_dir}}/" +
-        "{{source_file_part}}",
-  ]
-}
-
 ################################
 # EG2 targets.
 
@@ -127,7 +113,6 @@
   deps = [
     "//ios/testing/earl_grey:eg_test_support+eg2",
     "//ios/third_party/earl_grey2:test_lib",
-    "//ios/web/public/test/http_server",
   ]
 }
 
@@ -169,6 +154,4 @@
     # Test support libraries.
     ":eg_tests+eg2",
   ]
-
-  bundle_deps = [ ":bundle" ]
 }
diff --git a/ios/web/shell/test/context_menu_egtest.mm b/ios/web/shell/test/context_menu_egtest.mm
index a625841..091170452 100644
--- a/ios/web/shell/test/context_menu_egtest.mm
+++ b/ios/web/shell/test/context_menu_egtest.mm
@@ -10,8 +10,6 @@
 #import "base/ios/block_types.h"
 #import "ios/testing/earl_grey/matchers.h"
 #include "ios/web/public/test/element_selector.h"
-#import "ios/web/public/test/http_server/http_server.h"
-#include "ios/web/public/test/http_server/http_server_util.h"
 #import "ios/web/public/test/web_view_interaction_test_util.h"
 #import "ios/web/shell/test/app/web_shell_test_util.h"
 #include "ios/web/shell/test/app/web_view_interaction_test_util.h"
@@ -20,6 +18,7 @@
 #import "ios/web/shell/test/earl_grey/shell_matchers.h"
 #import "ios/web/shell/test/earl_grey/shell_matchers_shorthand.h"
 #import "ios/web/shell/test/earl_grey/web_shell_test_case.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -28,34 +27,38 @@
 using testing::ButtonWithAccessibilityLabel;
 using testing::ElementToDismissAlert;
 
+namespace {
+const char kHtmlFile[] =
+    "/ios/testing/data/http_server_files/context_menu.html";
+}
+
 // Context menu test cases for the web shell.
-@interface ContextMenuTestCase : WebShellTestCase
+@interface ContextMenuTestCase : WebShellTestCase {
+  net::EmbeddedTestServer _server;
+}
+
 @end
 
 @implementation ContextMenuTestCase
 
+- (void)setUp {
+  [super setUp];
+
+  _server.ServeFilesFromSourceDirectory(base::FilePath(FILE_PATH_LITERAL(".")));
+  GREYAssert(_server.Start(), @"EmbeddedTestServer failed to start.");
+}
+
 // Tests context menu appears on a regular link.
 - (void)testContextMenu {
-  // Create map of canned responses and set up the test HTML server.
-  std::map<GURL, std::string> responses;
-  GURL initialURL = web::test::HttpServer::MakeUrl("http://contextMenuOpen");
-  GURL destinationURL = web::test::HttpServer::MakeUrl("http://destination");
-  // The initial page contains a link to the destination URL.
-  std::string linkID = "link";
-  std::string linkText = "link for context menu";
-  responses[initialURL] =
-      "<body>"
-      "<a href='" +
-      destinationURL.spec() + "' id='" + linkID + "'>" + linkText +
-      "</a>"
-      "</span></body>";
+  const char linkID[] = "normal-link";
+  const char linkText[] = "normal-link-text";
+  const GURL pageURL = _server.GetURL(kHtmlFile);
 
-  web::test::SetUpSimpleHttpServer(responses);
-  bool success = [ShellEarlGrey loadURL:initialURL];
+  bool success = [ShellEarlGrey loadURL:pageURL];
   GREYAssert(success, @"Page did not complete loading.");
+
   success = [ShellEarlGrey waitForWebViewContainingText:linkText];
-  GREYAssert(success, @"Failed waiting for web view containing %s",
-             linkText.c_str());
+  GREYAssert(success, @"Failed waiting for web view containing '%s'", linkText);
 
   [[EarlGrey selectElementWithMatcher:web::WebView()]
       performAction:web::LongPressElementForContextMenu(
@@ -78,29 +81,14 @@
 // Tests context menu on element that has WebkitTouchCallout set to none from an
 // ancestor and overridden.
 - (void)testContextMenuWebkitTouchCalloutOverride {
-  // Create map of canned responses and set up the test HTML server.
-  std::map<GURL, std::string> responses;
-  GURL initialURL =
-      web::test::HttpServer::MakeUrl("http://contextMenuDisabledByWebkit");
-  GURL destinationURL = web::test::HttpServer::MakeUrl("http://destination");
-  // The initial page contains a link to the destination URL that has an
-  // ancestor that disables the context menu via -webkit-touch-callout.
-  std::string linkID = "link";
-  std::string linkText = "override no-callout link";
-  responses[initialURL] =
-      "<body style='-webkit-touch-callout: none'>"
-      "<a href='" +
-      destinationURL.spec() + "' style='-webkit-touch-callout: default' id='" +
-      linkID + "'>" + linkText +
-      "</a>"
-      "</body>";
+  const char linkID[] = "no-webkit-link";
+  const char linkText[] = "no-webkit-link-text";
+  const GURL pageURL = _server.GetURL(kHtmlFile);
 
-  web::test::SetUpSimpleHttpServer(responses);
-  bool success = [ShellEarlGrey loadURL:initialURL];
+  bool success = [ShellEarlGrey loadURL:pageURL];
   GREYAssert(success, @"Page did not complete loading.");
   success = [ShellEarlGrey waitForWebViewContainingText:linkText];
-  GREYAssert(success, @"Failed waiting for web view containing %s",
-             linkText.c_str());
+  GREYAssert(success, @"Failed waiting for web view containing '%s'", linkText);
 
   [[EarlGrey selectElementWithMatcher:web::WebView()]
       performAction:web::LongPressElementForContextMenu(
diff --git a/ios/web/shell/test/earl_grey/web_shell_test_case.mm b/ios/web/shell/test/earl_grey/web_shell_test_case.mm
index 8827aee..db56765 100644
--- a/ios/web/shell/test/earl_grey/web_shell_test_case.mm
+++ b/ios/web/shell/test/earl_grey/web_shell_test_case.mm
@@ -5,7 +5,6 @@
 #import "ios/web/shell/test/earl_grey/web_shell_test_case.h"
 
 #import "ios/testing/earl_grey/earl_grey_test.h"
-#import "ios/web/public/test/http_server/http_server.h"
 
 #if defined(CHROME_EARL_GREY_1)
 #include "testing/coverage_util_ios.h"  // nogncheck
@@ -15,8 +14,6 @@
 #error "This file requires ARC support."
 #endif
 
-using web::test::HttpServer;
-
 @implementation WebShellTestCase
 
 #if defined(CHROME_EARL_GREY_1)
@@ -42,23 +39,10 @@
 // Set up called once for the class.
 + (void)setUp {
   [super setUp];
-  HttpServer::GetSharedInstance().StartOrDie();
 
 #if defined(CHROME_EARL_GREY_1)
   coverage_util::ConfigureCoverageReportPath();
 #endif
 }
 
-// Tear down called once for the class.
-+ (void)tearDown {
-  HttpServer::GetSharedInstance().Stop();
-  [super tearDown];
-}
-
-// Tear down called after each test.
-- (void)tearDown {
-  HttpServer::GetSharedInstance().RemoveAllResponseProviders();
-  [super tearDown];
-}
-
 @end
diff --git a/ios/web/shell/test/page_state_egtest.mm b/ios/web/shell/test/page_state_egtest.mm
index 96865661..27e6af1 100644
--- a/ios/web/shell/test/page_state_egtest.mm
+++ b/ios/web/shell/test/page_state_egtest.mm
@@ -8,12 +8,11 @@
 #import <XCTest/XCTest.h>
 
 #include "base/strings/string_number_conversions.h"
-#import "ios/web/public/test/http_server/http_server.h"
-#include "ios/web/public/test/http_server/http_server_util.h"
 #import "ios/web/shell/test/earl_grey/shell_earl_grey.h"
 #import "ios/web/shell/test/earl_grey/shell_matchers.h"
 #import "ios/web/shell/test/earl_grey/shell_matchers_shorthand.h"
 #import "ios/web/shell/test/earl_grey/web_shell_test_case.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -21,11 +20,9 @@
 
 namespace {
 
-// URLs for test pages.
-const char kLongPage1[] =
-    "http://ios/web/shell/test/http_server_files/tall_page.html";
+const char kLongPage1[] = "/ios/testing/data/http_server_files/tall_page.html";
 const char kLongPage2[] =
-    "http://ios/web/shell/test/http_server_files/tall_page.html?2";
+    "/ios/testing/data/http_server_files/tall_page.html?2";
 
 // Test scroll offsets.
 const CGFloat kOffset1 = 20.0f;
@@ -68,28 +65,33 @@
 
 }  // namespace
 
-using web::test::HttpServer;
-
 // Page state test cases for the web shell.
-@interface PageStateTestCase : WebShellTestCase
+@interface PageStateTestCase : WebShellTestCase {
+  net::EmbeddedTestServer _server;
+}
 @end
 
 @implementation PageStateTestCase
 
+- (void)setUp {
+  [super setUp];
+
+  _server.ServeFilesFromSourceDirectory(base::FilePath(FILE_PATH_LITERAL(".")));
+  GREYAssert(_server.Start(), @"EmbeddedTestServer failed to start.");
+}
+
 // Tests that page scroll position of a page is restored upon returning to the
 // page via the back/forward buttons.
 - (void)testScrollPositionRestoring {
-  web::test::SetUpFileBasedHttpServer();
-
   // Scroll the first page and verify the offset.
-  ScrollLongPageToTop(HttpServer::MakeUrl(kLongPage1));
+  ScrollLongPageToTop(_server.GetURL(kLongPage1));
   [[EarlGrey selectElementWithMatcher:web::WebViewScrollView()]
       performAction:grey_scrollInDirection(kGREYDirectionDown, kOffset1)];
   [[EarlGrey selectElementWithMatcher:web::WebViewScrollView()]
       assertWithMatcher:grey_scrollViewContentOffset(CGPointMake(0, kOffset1))];
 
   // Scroll the second page and verify the offset.
-  ScrollLongPageToTop(HttpServer::MakeUrl(kLongPage2));
+  ScrollLongPageToTop(_server.GetURL(kLongPage2));
   [[EarlGrey selectElementWithMatcher:web::WebViewScrollView()]
       performAction:grey_scrollInDirection(kGREYDirectionDown, kOffset2)];
   [[EarlGrey selectElementWithMatcher:web::WebViewScrollView()]
@@ -112,8 +114,7 @@
 - (void)testZeroContentOffsetAfterLoad {
   EARL_GREY_TEST_DISABLED(@"Test disabled.");
   // Set up the file-based server to load the tall page.
-  const GURL baseURL = web::test::HttpServer::MakeUrl(kLongPage1);
-  web::test::SetUpFileBasedHttpServer();
+  const GURL baseURL = _server.GetURL(kLongPage1);
   bool success = [ShellEarlGrey loadURL:baseURL];
   GREYAssert(success, @"Page did not complete loading.");
 
diff --git a/ios/web/test/data/mojo_test.html b/ios/web/test/data/mojo_test.html
index ad9eb73..e1396283 100644
--- a/ios/web/test/data/mojo_test.html
+++ b/ios/web/test/data/mojo_test.html
@@ -1,7 +1,8 @@
 <!doctype html>
 <html>
 <head>
-  <script src="chrome://resources/js/ios/web_ui.js"></script>
+  <script src="testwebui://resources/js/ios/mojo_api.js"></script>
+  <script src="testwebui://resources/js/ios/web_ui.js"></script>
   <script src="mojo_bindings.js"></script>
   <script src="mojo_test.mojom.js"></script>
   <script src="mojo_test.js"></script>
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index e4fcdf6..1f29bf2 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -43,6 +43,7 @@
 #import "ios/net/http_response_headers_util.h"
 #import "ios/web/common/crw_content_view.h"
 #import "ios/web/common/crw_web_view_content_view.h"
+#include "ios/web/common/url_util.h"
 #import "ios/web/find_in_page/find_in_page_manager_impl.h"
 #include "ios/web/history_state_util.h"
 #import "ios/web/interstitials/web_interstitial_impl.h"
@@ -66,7 +67,6 @@
 #include "ios/web/public/referrer_util.h"
 #include "ios/web/public/ssl_status.h"
 #import "ios/web/public/url_scheme_util.h"
-#include "ios/web/public/url_util.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/context_menu_params.h"
 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
@@ -914,7 +914,8 @@
   if (!_mojoFacade) {
     service_manager::mojom::InterfaceProvider* interfaceProvider =
         self.webStateImpl->GetWebStateInterfaceProvider();
-    _mojoFacade.reset(new web::MojoFacade(interfaceProvider, self));
+    _mojoFacade =
+        std::make_unique<web::MojoFacade>(interfaceProvider, self.webState);
   }
   return _mojoFacade.get();
 }
@@ -1033,6 +1034,7 @@
   self.webStateImpl->CancelDialogs();
 
   _SSLStatusUpdater = nil;
+  _mojoFacade.reset();
 
   self.nativeProvider = nil;
   self.swipeRecognizerProvider = nil;
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index be3701e..cb5a553 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -14,6 +14,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #import "ios/web/common/crw_content_view.h"
+#include "ios/web/common/url_util.h"
 #import "ios/web/interstitials/web_interstitial_impl.h"
 #import "ios/web/navigation/crw_session_controller.h"
 #import "ios/web/navigation/legacy_navigation_manager_impl.h"
@@ -27,7 +28,6 @@
 #include "ios/web/public/favicon_url.h"
 #import "ios/web/public/java_script_dialog_presenter.h"
 #import "ios/web/public/navigation_item.h"
-#include "ios/web/public/url_util.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/context_menu_params.h"
 #import "ios/web/public/web_state/ui/crw_native_content.h"
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm
index 828262d6..62f271f 100644
--- a/ios/web/web_state/web_state_unittest.mm
+++ b/ios/web/web_state/web_state_unittest.mm
@@ -334,6 +334,12 @@
 // Verifies that large session can be restored. SlimNavigationManagder has max
 // session size limit of |wk_navigation_util::kMaxSessionSize|.
 TEST_P(WebStateTest, RestoreLargeSession) {
+// TODO(crbug.com/946898): Re-enable once fixed on device on iOS12.2
+#if !TARGET_IPHONE_SIMULATOR
+  UIUserInterfaceIdiom idiom = [[UIDevice currentDevice] userInterfaceIdiom];
+  if (idiom == UIUserInterfaceIdiomPhone)
+    return;
+#endif
   // Create session storage with large number of items.
   const int kItemCount = 150;
   NSMutableArray<CRWNavigationItemStorage*>* item_storages =
diff --git a/ios/web/webui/mojo_facade.h b/ios/web/webui/mojo_facade.h
index c8a528d..b6631b9 100644
--- a/ios/web/webui/mojo_facade.h
+++ b/ios/web/webui/mojo_facade.h
@@ -12,8 +12,6 @@
 #include "base/values.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 
-@protocol CRWJSInjectionEvaluator;
-
 namespace service_manager {
 namespace mojom {
 class InterfaceProvider;
@@ -22,15 +20,17 @@
 
 namespace web {
 
+class WebState;
+
 // Facade class for Mojo. All inputs and outputs are optimized for communication
 // with WebUI pages and hence use JSON format. Must be created used and
 // destroyed on UI thread.
 class MojoFacade {
  public:
   // Constructs MojoFacade. The calling code must retain the ownership of
-  // |interface_provider| and |script_evaluator|, both can not be null.
+  // |interface_provider| and |web_state|, both can not be null.
   MojoFacade(service_manager::mojom::InterfaceProvider* interface_provider,
-             id<CRWJSInjectionEvaluator> script_evaluator);
+             WebState* web_state);
   ~MojoFacade();
 
   // Handles Mojo message received from WebUI page. Returns a valid JSON string
@@ -115,7 +115,8 @@
   // Provides interfaces.
   service_manager::mojom::InterfaceProvider* interface_provider_;
   // Runs JavaScript on WebUI page.
-  __weak id<CRWJSInjectionEvaluator> script_evaluator_ = nil;
+  WebState* web_state_ = nil;
+  //  __weak id<CRWJSInjectionEvaluator> script_evaluator_ = nil;
   // Id of the last created watch.
   int last_watch_id_ = 0;
   // Currently active watches created through this facade.
diff --git a/ios/web/webui/mojo_facade.mm b/ios/web/webui/mojo_facade.mm
index 1197e2b..4c5429c 100644
--- a/ios/web/webui/mojo_facade.mm
+++ b/ios/web/webui/mojo_facade.mm
@@ -17,8 +17,9 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
-#import "ios/web/public/web_state/js/crw_js_injection_evaluator.h"
+#include "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_thread.h"
 #include "mojo/public/cpp/system/core.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom.h"
@@ -31,12 +32,11 @@
 
 MojoFacade::MojoFacade(
     service_manager::mojom::InterfaceProvider* interface_provider,
-    id<CRWJSInjectionEvaluator> script_evaluator)
-    : interface_provider_(interface_provider),
-      script_evaluator_(script_evaluator) {
+    WebState* web_state)
+    : interface_provider_(interface_provider), web_state_(web_state) {
   DCHECK_CURRENTLY_ON(WebThread::UI);
   DCHECK(interface_provider_);
-  DCHECK(script_evaluator_);
+  DCHECK(web_state_);
 }
 
 MojoFacade::~MojoFacade() {
@@ -223,7 +223,7 @@
             stringWithFormat:
                 @"Mojo.internal.watchCallbacksHolder.callCallback(%d, %d)",
                 callback_id, result];
-        [script_evaluator_ executeJavaScript:script completionHandler:nil];
+        web_state_->ExecuteJavaScript(base::SysNSStringToUTF16(script));
       },
       *callback_id);
   auto watcher = std::make_unique<mojo::SimpleWatcher>(
diff --git a/ios/web/webui/mojo_facade_unittest.mm b/ios/web/webui/mojo_facade_unittest.mm
index f3640e93..55fcb4d 100644
--- a/ios/web/webui/mojo_facade_unittest.mm
+++ b/ios/web/webui/mojo_facade_unittest.mm
@@ -7,22 +7,25 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/web_test.h"
-#import "ios/web/public/web_state/js/crw_js_injection_evaluator.h"
 #include "ios/web/public/web_state/web_state_interface_provider.h"
 #include "ios/web/test/mojo_test.mojom.h"
 #include "ios/web/web_state/web_state_impl.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #import "testing/gtest_mac.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+using base::test::ios::kWaitForJSCompletionTimeout;
+using base::test::ios::WaitUntilConditionOrTimeout;
+
 namespace web {
 
 namespace {
@@ -46,6 +49,31 @@
                                            error:nil];
 }
 
+class FakeWebState : public TestWebState {
+ public:
+  void SetWatchId(int watch_id) { watch_id_ = watch_id; }
+
+  void SetFacade(MojoFacade* facade) { facade_ = facade; }
+
+  void ExecuteJavaScript(const base::string16& javascript) override {
+    TestWebState::ExecuteJavaScript(javascript);
+    // Cancel the watch immediately to ensure there are no additional
+    // notifications.
+    // NOTE: This must be done as a side effect of executing the JavaScript.
+    NSDictionary* cancel_watch = @{
+      @"name" : @"MojoWatcher.cancel",
+      @"args" : @{
+        @"watchId" : @(watch_id_),
+      },
+    };
+    EXPECT_TRUE(facade_->HandleMojoMessage(GetJson(cancel_watch)).empty());
+  }
+
+ private:
+  int watch_id_;
+  MojoFacade* facade_;  // weak
+};
+
 }  // namespace
 
 // A test fixture to test MojoFacade class.
@@ -55,14 +83,12 @@
     interface_provider_ = std::make_unique<WebStateInterfaceProvider>();
     interface_provider_->registry()->AddInterface(base::Bind(
         &MojoFacadeTest::BindTestUIHandlerMojoRequest, base::Unretained(this)));
-    evaluator_ =
-        [OCMockObject mockForProtocol:@protocol(CRWJSInjectionEvaluator)];
-    facade_ = std::make_unique<MojoFacade>(
-        interface_provider_.get(),
-        static_cast<id<CRWJSInjectionEvaluator>>(evaluator_));
+    facade_ =
+        std::make_unique<MojoFacade>(interface_provider_.get(), &web_state_);
+    web_state_.SetFacade(facade_.get());
   }
 
-  OCMockObject* evaluator() { return evaluator_; }
+  FakeWebState* web_state() { return &web_state_; }
   MojoFacade* facade() { return facade_.get(); }
 
   void CreateMessagePipe(uint32_t* handle0, uint32_t* handle1) {
@@ -97,7 +123,7 @@
   void BindTestUIHandlerMojoRequest(TestUIHandlerMojoRequest request) {}
 
   std::unique_ptr<WebStateInterfaceProvider> interface_provider_;
-  OCMockObject* evaluator_;
+  FakeWebState web_state_;
   std::unique_ptr<MojoFacade> facade_;
 };
 
@@ -151,27 +177,7 @@
   int watch_id = 0;
   EXPECT_TRUE(base::StringToInt(watch_id_as_string, &watch_id));
 
-  // Start waiting for the watch callback.
-  __block bool callback_received = false;
-  NSString* expected_script =
-      [NSString stringWithFormat:
-                    @"Mojo.internal.watchCallbacksHolder.callCallback(%d, %d)",
-                    callback_id, MOJO_RESULT_OK];
-  [[[evaluator() expect] andDo:^(NSInvocation*) {
-    callback_received = true;
-
-    // Cancel the watch immediately to ensure there are no additional
-    // notifications.
-    NSDictionary* cancel_watch = @{
-      @"name" : @"MojoWatcher.cancel",
-      @"args" : @{
-        @"watchId" : @(watch_id),
-      },
-    };
-    std::string result_as_string =
-        facade()->HandleMojoMessage(GetJson(cancel_watch));
-    EXPECT_TRUE(result_as_string.empty());
-  }] executeJavaScript:expected_script completionHandler:nil];
+  web_state()->SetWatchId(watch_id);
 
   // Write to the other end of the pipe.
   NSDictionary* write = @{
@@ -185,11 +191,18 @@
   EXPECT_TRUE(base::StringToInt(result_as_string, &result));
   EXPECT_EQ(MOJO_RESULT_OK, static_cast<MojoResult>(result));
 
-  base::test::ios::WaitUntilCondition(
-      ^{
-        return callback_received;
-      },
-      true, base::TimeDelta());
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^bool {
+    base::RunLoop().RunUntilIdle();
+    return !web_state()->GetLastExecutedJavascript().empty();
+  }));
+
+  NSString* expected_script =
+      [NSString stringWithFormat:
+                    @"Mojo.internal.watchCallbacksHolder.callCallback(%d, %d)",
+                    callback_id, MOJO_RESULT_OK];
+
+  EXPECT_EQ(base::SysNSStringToUTF16(expected_script),
+            web_state()->GetLastExecutedJavascript());
 
   CloseHandle(handle0);
   CloseHandle(handle1);
diff --git a/ios/web/webui/web_ui_ios_controller_factory_registry.mm b/ios/web/webui/web_ui_ios_controller_factory_registry.mm
index 92dcb9d..34926557 100644
--- a/ios/web/webui/web_ui_ios_controller_factory_registry.mm
+++ b/ios/web/webui/web_ui_ios_controller_factory_registry.mm
@@ -46,7 +46,7 @@
 
 NSInteger WebUIIOSControllerFactoryRegistry::GetErrorCodeForWebUIURL(
     const GURL& url) const {
-  NSInteger error_code = NSURLErrorUnknown;
+  NSInteger error_code = NSURLErrorUnsupportedURL;
   for (WebUIIOSControllerFactory* factory : GetGlobalFactories()) {
     error_code = factory->GetErrorCodeForWebUIURL(url);
     if (error_code == 0)
diff --git a/ios/web/webui/web_ui_mojo_inttest.mm b/ios/web/webui/web_ui_mojo_inttest.mm
index 21681f4d..cf777e7 100644
--- a/ios/web/webui/web_ui_mojo_inttest.mm
+++ b/ios/web/webui/web_ui_mojo_inttest.mm
@@ -134,7 +134,7 @@
   NSInteger GetErrorCodeForWebUIURL(const GURL& url) const override {
     if (url.SchemeIs(kTestWebUIScheme))
       return 0;
-    return NSURLErrorUnknown;
+    return NSURLErrorUnsupportedURL;
   }
 
  private:
diff --git a/media/base/bit_reader_fuzzertest.cc b/media/base/bit_reader_fuzzertest.cc
index 7056e00b..cb6205b 100644
--- a/media/base/bit_reader_fuzzertest.cc
+++ b/media/base/bit_reader_fuzzertest.cc
@@ -5,7 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/numerics/safe_conversions.h"
 #include "media/base/bit_reader.h"
 #include "media/base/test_random.h"
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 05c9392..794290d 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -96,10 +96,11 @@
 // or <path>%noloop to stop after playing the file to completion.
 const char kUseFileForFakeAudioCapture[] = "use-file-for-fake-audio-capture";
 
-// Use fake device for accelerated decoding of JPEG. This allows, for example,
-// testing of the communication to the GPU service without requiring actual
-// accelerator hardware to be present.
-const char kUseFakeJpegDecodeAccelerator[] = "use-fake-jpeg-decode-accelerator";
+// Use a fake device for accelerated decoding of MJPEG. This allows, for
+// example, testing of the communication to the GPU service without requiring
+// actual accelerator hardware to be present.
+const char kUseFakeMjpegDecodeAccelerator[] =
+    "use-fake-mjpeg-decode-accelerator";
 
 // Disable hardware acceleration of mjpeg decode for captured frame, where
 // available.
@@ -257,10 +258,6 @@
 const base::Feature kD3D11VideoDecoderIgnoreWorkarounds{
     "D3D11VideoDecoderIgnoreWorkarounds", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enable usage of dav1d for AV1 video decoding.
-const base::Feature kDav1dVideoDecoder{"Dav1dVideoDecoder",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Falls back to other decoders after audio/video decode error happens. The
 // implementation may choose different strategies on when to fallback. See
 // DecoderStream for details. When disabled, playback will fail immediately
@@ -500,7 +497,7 @@
     return false;
   }
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kUseFakeJpegDecodeAccelerator)) {
+          switches::kUseFakeMjpegDecodeAccelerator)) {
     return true;
   }
 #if defined(OS_CHROMEOS)
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index dff654d..de8f2bc 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -59,7 +59,7 @@
 MEDIA_EXPORT extern const char kUseFakeDeviceForMediaStream[];
 MEDIA_EXPORT extern const char kUseFileForFakeVideoCapture[];
 MEDIA_EXPORT extern const char kUseFileForFakeAudioCapture[];
-MEDIA_EXPORT extern const char kUseFakeJpegDecodeAccelerator[];
+MEDIA_EXPORT extern const char kUseFakeMjpegDecodeAccelerator[];
 MEDIA_EXPORT extern const char kDisableAcceleratedMjpegDecode[];
 
 MEDIA_EXPORT extern const char kRequireAudioHardwareForTesting[];
@@ -101,7 +101,6 @@
 MEDIA_EXPORT extern const base::Feature kBackgroundVideoPauseOptimization;
 MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoder;
 MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoderIgnoreWorkarounds;
-MEDIA_EXPORT extern const base::Feature kDav1dVideoDecoder;
 MEDIA_EXPORT extern const base::Feature kExternalClearKeyForTesting;
 MEDIA_EXPORT extern const base::Feature kFallbackAfterDecodeError;
 MEDIA_EXPORT extern const base::Feature kHardwareMediaKeyHandling;
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index 813c8042..dd54aa2 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -14,9 +14,9 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/memory/aligned_memory.h"
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/shared_memory.h"
diff --git a/media/blink/multibuffer.h b/media/blink/multibuffer.h
index 987326f..96d6f204 100644
--- a/media/blink/multibuffer.h
+++ b/media/blink/multibuffer.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <functional>
 #include <limits>
 #include <map>
 #include <memory>
@@ -16,7 +17,7 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
diff --git a/media/capabilities/learning_helper.cc b/media/capabilities/learning_helper.cc
index 824c422..d40815a0 100644
--- a/media/capabilities/learning_helper.cc
+++ b/media/capabilities/learning_helper.cc
@@ -27,10 +27,22 @@
 // Dropped frame ratio, default+FeatureLibrary features, regression tree.
 const char* const kDroppedFrameRatioEnhancedTreeTaskName =
     "DroppedFrameRatioEnhancedTreeTask";
+// Dropped frame ratio, default+FeatureLibrary features, regression tree,
+// examples are unweighted.
+const char* const kDroppedFrameRatioEnhancedUnweightedTreeTaskName =
+    "DroppedFrameRatioEnhancedUnweightedTreeTask";
+// Binary smoothness, default+FeatureLibrary features, regression tree,
+// examples are unweighted.
+const char* const kBinarySmoothnessEnhancedUnweightedTreeTaskName =
+    "BinarySmoothnessTreeTask";
 // Dropped frame ratio, default features, lookup table.
 const char* const kDroppedFrameRatioBaseTableTaskName =
     "DroppedFrameRatioBaseTableTask";
 
+// Threshold for the dropped frame to total frame ratio, at which we'll decide
+// that the playback was not smooth.
+constexpr double kSmoothnessThreshold = 0.1;
+
 LearningHelper::LearningHelper(FeatureProviderFactoryCB feature_factory) {
   // Create the LearningSession on a background task runner.  In the future,
   // it's likely that the session will live on the main thread, and handle
@@ -57,6 +69,8 @@
       LearningTask::ValueDescription(
           {"dropped_ratio", LearningTask::Ordering::kNumeric}));
 
+  dropped_frame_task.smoothness_threshold = kSmoothnessThreshold;
+
   // Enable hacky reporting of accuracy.
   dropped_frame_task.uma_hacky_confusion_matrix =
       "Media.Learning.MediaCapabilities.DroppedFrameRatioTask.BaseTable";
@@ -90,6 +104,40 @@
                                     feature_factory.Run(dropped_frame_task));
     enhanced_tree_controller_ =
         learning_session_->GetController(dropped_frame_task.name);
+
+    // Duplicate the task with a new name and UMA histogram.  We'll add
+    // unweighted examples to it to see which one does better.
+    dropped_frame_task.name = kDroppedFrameRatioEnhancedUnweightedTreeTaskName;
+    dropped_frame_task.uma_hacky_confusion_matrix =
+        "Media.Learning.MediaCapabilities.DroppedFrameRatioTask."
+        "EnhancedUnweightedTree";
+    learning_session_->RegisterTask(dropped_frame_task,
+                                    feature_factory.Run(dropped_frame_task));
+    unweighted_tree_controller_ =
+        learning_session_->GetController(dropped_frame_task.name);
+
+    // Set up the binary smoothness task.  This has a nominal target, with
+    // "smooth" as 0, and "not smooth" as 1.  This is so that the low numbers
+    // are still smooth, and the hight numbers are still not smooth.  It makes
+    // reporting the same for both.
+    dropped_frame_task.name = kBinarySmoothnessEnhancedUnweightedTreeTaskName;
+    /* TODO(liberato): DistributionReporter only supports regression, so we
+       leave it as kNumeric.  Since we only add 0,1 as targets, it's probably
+       fairly close to the same thing.
+    dropped_frame_task.target_description = {
+        "is_smooth", ::media::learning::LearningTask::Ordering::kUnordered};
+    */
+    dropped_frame_task.uma_hacky_confusion_matrix =
+        "Media.Learning.MediaCapabilities.DroppedFrameRatioTask."
+        "BinarySmoothnessTree";
+    // We'll threshold the ratio when figuring out the binary label, so we just
+    // want to pick the majority.  Note that I have no idea if this is actually
+    // the best threshold, but it seems like a good place to start.
+    dropped_frame_task.smoothness_threshold = 0.5;
+    learning_session_->RegisterTask(dropped_frame_task,
+                                    feature_factory.Run(dropped_frame_task));
+    binary_tree_controller_ =
+        learning_session_->GetController(dropped_frame_task.name);
   }
 }
 
@@ -115,7 +163,6 @@
   example.features.push_back(FeatureValue(video_key.size.width()));
   example.features.push_back(FeatureValue(video_key.size.height()));
   example.features.push_back(FeatureValue(video_key.frame_rate));
-  // TODO(liberato): Other features?
 
   // Record the ratio of dropped frames to non-dropped frames.  Weight this
   // example by the total number of frames, since we want to predict the
@@ -136,6 +183,15 @@
   if (enhanced_tree_controller_) {
     example.features.push_back(origin);
     AddExample(enhanced_tree_controller_.get(), example);
+
+    // Also add to the unweighted model.
+    example.weight = 1u;
+    AddExample(unweighted_tree_controller_.get(), example);
+
+    // Threshold the target to 0 for "smooth", and 1 for "not smooth".
+    example.target_value =
+        TargetValue(example.target_value.value() > kSmoothnessThreshold);
+    AddExample(binary_tree_controller_.get(), example);
   }
 }
 
diff --git a/media/capabilities/learning_helper.h b/media/capabilities/learning_helper.h
index d8b5506..32bf9cb0 100644
--- a/media/capabilities/learning_helper.h
+++ b/media/capabilities/learning_helper.h
@@ -48,6 +48,8 @@
   std::unique_ptr<learning::LearningTaskController> base_table_controller_;
   std::unique_ptr<learning::LearningTaskController> base_tree_controller_;
   std::unique_ptr<learning::LearningTaskController> enhanced_tree_controller_;
+  std::unique_ptr<learning::LearningTaskController> unweighted_tree_controller_;
+  std::unique_ptr<learning::LearningTaskController> binary_tree_controller_;
 };
 
 }  // namespace media
diff --git a/media/cast/net/rtcp/sender_rtcp_session.h b/media/cast/net/rtcp/sender_rtcp_session.h
index 0131bc3..08ec817 100644
--- a/media/cast/net/rtcp/sender_rtcp_session.h
+++ b/media/cast/net/rtcp/sender_rtcp_session.h
@@ -10,7 +10,7 @@
 #include <utility>
 
 #include "base/containers/queue.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/time/time.h"
 #include "media/cast/net/cast_transport.h"
 #include "media/cast/net/pacing/paced_sender.h"
diff --git a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
index f568983..fc984ef 100644
--- a/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc
@@ -36,6 +36,10 @@
 #include "media/filters/aom_video_decoder.h"
 #endif
 
+#if BUILDFLAG(ENABLE_DAV1D_DECODER)
+#include "media/filters/dav1d_video_decoder.h"
+#endif
+
 #if BUILDFLAG(ENABLE_FFMPEG)
 #include "media/filters/ffmpeg_video_decoder.h"
 #endif
@@ -300,7 +304,10 @@
     video_decoder.reset(new VpxVideoDecoder());
 #endif
 
-#if BUILDFLAG(ENABLE_LIBAOM_DECODER)
+#if BUILDFLAG(ENABLE_DAV1D_DECODER)
+  if (config.codec == cdm::kCodecAv1)
+    video_decoder.reset(new Dav1dVideoDecoder(null_media_log.get()));
+#elif BUILDFLAG(ENABLE_LIBAOM_DECODER)
   if (config.codec == cdm::kCodecAv1)
     video_decoder.reset(new AomVideoDecoder(null_media_log.get()));
 #endif
diff --git a/media/device_monitors/device_monitor_udev.cc b/media/device_monitors/device_monitor_udev.cc
index 99f149b..8b6ec21 100644
--- a/media/device_monitors/device_monitor_udev.cc
+++ b/media/device_monitors/device_monitor_udev.cc
@@ -39,10 +39,10 @@
 // Wraps a device::UdevLinux with an API that makes it easier to use from
 // DeviceMonitorLinux. Since it is essentially a wrapper around blocking udev
 // calls, Initialize() must be called from a task runner that can block.
-class DeviceMonitorLinux::BlockingTaskHelper {
+class DeviceMonitorLinux::BlockingTaskRunnerHelper {
  public:
-  BlockingTaskHelper();
-  ~BlockingTaskHelper() = default;
+  BlockingTaskRunnerHelper();
+  ~BlockingTaskRunnerHelper() = default;
 
   void Initialize();
 
@@ -53,16 +53,16 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
-  DISALLOW_COPY_AND_ASSIGN(BlockingTaskHelper);
+  DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunnerHelper);
 };
 
-DeviceMonitorLinux::BlockingTaskHelper::BlockingTaskHelper() {
+DeviceMonitorLinux::BlockingTaskRunnerHelper::BlockingTaskRunnerHelper() {
   // Detaches from the sequence on which this object was created. It will be
   // bound to its owning sequence when Initialize() is called.
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
-void DeviceMonitorLinux::BlockingTaskHelper::Initialize() {
+void DeviceMonitorLinux::BlockingTaskRunnerHelper::Initialize() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   std::vector<device::UdevLinux::UdevMonitorFilter> filters;
   for (const SubsystemMap& entry : kSubsystemMap) {
@@ -70,11 +70,11 @@
         device::UdevLinux::UdevMonitorFilter(entry.subsystem, entry.devtype));
   }
   udev_ = std::make_unique<device::UdevLinux>(
-      filters, base::BindRepeating(&BlockingTaskHelper::OnDevicesChanged,
+      filters, base::BindRepeating(&BlockingTaskRunnerHelper::OnDevicesChanged,
                                    base::Unretained(this)));
 }
 
-void DeviceMonitorLinux::BlockingTaskHelper::OnDevicesChanged(
+void DeviceMonitorLinux::BlockingTaskRunnerHelper::OnDevicesChanged(
     udev_device* device) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(device);
@@ -99,14 +99,14 @@
     : blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
-      blocking_task_helper_(new BlockingTaskHelper,
+      blocking_task_helper_(new BlockingTaskRunnerHelper,
                             base::OnTaskRunnerDeleter(blocking_task_runner_)) {
   // Unretained() is safe because the deletion of |blocking_task_helper_|
   // is scheduled on |blocking_task_runner_| when DeviceMonitorLinux is
   // deleted.
   blocking_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(&DeviceMonitorLinux::BlockingTaskHelper::Initialize,
+      base::BindOnce(&DeviceMonitorLinux::BlockingTaskRunnerHelper::Initialize,
                      base::Unretained(blocking_task_helper_.get())));
 }
 
diff --git a/media/device_monitors/device_monitor_udev.h b/media/device_monitors/device_monitor_udev.h
index 1d302c2..270bbe7 100644
--- a/media/device_monitors/device_monitor_udev.h
+++ b/media/device_monitors/device_monitor_udev.h
@@ -25,13 +25,14 @@
   // DeviceMonitorMac to reduce startup impact time.
 
  private:
-  class BlockingTaskHelper;
+  class BlockingTaskRunnerHelper;
 
   // Task for running udev code that can potentially block.
   const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
 
-  // Holds the BlockingTaskHelper which runs tasks on |blocking_task_runner_|.
-  std::unique_ptr<BlockingTaskHelper, base::OnTaskRunnerDeleter>
+  // Holds the BlockingTaskRunnerHelper which runs tasks on
+  // |blocking_task_runner_|.
+  std::unique_ptr<BlockingTaskRunnerHelper, base::OnTaskRunnerDeleter>
       blocking_task_helper_;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceMonitorLinux);
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 473713f..679bd13c 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -4,8 +4,8 @@
 
 #include "media/ffmpeg/ffmpeg_common.h"
 
+#include "base/hash/sha1.h"
 #include "base/logging.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index f026f02..7d95ed0 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -11,8 +11,8 @@
 #include "base/bind_helpers.h"
 #include "base/containers/circular_deque.h"
 #include "base/format_macros.h"
+#include "base/hash/md5.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
diff --git a/media/filters/audio_file_reader_unittest.cc b/media/filters/audio_file_reader_unittest.cc
index 360ea6e7..11b1931 100644
--- a/media/filters/audio_file_reader_unittest.cc
+++ b/media/filters/audio_file_reader_unittest.cc
@@ -6,9 +6,9 @@
 
 #include <memory>
 
+#include "base/hash/md5.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "build/build_config.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_hash.h"
diff --git a/media/filters/audio_video_metadata_extractor_unittest.cc b/media/filters/audio_video_metadata_extractor_unittest.cc
index 7e5793a..237ee48 100644
--- a/media/filters/audio_video_metadata_extractor_unittest.cc
+++ b/media/filters/audio_video_metadata_extractor_unittest.cc
@@ -6,8 +6,8 @@
 
 #include <memory>
 
+#include "base/hash/sha1.h"
 #include "base/logging.h"
-#include "base/sha1.h"
 #include "build/build_config.h"
 #include "media/base/test_data_util.h"
 #include "media/filters/file_data_source.h"
diff --git a/media/gpu/gpu_jpeg_decode_accelerator_factory.cc b/media/gpu/gpu_jpeg_decode_accelerator_factory.cc
index 58054601..dd91ba6d 100644
--- a/media/gpu/gpu_jpeg_decode_accelerator_factory.cc
+++ b/media/gpu/gpu_jpeg_decode_accelerator_factory.cc
@@ -75,7 +75,7 @@
 std::vector<GpuJpegDecodeAcceleratorFactory::CreateAcceleratorCB>
 GpuJpegDecodeAcceleratorFactory::GetAcceleratorFactories() {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kUseFakeJpegDecodeAccelerator)) {
+          switches::kUseFakeMjpegDecodeAccelerator)) {
     return {base::Bind(&CreateFakeMjpegDecodeAccelerator)};
   }
 
diff --git a/media/gpu/image_processor_test.cc b/media/gpu/image_processor_test.cc
index 76bbe76..1d03cdb 100644
--- a/media/gpu/image_processor_test.cc
+++ b/media/gpu/image_processor_test.cc
@@ -7,7 +7,7 @@
 #include <tuple>
 
 #include "base/files/file_path.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
 #include "build/build_config.h"
diff --git a/media/gpu/libyuv_image_processor.cc b/media/gpu/libyuv_image_processor.cc
index 2f826f10..247f5f3 100644
--- a/media/gpu/libyuv_image_processor.cc
+++ b/media/gpu/libyuv_image_processor.cc
@@ -137,20 +137,9 @@
   DCHECK(process_thread_.task_runner()->BelongsToCurrentThread());
   DVLOGF(4);
 
-  int result = libyuv::I420ToNV12(input_frame->data(VideoFrame::kYPlane),
-                                  input_frame->stride(VideoFrame::kYPlane),
-                                  input_frame->data(VideoFrame::kUPlane),
-                                  input_frame->stride(VideoFrame::kUPlane),
-                                  input_frame->data(VideoFrame::kVPlane),
-                                  input_frame->stride(VideoFrame::kVPlane),
-                                  output_frame->data(VideoFrame::kYPlane),
-                                  output_frame->stride(VideoFrame::kYPlane),
-                                  output_frame->data(VideoFrame::kUVPlane),
-                                  output_frame->stride(VideoFrame::kUVPlane),
-                                  output_frame->visible_rect().width(),
-                                  output_frame->visible_rect().height());
-  if (result != 0) {
-    VLOGF(1) << "libyuv::I420ToNV12 returns non-zero code: " << result;
+  int res = DoConversion(input_frame.get(), output_frame.get());
+  if (res != 0) {
+    VLOGF(1) << "libyuv::I420ToNV12 returns non-zero code: " << res;
     NotifyError();
     return;
   }
@@ -172,18 +161,56 @@
 // static
 bool LibYUVImageProcessor::IsFormatSupported(VideoPixelFormat input_format,
                                              VideoPixelFormat output_format) {
-  if (input_format == PIXEL_FORMAT_I420) {
-    if (output_format == PIXEL_FORMAT_NV12) {
+  constexpr struct {
+    VideoPixelFormat input;
+    VideoPixelFormat output;
+  } kSupportFormatConversionArray[] = {
+      {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12},
+  };
+
+  for (auto* conv = std::cbegin(kSupportFormatConversionArray);
+       conv != std::cend(kSupportFormatConversionArray); conv++) {
+    if (conv->input == input_format && conv->output == output_format)
       return true;
-    } else {
-      VLOGF(2) << "Unsupported output format: " << output_format
-               << " for converting input format: " << input_format;
-      return false;
-    }
-  } else {
-    VLOGF(2) << "Unsupported input format: " << input_format;
-    return false;
   }
+
+  VLOGF(2) << "Unsupported conversion: input=" << input_format
+           << ", output=" << output_format;
+  return false;
+}
+
+int LibYUVImageProcessor::DoConversion(const VideoFrame* const input,
+                                       VideoFrame* const output) {
+  DCHECK(process_thread_.task_runner()->BelongsToCurrentThread());
+
+#define Y_U_V_DATA(fr)                                                \
+  fr->data(VideoFrame::kYPlane), fr->stride(VideoFrame::kYPlane),     \
+      fr->data(VideoFrame::kUPlane), fr->stride(VideoFrame::kUPlane), \
+      fr->data(VideoFrame::kVPlane), fr->stride(VideoFrame::kVPlane)
+
+#define Y_UV_DATA(fr)                                             \
+  fr->data(VideoFrame::kYPlane), fr->stride(VideoFrame::kYPlane), \
+      fr->data(VideoFrame::kUVPlane), fr->stride(VideoFrame::kUVPlane)
+
+#define LIBYUV_FUNC(func, i, o)                      \
+  libyuv::func(i, o, output->visible_rect().width(), \
+               output->visible_rect().height())
+
+  if (output->format() == PIXEL_FORMAT_NV12) {
+    switch (input->format()) {
+      case PIXEL_FORMAT_I420:
+        return LIBYUV_FUNC(I420ToNV12, Y_U_V_DATA(input), Y_UV_DATA(output));
+      default:
+        VLOGF(1) << "Unexpected input format: " << input->format();
+        return -1;
+    }
+  }
+#undef Y_U_V_DATA
+#undef Y_UV_DATA
+#undef LIBYUV_FUNC
+
+  VLOGF(1) << "Unexpected output format: " << output->format();
+  return -1;
 }
 
 }  // namespace media
diff --git a/media/gpu/libyuv_image_processor.h b/media/gpu/libyuv_image_processor.h
index eec9a8b9..61ebe71a 100644
--- a/media/gpu/libyuv_image_processor.h
+++ b/media/gpu/libyuv_image_processor.h
@@ -73,6 +73,9 @@
   static bool IsFormatSupported(VideoPixelFormat input_format,
                                 VideoPixelFormat output_format);
 
+  // Execute Libyuv function for the conversion from |input| to |output|.
+  int DoConversion(const VideoFrame* const input, VideoFrame* const output);
+
   const gfx::Rect input_visible_rect_;
   const gfx::Rect output_visible_rect_;
 
diff --git a/media/gpu/test/image.cc b/media/gpu/test/image.cc
index 6585c9b5..6b5e64e5 100644
--- a/media/gpu/test/image.cc
+++ b/media/gpu/test/image.cc
@@ -7,8 +7,8 @@
 #include <memory>
 
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/json/json_reader.h"
-#include "base/md5.h"
 #include "base/values.h"
 #include "media/base/test_data_util.h"
 
diff --git a/media/gpu/test/video_frame_validator.cc b/media/gpu/test/video_frame_validator.cc
index 3248a15..88e627b2 100644
--- a/media/gpu/test/video_frame_validator.cc
+++ b/media/gpu/test/video_frame_validator.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/files/file.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/stringprintf.h"
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
index 7930e98..ba521cff 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -186,11 +186,12 @@
   scoped_refptr<VP8Picture> GetPicture(
       AcceleratedVideoEncoder::EncodeJob* job) override;
 
-  bool SubmitFrameParameters(
-      AcceleratedVideoEncoder::EncodeJob* job,
-      const VP8Encoder::EncodeParams& encode_params,
-      scoped_refptr<VP8Picture> pic,
-      const Vp8ReferenceFrameVector& ref_frames) override;
+  bool SubmitFrameParameters(AcceleratedVideoEncoder::EncodeJob* job,
+                             const VP8Encoder::EncodeParams& encode_params,
+                             scoped_refptr<VP8Picture> pic,
+                             const Vp8ReferenceFrameVector& ref_frames,
+                             const std::array<bool, kNumVp8ReferenceBuffers>&
+                                 ref_frames_used) override;
 
  private:
   VaapiVideoEncodeAccelerator* const vea_;
@@ -1051,7 +1052,8 @@
     AcceleratedVideoEncoder::EncodeJob* job,
     const VP8Encoder::EncodeParams& encode_params,
     scoped_refptr<VP8Picture> pic,
-    const Vp8ReferenceFrameVector& ref_frames) {
+    const Vp8ReferenceFrameVector& ref_frames,
+    const std::array<bool, kNumVp8ReferenceBuffers>& ref_frames_used) {
   VAEncSequenceParameterBufferVP8 seq_param = {};
 
   const auto& frame_header = pic->frame_hdr;
@@ -1082,9 +1084,16 @@
                 : VA_INVALID_ID;
   pic_param.coded_buf = job->AsVaapiEncodeJob()->coded_buffer_id();
   DCHECK_NE(pic_param.coded_buf, VA_INVALID_ID);
+  pic_param.ref_flags.bits.no_ref_last =
+      !ref_frames_used[Vp8RefType::VP8_FRAME_LAST];
+  pic_param.ref_flags.bits.no_ref_gf =
+      !ref_frames_used[Vp8RefType::VP8_FRAME_GOLDEN];
+  pic_param.ref_flags.bits.no_ref_arf =
+      !ref_frames_used[Vp8RefType::VP8_FRAME_ALTREF];
 
-  if (frame_header->IsKeyframe())
+  if (frame_header->IsKeyframe()) {
     pic_param.ref_flags.bits.force_kf = true;
+  }
 
   pic_param.pic_flags.bits.frame_type = frame_header->frame_type;
   pic_param.pic_flags.bits.version = frame_header->version;
diff --git a/media/gpu/vaapi/vp8_encoder.cc b/media/gpu/vaapi/vp8_encoder.cc
index 5937b75..18440758 100644
--- a/media/gpu/vaapi/vp8_encoder.cc
+++ b/media/gpu/vaapi/vp8_encoder.cc
@@ -110,8 +110,19 @@
   UpdateFrameHeader(encode_job->IsKeyframeRequested());
   *picture->frame_hdr = current_frame_hdr_;
 
+  // We only use |last_frame| for a reference frame. This follows the behavior
+  // of libvpx encoder in chromium webrtc use case.
+  std::array<bool, kNumVp8ReferenceBuffers> ref_frames_used{true, false, false};
+
+  if (current_frame_hdr_.IsKeyframe()) {
+    // A driver should ignore |ref_frames_used| values if keyframe is requested.
+    // But we fill false in |ref_frames_used| just in case.
+    std::fill(std::begin(ref_frames_used), std::end(ref_frames_used), false);
+  }
+
   if (!accelerator_->SubmitFrameParameters(encode_job, current_params_, picture,
-                                           reference_frames_)) {
+                                           reference_frames_,
+                                           ref_frames_used)) {
     LOG(ERROR) << "Failed submitting frame parameters";
     return false;
   }
diff --git a/media/gpu/vaapi/vp8_encoder.h b/media/gpu/vaapi/vp8_encoder.h
index 77a30a7b..821b0c4 100644
--- a/media/gpu/vaapi/vp8_encoder.h
+++ b/media/gpu/vaapi/vp8_encoder.h
@@ -57,12 +57,14 @@
 
     // Initializes |job| to use the provided |encode_params| as its parameters,
     // and |pic| as the target, as well as |ref_frames| as reference frames for
-    // it. Returns true on success.
+    // it. |ref_frames_used| specifies which frames in |ref_frames| will be
+    // actually used as reference frames on encoding. Returns true on success.
     virtual bool SubmitFrameParameters(
         EncodeJob* job,
         const VP8Encoder::EncodeParams& encode_params,
         scoped_refptr<VP8Picture> pic,
-        const Vp8ReferenceFrameVector& ref_frames) = 0;
+        const Vp8ReferenceFrameVector& ref_frames,
+        const std::array<bool, kNumVp8ReferenceBuffers>& ref_frames_used) = 0;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(Accelerator);
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index 3ea3c1f..871b04f 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -34,9 +34,9 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
+#include "base/hash/md5.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/message_loop/message_loop.h"
 #include "base/process/process_handle.h"
 #include "base/run_loop.h"
diff --git a/media/learning/common/value.cc b/media/learning/common/value.cc
index 12ea399..caf94e0 100644
--- a/media/learning/common/value.cc
+++ b/media/learning/common/value.cc
@@ -4,7 +4,7 @@
 
 #include "media/learning/common/value.h"
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 
 namespace media {
 namespace learning {
diff --git a/media/media_options.gni b/media/media_options.gni
index 49d861e..4460ffc 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -84,12 +84,14 @@
   # are combined and we could override more logging than expected.
   enable_logging_override = !use_jumbo_build && is_chromecast
 
-  # Dav1d is only enabled when av1 decoding is enabled.
   if (is_win && target_cpu == "arm64") {
     # TODO: Enable dav1d for Windows ARM64. https://crbug.com/941022
     enable_dav1d_decoder = false
+  } else if (is_fuchsia && target_cpu == "x64") {
+    # TODO: Fix media_unittests for fuchsia X64. https://crbug.com/930300
+    enable_dav1d_decoder = false
   } else {
-    enable_dav1d_decoder = enable_libaom_decoder
+    enable_dav1d_decoder = !is_android && !is_ios
   }
 }
 
diff --git a/media/midi/midi_manager_usb.h b/media/midi/midi_manager_usb.h
index 49e6b17b..af436c6 100644
--- a/media/midi/midi_manager_usb.h
+++ b/media/midi/midi_manager_usb.h
@@ -14,7 +14,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/synchronization/lock.h"
 #include "base/time/time.h"
diff --git a/media/mojo/services/mojo_mjpeg_decode_accelerator_service_unittest.cc b/media/mojo/services/mojo_mjpeg_decode_accelerator_service_unittest.cc
index 1291bef..91403b4 100644
--- a/media/mojo/services/mojo_mjpeg_decode_accelerator_service_unittest.cc
+++ b/media/mojo/services/mojo_mjpeg_decode_accelerator_service_unittest.cc
@@ -27,7 +27,7 @@
 
   void SetUp() override {
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kUseFakeJpegDecodeAccelerator);
+        switches::kUseFakeMjpegDecodeAccelerator);
   }
 
   void OnInitializeDone(const base::Closure& continuation, bool success) {
diff --git a/media/mojo/services/watch_time_recorder.cc b/media/mojo/services/watch_time_recorder.cc
index 4602af2..d837bd2 100644
--- a/media/mojo/services/watch_time_recorder.cc
+++ b/media/mojo/services/watch_time_recorder.cc
@@ -7,7 +7,7 @@
 #include <algorithm>
 #include <cmath>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/string_piece.h"
 #include "media/base/limits.h"
diff --git a/media/mojo/services/watch_time_recorder_unittest.cc b/media/mojo/services/watch_time_recorder_unittest.cc
index c89ef8b..32fc1c2 100644
--- a/media/mojo/services/watch_time_recorder_unittest.cc
+++ b/media/mojo/services/watch_time_recorder_unittest.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/media/renderers/default_decoder_factory.cc b/media/renderers/default_decoder_factory.cc
index e293551..dd7fc88a 100644
--- a/media/renderers/default_decoder_factory.cc
+++ b/media/renderers/default_decoder_factory.cc
@@ -121,12 +121,7 @@
 #endif
 
 #if BUILDFLAG(ENABLE_DAV1D_DECODER)
-  if (base::FeatureList::IsEnabled(kDav1dVideoDecoder))
-    video_decoders->push_back(std::make_unique<Dav1dVideoDecoder>(media_log));
-#if BUILDFLAG(ENABLE_LIBAOM_DECODER)
-  else
-    video_decoders->push_back(std::make_unique<AomVideoDecoder>(media_log));
-#endif
+  video_decoders->push_back(std::make_unique<Dav1dVideoDecoder>(media_log));
 #elif BUILDFLAG(ENABLE_LIBAOM_DECODER)
   video_decoders->push_back(std::make_unique<AomVideoDecoder>(media_log));
 #endif
diff --git a/media/test/pipeline_integration_fuzzertest.cc b/media/test/pipeline_integration_fuzzertest.cc
index d38844ce..9d69367e 100644
--- a/media/test/pipeline_integration_fuzzertest.cc
+++ b/media/test/pipeline_integration_fuzzertest.cc
@@ -252,18 +252,6 @@
       media::ProgressivePipelineIntegrationFuzzerTest test;
       test.RunTest(data, size);
     }
-
-#if BUILDFLAG(ENABLE_DAV1D_DECODER)
-    {
-      // Rerun the test with the dav1d video decoder instead of libaom. Note:
-      // this ends up running for all SRC fuzzing and not just AV1 content, but
-      // that's true for our entire corpus.
-      base::test::ScopedFeatureList features_with_dav1d;
-      features_with_dav1d.InitAndEnableFeature(media::kDav1dVideoDecoder);
-      media::ProgressivePipelineIntegrationFuzzerTest test;
-      test.RunTest(data, size);
-    }
-#endif
   } else {
     // Sequentially fuzz with new and old MSE buffering APIs.  See
     // https://crbug.com/718641.
@@ -281,17 +269,6 @@
       media::MediaSourcePipelineIntegrationFuzzerTest test;
       test.RunTest(data, size, MseFuzzerVariantEnumToMimeTypeString(variant));
     }
-
-#if BUILDFLAG(ENABLE_DAV1D_DECODER)
-    // Rerun the test with the dav1d video decoder instead of libaom. No need to
-    // run with ByPts in both configurations, just use the default.
-    if (variant == MP4_AV1) {
-      base::test::ScopedFeatureList features_with_dav1d;
-      features_with_dav1d.InitAndEnableFeature(media::kDav1dVideoDecoder);
-      media::MediaSourcePipelineIntegrationFuzzerTest test;
-      test.RunTest(data, size, MseFuzzerVariantEnumToMimeTypeString(variant));
-    }
-#endif
   }
 
   return 0;
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index 33824a8..d1fb9701 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -74,12 +74,7 @@
 #endif
 
 #if BUILDFLAG(ENABLE_DAV1D_DECODER)
-  if (base::FeatureList::IsEnabled(kDav1dVideoDecoder))
-    video_decoders.push_back(std::make_unique<Dav1dVideoDecoder>(media_log));
-#if BUILDFLAG(ENABLE_LIBAOM_DECODER)
-  else
-    video_decoders.push_back(std::make_unique<AomVideoDecoder>(media_log));
-#endif
+  video_decoders.push_back(std::make_unique<Dav1dVideoDecoder>(media_log));
 #elif BUILDFLAG(ENABLE_LIBAOM_DECODER)
   video_decoders.push_back(std::make_unique<AomVideoDecoder>(media_log));
 #endif
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h
index c713390c..d84a4d79 100644
--- a/media/test/pipeline_integration_test_base.h
+++ b/media/test/pipeline_integration_test_base.h
@@ -9,7 +9,7 @@
 #include <memory>
 
 #include "base/callback_forward.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
diff --git a/mojo/core/ports/name.h b/mojo/core/ports/name.h
index 415ba65a..0dafee2 100644
--- a/mojo/core/ports/name.h
+++ b/mojo/core/ports/name.h
@@ -11,7 +11,7 @@
 #include <tuple>
 
 #include "base/component_export.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 
 namespace mojo {
 namespace core {
diff --git a/mojo/public/cpp/bindings/tests/rect_blink.h b/mojo/public/cpp/bindings/tests/rect_blink.h
index 7335989..3878191b 100644
--- a/mojo/public/cpp/bindings/tests/rect_blink.h
+++ b/mojo/public/cpp/bindings/tests/rect_blink.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_TESTS_RECT_BLINK_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_TESTS_RECT_BLINK_H_
 
+#include <functional>
+
 #include "base/logging.h"
 
 namespace mojo {
diff --git a/mojo/public/cpp/bindings/tests/rect_chromium.h b/mojo/public/cpp/bindings/tests/rect_chromium.h
index d2e0a3e..4092668 100644
--- a/mojo/public/cpp/bindings/tests/rect_chromium.h
+++ b/mojo/public/cpp/bindings/tests/rect_chromium.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_TESTS_RECT_CHROMIUM_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_TESTS_RECT_CHROMIUM_H_
 
+#include <functional>
+
 #include "base/logging.h"
 
 namespace mojo {
diff --git a/net/android/BUILD.gn b/net/android/BUILD.gn
index 5d8d756..816d03ca 100644
--- a/net/android/BUILD.gn
+++ b/net/android/BUILD.gn
@@ -171,9 +171,9 @@
     ":net_java_test_support",
     "//base:base_java",
     "//base:base_java_test_support",
+    "//third_party/android_sdk:android_test_mock_java",
     "//third_party/android_support_test_runner:rules_java",
     "//third_party/android_support_test_runner:runner_java",
-    "//third_party/android_tools:android_test_mock_java",
     "//third_party/junit",
     "//third_party/mockito:mockito_java",
   ]
diff --git a/net/cert/ct_objects_extractor.cc b/net/cert/ct_objects_extractor.cc
index 055fbdb..89478c30 100644
--- a/net/cert/ct_objects_extractor.cc
+++ b/net/cert/ct_objects_extractor.cc
@@ -6,8 +6,8 @@
 
 #include <string.h>
 
+#include "base/hash/sha1.h"
 #include "base/logging.h"
-#include "base/sha1.h"
 #include "base/strings/string_util.h"
 #include "crypto/sha2.h"
 #include "net/cert/asn1_util.h"
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc
index 007e437..bd42292 100644
--- a/net/cert/x509_certificate_unittest.cc
+++ b/net/cert/x509_certificate_unittest.cc
@@ -10,8 +10,8 @@
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/sha1.h"
 #include "base/pickle.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
diff --git a/net/data/websocket/README b/net/data/websocket/README
index ef9d896..515601e 100644
--- a/net/data/websocket/README
+++ b/net/data/websocket/README
@@ -47,6 +47,9 @@
      Used by kinds of PPAPI tests for WebSocket, ExtensionApiTest.WebSocket,
      and WorkerTest.WebSocketSharedWorker.
 
+- close-immediately_wsh.py : A WebSocket URL handler that performs an immediate
+     clean close as soon as the connection is established.
+
 - close_wsh.py : A WebSocket URL handler for testing outgoing close code and
      reason.
      Used by kinds of PPAPI tests for WebSocket.
diff --git a/net/data/websocket/close-immediately_wsh.py b/net/data/websocket/close-immediately_wsh.py
new file mode 100644
index 0000000..6cc08424
--- /dev/null
+++ b/net/data/websocket/close-immediately_wsh.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+def web_socket_do_extra_handshake(_request):
+  pass  # Always accept.
+
+
+def web_socket_transfer_data(_request):
+  pass  # Close immediately
diff --git a/net/disk_cache/blockfile/backend_impl.cc b/net/disk_cache/blockfile/backend_impl.cc
index b7af71b..bc53189 100644
--- a/net/disk_cache/blockfile/backend_impl.cc
+++ b/net/disk_cache/blockfile/backend_impl.cc
@@ -12,7 +12,7 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
diff --git a/net/disk_cache/blockfile/entry_impl.cc b/net/disk_cache/blockfile/entry_impl.cc
index dcbb28ac..4c9935a 100644
--- a/net/disk_cache/blockfile/entry_impl.cc
+++ b/net/disk_cache/blockfile/entry_impl.cc
@@ -6,7 +6,7 @@
 
 #include <limits>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/numerics/safe_math.h"
 #include "base/strings/string_util.h"
diff --git a/net/disk_cache/blockfile/storage_block-inl.h b/net/disk_cache/blockfile/storage_block-inl.h
index 784463e..0d7dea2 100644
--- a/net/disk_cache/blockfile/storage_block-inl.h
+++ b/net/disk_cache/blockfile/storage_block-inl.h
@@ -10,7 +10,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "net/disk_cache/blockfile/trace.h"
 
diff --git a/net/disk_cache/disk_cache_perftest.cc b/net/disk_cache/disk_cache_perftest.cc
index 8f30efe3..1f16e54 100644
--- a/net/disk_cache/disk_cache_perftest.cc
+++ b/net/disk_cache/disk_cache_perftest.cc
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/process/process_metrics.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
diff --git a/net/disk_cache/simple/simple_index_file.cc b/net/disk_cache/simple/simple_index_file.cc
index d6bfe32..287efee 100644
--- a/net/disk_cache/simple/simple_index_file.cc
+++ b/net/disk_cache/simple/simple_index_file.cc
@@ -11,7 +11,7 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/files/memory_mapped_file.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/pickle.h"
diff --git a/net/disk_cache/simple/simple_index_file_unittest.cc b/net/disk_cache/simple/simple_index_file_unittest.cc
index 001a9af..b8c4d57 100644
--- a/net/disk_cache/simple/simple_index_file_unittest.cc
+++ b/net/disk_cache/simple/simple_index_file_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/pickle.h"
diff --git a/net/disk_cache/simple/simple_index_unittest.cc b/net/disk_cache/simple/simple_index_unittest.cc
index 424e2c2f..375ce7d 100644
--- a/net/disk_cache/simple/simple_index_unittest.cc
+++ b/net/disk_cache/simple/simple_index_unittest.cc
@@ -11,7 +11,7 @@
 
 #include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_param_associator.h"
diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc
index 74d7045..a9903c5 100644
--- a/net/disk_cache/simple/simple_synchronous_entry.cc
+++ b/net/disk_cache/simple/simple_synchronous_entry.cc
@@ -12,7 +12,7 @@
 #include "base/compiler_specific.h"
 #include "base/containers/stack_container.h"
 #include "base/files/file_util.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial_params.h"
diff --git a/net/disk_cache/simple/simple_util.cc b/net/disk_cache/simple/simple_util.cc
index 5c1f5a7..41fc7e5 100644
--- a/net/disk_cache/simple/simple_util.cc
+++ b/net/disk_cache/simple/simple_util.cc
@@ -8,9 +8,9 @@
 
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc
index 424340f..6d22334 100644
--- a/net/http/http_auth_handler_digest.cc
+++ b/net/http/http_auth_handler_digest.cc
@@ -6,8 +6,8 @@
 
 #include <string>
 
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/rand_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/net/http/http_vary_data.h b/net/http/http_vary_data.h
index 3447028..0f4ceb1 100644
--- a/net/http/http_vary_data.h
+++ b/net/http/http_vary_data.h
@@ -5,7 +5,7 @@
 #ifndef NET_HTTP_HTTP_VARY_DATA_H_
 #define NET_HTTP_HTTP_VARY_DATA_H_
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "net/base/net_export.h"
 
 namespace base {
diff --git a/net/server/web_socket.cc b/net/server/web_socket.cc
index dc3ca0b..60d9074 100644
--- a/net/server/web_socket.cc
+++ b/net/server/web_socket.cc
@@ -7,8 +7,8 @@
 #include <vector>
 
 #include "base/base64.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_byteorder.h"
diff --git a/net/test/embedded_test_server/default_handlers.cc b/net/test/embedded_test_server/default_handlers.cc
index e438785..3632108 100644
--- a/net/test/embedded_test_server/default_handlers.cc
+++ b/net/test/embedded_test_server/default_handlers.cc
@@ -20,8 +20,8 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
+#include "base/hash/md5.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/path_service.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
diff --git a/net/tools/cachetool/cachetool.cc b/net/tools/cachetool/cachetool.cc
index 650e5d0..7200838 100644
--- a/net/tools/cachetool/cachetool.cc
+++ b/net/tools/cachetool/cachetool.cc
@@ -10,8 +10,8 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/format_macros.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
diff --git a/net/websockets/websocket_handshake_challenge.cc b/net/websockets/websocket_handshake_challenge.cc
index 3a1c3e8..0e8ced6 100644
--- a/net/websockets/websocket_handshake_challenge.cc
+++ b/net/websockets/websocket_handshake_challenge.cc
@@ -5,7 +5,7 @@
 #include "net/websockets/websocket_handshake_challenge.h"
 
 #include "base/base64.h"
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "net/websockets/websocket_handshake_constants.h"
 
 namespace net {
diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc
index cc72916..e8702cc 100644
--- a/ppapi/proxy/interface_list.cc
+++ b/ppapi/proxy/interface_list.cc
@@ -7,7 +7,7 @@
 #include <memory>
 #include <stdint.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/lazy_instance.h"
 #include "base/memory/singleton.h"
 #include "build/build_config.h"
diff --git a/ppapi/proxy/interface_list_unittest.cc b/ppapi/proxy/interface_list_unittest.cc
index 902a0a18..8f2c2a5 100644
--- a/ppapi/proxy/interface_list_unittest.cc
+++ b/ppapi/proxy/interface_list_unittest.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/hash.h"
-#include "ppapi/c/ppb_core.h"
 #include "ppapi/proxy/interface_list.h"
+#include "base/hash/hash.h"
+#include "ppapi/c/ppb_core.h"
 #include "ppapi/proxy/ppapi_proxy_test.h"
 
 namespace ppapi {
diff --git a/ppapi/tools/pepper_hash_for_uma.cc b/ppapi/tools/pepper_hash_for_uma.cc
index 588ae46..bb2706c 100644
--- a/ppapi/tools/pepper_hash_for_uma.cc
+++ b/ppapi/tools/pepper_hash_for_uma.cc
@@ -24,7 +24,7 @@
 #include <algorithm>
 #include <vector>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 
 int main(int argc, char **argv) {
diff --git a/printing/image.cc b/printing/image.cc
index 194a410c..267346d 100644
--- a/printing/image.cc
+++ b/printing/image.cc
@@ -9,7 +9,7 @@
 #include <algorithm>
 
 #include "base/files/file_util.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "printing/metafile.h"
diff --git a/remoting/host/linux/certificate_watcher.cc b/remoting/host/linux/certificate_watcher.cc
index 39aa54c..2f412818 100644
--- a/remoting/host/linux/certificate_watcher.cc
+++ b/remoting/host/linux/certificate_watcher.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/path_service.h"
diff --git a/remoting/host/setup/daemon_controller_delegate_linux.cc b/remoting/host/setup/daemon_controller_delegate_linux.cc
index 20962c72..a00f052 100644
--- a/remoting/host/setup/daemon_controller_delegate_linux.cc
+++ b/remoting/host/setup/daemon_controller_delegate_linux.cc
@@ -13,9 +13,9 @@
 #include "base/environment.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/json/json_writer.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
diff --git a/remoting/signaling/BUILD.gn b/remoting/signaling/BUILD.gn
index 2ed3acb..971d7a9c 100644
--- a/remoting/signaling/BUILD.gn
+++ b/remoting/signaling/BUILD.gn
@@ -27,6 +27,7 @@
     "message_reception_channel.h",
     "push_notification_subscriber.cc",
     "push_notification_subscriber.h",
+    "registration_manager.h",
     "server_log_entry.cc",
     "server_log_entry.h",
     "signal_strategy.h",
@@ -100,8 +101,6 @@
   sources = [
     "fake_signal_strategy.cc",
     "fake_signal_strategy.h",
-    "ftl_grpc_test_environment.cc",
-    "ftl_grpc_test_environment.h",
     "mock_signal_strategy.cc",
     "mock_signal_strategy.h",
   ]
@@ -116,7 +115,6 @@
   testonly = true
 
   sources = [
-    "ftl_grpc_context_unittest.cc",
     "ftl_message_reception_channel_unittest.cc",
     "ftl_messaging_client_unittest.cc",
     "iq_sender_unittest.cc",
diff --git a/remoting/signaling/ftl_grpc_context.cc b/remoting/signaling/ftl_grpc_context.cc
index 843d8e5..a0970e5 100644
--- a/remoting/signaling/ftl_grpc_context.cc
+++ b/remoting/signaling/ftl_grpc_context.cc
@@ -6,10 +6,12 @@
 
 #include <utility>
 
-#include "base/bind.h"
 #include "base/guid.h"
+#include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "google_apis/google_api_keys.h"
+#include "third_party/grpc/src/include/grpcpp/channel.h"
+#include "third_party/grpc/src/include/grpcpp/client_context.h"
 #include "third_party/grpc/src/include/grpcpp/grpcpp.h"
 
 namespace remoting {
@@ -21,6 +23,8 @@
 // TODO(yuweih): We should target different service environments.
 constexpr char kFtlServerEndpoint[] = "instantmessaging-pa.googleapis.com";
 
+static base::NoDestructor<GrpcChannelSharedPtr> g_channel_for_testing;
+
 }  // namespace
 
 // static
@@ -29,7 +33,7 @@
 }
 
 // static
-ftl::Id FtlGrpcContext::BuildIdFromString(const std::string& ftl_id) {
+ftl::Id FtlGrpcContext::CreateIdFromString(const std::string& ftl_id) {
   ftl::Id id;
   id.set_id(ftl_id);
   id.set_app(GetChromotingAppIdentifier());
@@ -38,52 +42,12 @@
   return id;
 }
 
-FtlGrpcContext::FtlGrpcContext(OAuthTokenGetter* token_getter)
-    : weak_factory_(this) {
-  DCHECK(token_getter);
-  token_getter_ = token_getter;
-  auto channel_creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
-  channel_ = grpc::CreateChannel(kFtlServerEndpoint, channel_creds);
-}
-
-FtlGrpcContext::~FtlGrpcContext() = default;
-
-void FtlGrpcContext::SetAuthToken(const std::string& auth_token) {
-  DCHECK(!auth_token.empty());
-  auth_token_ = auth_token;
-}
-
-void FtlGrpcContext::SetChannelForTesting(
-    std::shared_ptr<grpc::ChannelInterface> channel) {
-  channel_ = channel;
-}
-
-void FtlGrpcContext::GetOAuthTokenAndExecuteRpc(
-    std::unique_ptr<GrpcAsyncRequest> request,
-    base::OnceClosure on_stream_started) {
-  token_getter_->CallWithToken(
-      base::BindOnce(&FtlGrpcContext::ExecuteRpcWithFetchedOAuthToken,
-                     weak_factory_.GetWeakPtr(), std::move(request),
-                     std::move(on_stream_started)));
-}
-
-void FtlGrpcContext::ExecuteRpcWithFetchedOAuthToken(
-    std::unique_ptr<GrpcAsyncRequest> request,
-    base::OnceClosure on_stream_started,
-    OAuthTokenGetter::Status status,
-    const std::string& user_email,
-    const std::string& access_token) {
-  if (status != OAuthTokenGetter::Status::SUCCESS) {
-    LOG(ERROR) << "Failed to fetch access token. Status: " << status;
+// static
+GrpcChannelSharedPtr FtlGrpcContext::CreateChannel() {
+  if (*g_channel_for_testing) {
+    return *g_channel_for_testing;
   }
-  if (status == OAuthTokenGetter::Status::SUCCESS && !access_token.empty()) {
-    request->context()->set_credentials(
-        grpc::AccessTokenCredentials(access_token));
-  } else {
-    LOG(WARNING) << "Attempting to execute RPC without access token.";
-  }
-  executor_.ExecuteRpc(std::move(request));
-  std::move(on_stream_started).Run();
+  return CreateSslChannelForEndpoint(kFtlServerEndpoint);
 }
 
 // static
@@ -93,14 +57,16 @@
   return context;
 }
 
-std::unique_ptr<ftl::RequestHeader> FtlGrpcContext::BuildRequestHeader() {
-  auto header = std::make_unique<ftl::RequestHeader>();
-  header->set_request_id(base::GenerateGUID());
-  header->set_app(kChromotingAppIdentifier);
-  if (!auth_token_.empty()) {
-    header->set_auth_token_payload(auth_token_);
+// static
+ftl::RequestHeader FtlGrpcContext::CreateRequestHeader(
+    const std::string& ftl_auth_token) {
+  ftl::RequestHeader header;
+  header.set_request_id(base::GenerateGUID());
+  header.set_app(kChromotingAppIdentifier);
+  if (!ftl_auth_token.empty()) {
+    header.set_auth_token_payload(ftl_auth_token);
   }
-  ftl::ClientInfo* client_info = header->mutable_client_info();
+  ftl::ClientInfo* client_info = header.mutable_client_info();
   client_info->set_api_version(ftl::ApiVersion_Value_V4);
   client_info->set_version_major(VERSION_MAJOR);
   // Chrome's version has four number components, and the VERSION_MINOR is
@@ -120,4 +86,9 @@
   return header;
 }
 
+// static
+void FtlGrpcContext::SetChannelForTesting(GrpcChannelSharedPtr channel) {
+  *g_channel_for_testing = channel;
+}
+
 }  // namespace remoting
diff --git a/remoting/signaling/ftl_grpc_context.h b/remoting/signaling/ftl_grpc_context.h
index e297fec..81a9e09 100644
--- a/remoting/signaling/ftl_grpc_context.h
+++ b/remoting/signaling/ftl_grpc_context.h
@@ -7,100 +7,32 @@
 
 #include <memory>
 #include <string>
-#include <utility>
-#include <vector>
 
-#include "base/bind_helpers.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "remoting/base/oauth_token_getter.h"
-#include "remoting/signaling/ftl_services.grpc.pb.h"
-#include "remoting/signaling/grpc_support/grpc_async_executor.h"
-#include "remoting/signaling/grpc_support/grpc_async_server_streaming_request.h"
-#include "remoting/signaling/grpc_support/grpc_async_unary_request.h"
-#include "remoting/signaling/grpc_support/scoped_grpc_server_stream.h"
-#include "third_party/grpc/src/include/grpcpp/support/status.h"
+#include "remoting/signaling/ftl.pb.h"
+#include "remoting/signaling/grpc_support/grpc_channel.h"
+
+namespace grpc {
+class ClientContext;
+}  // namespace grpc
 
 namespace remoting {
 
-// This is the class that makes RPC calls to the FTL signaling backend.
+// This is the class for creating context objects to be used when connecting
+// to FTL backend.
 class FtlGrpcContext final {
  public:
-  template <typename ResponseType>
-  using RpcCallback =
-      base::OnceCallback<void(const grpc::Status&, const ResponseType&)>;
-  using StreamStartedCallback =
-      base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>;
-
   static std::string GetChromotingAppIdentifier();
-  static ftl::Id BuildIdFromString(const std::string& ftl_id);
+  static ftl::Id CreateIdFromString(const std::string& ftl_id);
+  static GrpcChannelSharedPtr CreateChannel();
+  static std::unique_ptr<grpc::ClientContext> CreateClientContext();
+  static ftl::RequestHeader CreateRequestHeader(
+      const std::string& ftl_auth_token = {});
 
-  explicit FtlGrpcContext(OAuthTokenGetter* token_getter);
-  ~FtlGrpcContext();
-
-  void SetAuthToken(const std::string& auth_token);
-
-  // |request| doesn't need to set the header field since this class will set
-  // it for you.
-  template <typename RequestType, typename ResponseType>
-  void ExecuteRpc(GrpcAsyncUnaryRpcFunction<RequestType, ResponseType> rpc,
-                  const RequestType& request,
-                  GrpcAsyncUnaryRpcCallback<ResponseType> callback) {
-    RequestType mutable_request = request;
-    mutable_request.set_allocated_header(BuildRequestHeader().release());
-    auto grpc_request =
-        CreateGrpcAsyncUnaryRequest(std::move(rpc), CreateClientContext(),
-                                    mutable_request, std::move(callback));
-    GetOAuthTokenAndExecuteRpc(std::move(grpc_request), base::DoNothing());
-  }
-
-  // |request| doesn't need to set the header field since this class will set
-  // it for you.
-  // Note that |on_stream_started| will be removed in a future refactoring CL.
-  template <typename RequestType, typename ResponseType>
-  void ExecuteServerStreamingRpc(
-      GrpcAsyncServerStreamingRpcFunction<RequestType, ResponseType> rpc,
-      const RequestType& request,
-      StreamStartedCallback on_stream_started,
-      const base::RepeatingCallback<void(const ResponseType&)>& on_incoming_msg,
-      base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-    RequestType mutable_request = request;
-    mutable_request.set_allocated_header(BuildRequestHeader().release());
-    std::unique_ptr<ScopedGrpcServerStream> scoped_stream;
-    auto grpc_request = CreateGrpcAsyncServerStreamingRequest(
-        std::move(rpc), CreateClientContext(), mutable_request,
-        std::move(on_incoming_msg), std::move(on_channel_closed),
-        &scoped_stream);
-    GetOAuthTokenAndExecuteRpc(
-        std::move(grpc_request),
-        base::BindOnce(std::move(on_stream_started), std::move(scoped_stream)));
-  }
-
-  std::shared_ptr<grpc::ChannelInterface> channel() { return channel_; }
-
-  void SetChannelForTesting(std::shared_ptr<grpc::ChannelInterface> channel);
+  static void SetChannelForTesting(GrpcChannelSharedPtr channel);
 
  private:
-  void GetOAuthTokenAndExecuteRpc(std::unique_ptr<GrpcAsyncRequest> request,
-                                  base::OnceClosure on_stream_started);
-
-  void ExecuteRpcWithFetchedOAuthToken(
-      std::unique_ptr<GrpcAsyncRequest> request,
-      base::OnceClosure on_stream_started,
-      OAuthTokenGetter::Status status,
-      const std::string& user_email,
-      const std::string& access_token);
-
-  static std::unique_ptr<grpc::ClientContext> CreateClientContext();
-  std::unique_ptr<ftl::RequestHeader> BuildRequestHeader();
-
-  std::shared_ptr<grpc::ChannelInterface> channel_;
-  OAuthTokenGetter* token_getter_;
-  GrpcAsyncExecutor executor_;
-  std::string auth_token_;
-
-  base::WeakPtrFactory<FtlGrpcContext> weak_factory_;
-  DISALLOW_COPY_AND_ASSIGN(FtlGrpcContext);
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FtlGrpcContext);
 };
 
 }  // namespace remoting
diff --git a/remoting/signaling/ftl_grpc_context_unittest.cc b/remoting/signaling/ftl_grpc_context_unittest.cc
deleted file mode 100644
index e36a174e..0000000
--- a/remoting/signaling/ftl_grpc_context_unittest.cc
+++ /dev/null
@@ -1,250 +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 "remoting/signaling/ftl_grpc_context.h"
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/run_loop.h"
-#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "remoting/base/fake_oauth_token_getter.h"
-#include "remoting/signaling/ftl_services.grpc.pb.h"
-#include "remoting/signaling/grpc_support/grpc_async_test_server.h"
-#include "remoting/signaling/grpc_support/grpc_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/grpc/src/include/grpcpp/grpcpp.h"
-
-namespace remoting {
-
-namespace {
-
-constexpr char kFakeUserEmail[] = "fake@gmail.com";
-constexpr char kFakeAccessToken[] = "Dummy Token";
-constexpr char kFakeFtlAuthToken[] = "Dummy FTL Token";
-
-using PullMessagesCallback =
-    FtlGrpcContext::RpcCallback<ftl::PullMessagesResponse>;
-using IncomingMessageCallback =
-    base::RepeatingCallback<void(const ftl::ReceiveMessagesResponse&)>;
-using PullMessagesResponder =
-    test::GrpcServerResponder<ftl::PullMessagesResponse>;
-using ReceiveMessagesResponder =
-    test::GrpcServerStreamResponder<ftl::ReceiveMessagesResponse>;
-
-PullMessagesCallback QuitRunLoopOnPullMessagesCallback(
-    base::RunLoop* run_loop) {
-  return base::BindOnce(
-      [](base::RunLoop* run_loop, const grpc::Status&,
-         const ftl::PullMessagesResponse&) { run_loop->QuitWhenIdle(); },
-      run_loop);
-}
-
-}  // namespace
-
-class FtlGrpcContextTest : public testing::Test {
- public:
-  void SetUp() override;
-  void TearDown() override;
-
- protected:
-  using Messaging =
-      google::internal::communications::instantmessaging::v1::Messaging;
-
-  void SendFakePullMessagesRequest(PullMessagesCallback on_response);
-  void SendFakeReceiveMessagesRequest(
-      FtlGrpcContext::StreamStartedCallback on_stream_started,
-      const IncomingMessageCallback& on_incoming_msg,
-      base::OnceCallback<void(const grpc::Status&)> on_channel_closed);
-  std::unique_ptr<PullMessagesResponder> HandlePullMessages(
-      ftl::PullMessagesRequest* request);
-  std::unique_ptr<ReceiveMessagesResponder> HandleReceiveMessages(
-      ftl::ReceiveMessagesRequest* request);
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  std::unique_ptr<FtlGrpcContext> context_;
-
- private:
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
-  std::unique_ptr<Messaging::Stub> stub_;
-  std::unique_ptr<test::GrpcAsyncTestServer> server_;
-  std::unique_ptr<FakeOAuthTokenGetter> token_getter_;
-};
-
-void FtlGrpcContextTest::SetUp() {
-  task_runner_ = base::SequencedTaskRunnerHandle::Get();
-  server_ = std::make_unique<test::GrpcAsyncTestServer>(
-      std::make_unique<Messaging::AsyncService>());
-  stub_ = Messaging::NewStub(server_->CreateInProcessChannel());
-  token_getter_ = std::make_unique<FakeOAuthTokenGetter>(
-      OAuthTokenGetter::Status::SUCCESS, kFakeUserEmail, kFakeAccessToken);
-  context_ = std::make_unique<FtlGrpcContext>(token_getter_.get());
-}
-
-void FtlGrpcContextTest::TearDown() {
-  context_.reset();
-  token_getter_.reset();
-  server_.reset();
-  stub_.reset();
-}
-
-void FtlGrpcContextTest::SendFakePullMessagesRequest(
-    PullMessagesCallback on_response) {
-  DCHECK(context_);
-  ftl::PullMessagesRequest request;
-  context_->ExecuteRpc(base::BindOnce(&Messaging::Stub::AsyncPullMessages,
-                                      base::Unretained(stub_.get())),
-                       request, std::move(on_response));
-}
-
-void FtlGrpcContextTest::SendFakeReceiveMessagesRequest(
-    FtlGrpcContext::StreamStartedCallback on_stream_started,
-    const IncomingMessageCallback& on_incoming_msg,
-    base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-  context_->ExecuteServerStreamingRpc(
-      base::BindOnce(&Messaging::Stub::AsyncReceiveMessages,
-                     base::Unretained(stub_.get())),
-      ftl::ReceiveMessagesRequest(), std::move(on_stream_started),
-      on_incoming_msg, std::move(on_channel_closed));
-}
-
-std::unique_ptr<PullMessagesResponder> FtlGrpcContextTest::HandlePullMessages(
-    ftl::PullMessagesRequest* request) {
-  return server_->HandleRequest(&Messaging::AsyncService::RequestPullMessages,
-                                request);
-}
-
-std::unique_ptr<ReceiveMessagesResponder>
-FtlGrpcContextTest::HandleReceiveMessages(
-    ftl::ReceiveMessagesRequest* request) {
-  return server_->HandleStreamRequest(
-      &Messaging::AsyncService::RequestReceiveMessages, request);
-}
-
-TEST_F(FtlGrpcContextTest, VerifyAPIKeyIsProvided) {
-  base::RunLoop run_loop;
-
-  SendFakePullMessagesRequest(QuitRunLoopOnPullMessagesCallback(&run_loop));
-
-  task_runner_->PostTask(
-      FROM_HERE, base::BindLambdaForTesting([&]() {
-        ftl::PullMessagesRequest request;
-        auto responder = HandlePullMessages(&request);
-
-        const std::multimap<grpc::string_ref, grpc::string_ref>&
-            client_metadata = responder->context()->client_metadata();
-        auto api_key_iter = client_metadata.find("x-goog-api-key");
-        ASSERT_NE(client_metadata.end(), api_key_iter);
-        ASSERT_FALSE(api_key_iter->second.empty());
-        responder->Respond(ftl::PullMessagesResponse(), grpc::Status::OK);
-      }));
-  run_loop.Run();
-}
-
-TEST_F(FtlGrpcContextTest, VerifyRequestHeaderIsSet) {
-  base::RunLoop run_loop;
-
-  SendFakePullMessagesRequest(QuitRunLoopOnPullMessagesCallback(&run_loop));
-
-  task_runner_->PostTask(FROM_HERE, base::BindLambdaForTesting([&]() {
-                           ftl::PullMessagesRequest request;
-                           auto responder = HandlePullMessages(&request);
-                           ASSERT_TRUE(request.has_header());
-                           ASSERT_FALSE(request.header().request_id().empty());
-                           ASSERT_FALSE(request.header().app().empty());
-                           ASSERT_TRUE(request.header().has_client_info());
-                           responder->Respond(ftl::PullMessagesResponse(),
-                                              grpc::Status::OK);
-                         }));
-  run_loop.Run();
-}
-
-TEST_F(FtlGrpcContextTest, NoAuthTokenIfNotSet) {
-  base::RunLoop run_loop;
-
-  SendFakePullMessagesRequest(QuitRunLoopOnPullMessagesCallback(&run_loop));
-
-  task_runner_->PostTask(
-      FROM_HERE, base::BindLambdaForTesting([&]() {
-        ftl::PullMessagesRequest request;
-        auto responder = HandlePullMessages(&request);
-        ASSERT_TRUE(request.header().auth_token_payload().empty());
-        responder->Respond(ftl::PullMessagesResponse(), grpc::Status::OK);
-      }));
-  run_loop.Run();
-}
-
-TEST_F(FtlGrpcContextTest, HasAuthTokenIfSet) {
-  base::RunLoop run_loop;
-  context_->SetAuthToken(kFakeFtlAuthToken);
-
-  SendFakePullMessagesRequest(QuitRunLoopOnPullMessagesCallback(&run_loop));
-
-  task_runner_->PostTask(
-      FROM_HERE, base::BindLambdaForTesting([&]() {
-        ftl::PullMessagesRequest request;
-        auto responder = HandlePullMessages(&request);
-        ASSERT_EQ(kFakeFtlAuthToken, request.header().auth_token_payload());
-        responder->Respond(ftl::PullMessagesResponse(), grpc::Status::OK);
-      }));
-  run_loop.Run();
-}
-
-TEST_F(FtlGrpcContextTest, ServerStreamingScenario) {
-  base::RunLoop run_loop;
-  context_->SetAuthToken(kFakeFtlAuthToken);
-
-  ftl::InboxMessage fake_inbox_message;
-  fake_inbox_message.set_message_id("msg_1");
-
-  std::unique_ptr<ScopedGrpcServerStream> server_stream;
-  std::unique_ptr<ReceiveMessagesResponder> responder;
-
-  SendFakeReceiveMessagesRequest(
-      // On stream started
-      base::BindLambdaForTesting(
-          [&](std::unique_ptr<ScopedGrpcServerStream> stream) {
-            server_stream = std::move(stream);
-
-            ftl::ReceiveMessagesRequest request;
-            responder = HandleReceiveMessages(&request);
-            ASSERT_TRUE(request.has_header());
-            ASSERT_FALSE(request.header().request_id().empty());
-            ASSERT_FALSE(request.header().app().empty());
-            ASSERT_TRUE(request.header().has_client_info());
-            ASSERT_EQ(kFakeFtlAuthToken, request.header().auth_token_payload());
-
-            ftl::ReceiveMessagesResponse response;
-            response.set_allocated_inbox_message(
-                new ftl::InboxMessage(fake_inbox_message));
-            responder->SendMessage(response);
-          }),
-
-      // On message received
-      base::BindLambdaForTesting(
-          [&](const ftl::ReceiveMessagesResponse& response) {
-            ASSERT_EQ(fake_inbox_message.message_id(),
-                      response.inbox_message().message_id());
-            ASSERT_TRUE(responder->WaitForSendMessageResult());
-            responder->Close(grpc::Status::OK);
-          }),
-
-      // On channel closed
-      test::CheckStatusThenQuitRunLoopCallback(FROM_HERE, grpc::StatusCode::OK,
-                                               &run_loop));
-
-  run_loop.Run();
-}
-
-// TODO(yuweih): Ideally we should verify access token is properly attached too,
-// but currently this information seems to be lost in ServiceContext.
-
-}  // namespace remoting
diff --git a/remoting/signaling/ftl_grpc_test_environment.cc b/remoting/signaling/ftl_grpc_test_environment.cc
deleted file mode 100644
index 7465d80..0000000
--- a/remoting/signaling/ftl_grpc_test_environment.cc
+++ /dev/null
@@ -1,27 +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 "remoting/signaling/ftl_grpc_test_environment.h"
-
-#include <utility>
-
-#include "remoting/base/fake_oauth_token_getter.h"
-#include "remoting/signaling/ftl_grpc_context.h"
-
-namespace remoting {
-namespace test {
-
-FtlGrpcTestEnvironment::FtlGrpcTestEnvironment(
-    std::shared_ptr<grpc::ChannelInterface> channel) {
-  token_getter_ = std::make_unique<FakeOAuthTokenGetter>(
-      OAuthTokenGetter::Status::SUCCESS, "fake_user_email",
-      "fake_access_token");
-  context_ = std::make_unique<FtlGrpcContext>(token_getter_.get());
-  context_->SetChannelForTesting(channel);
-}
-
-FtlGrpcTestEnvironment::~FtlGrpcTestEnvironment() = default;
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/signaling/ftl_grpc_test_environment.h b/remoting/signaling/ftl_grpc_test_environment.h
deleted file mode 100644
index fd89119..0000000
--- a/remoting/signaling/ftl_grpc_test_environment.h
+++ /dev/null
@@ -1,46 +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 REMOTING_SIGNALING_FTL_GRPC_TEST_ENVIRONMENT_H_
-#define REMOTING_SIGNALING_FTL_GRPC_TEST_ENVIRONMENT_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/sequenced_task_runner.h"
-
-namespace grpc {
-class ChannelInterface;
-}  // namespace grpc
-
-namespace remoting {
-
-class FakeOAuthTokenGetter;
-class FtlGrpcContext;
-
-namespace test {
-
-// This class creates FtlGrpcContext with fake OAuthTokenGetter and connects it
-// with the test channel.
-class FtlGrpcTestEnvironment final {
- public:
-  // TODO(yuweih): Typedef std::shared_ptr since it's not used in Chromium.
-  explicit FtlGrpcTestEnvironment(
-      std::shared_ptr<grpc::ChannelInterface> channel);
-  ~FtlGrpcTestEnvironment();
-
-  FtlGrpcContext* context() { return context_.get(); }
-
- private:
-  std::unique_ptr<FakeOAuthTokenGetter> token_getter_;
-  std::unique_ptr<FtlGrpcContext> context_;
-
-  DISALLOW_COPY_AND_ASSIGN(FtlGrpcTestEnvironment);
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_SIGNALING_FTL_GRPC_TEST_ENVIRONMENT_H_
diff --git a/remoting/signaling/ftl_message_reception_channel.cc b/remoting/signaling/ftl_message_reception_channel.cc
index ab74d048..ef436d0 100644
--- a/remoting/signaling/ftl_message_reception_channel.cc
+++ b/remoting/signaling/ftl_message_reception_channel.cc
@@ -91,11 +91,6 @@
   return reconnect_retry_backoff_;
 }
 
-void FtlMessageReceptionChannel::OnReceiveMessagesStreamStarted(
-    std::unique_ptr<ScopedGrpcServerStream> stream) {
-  receive_messages_stream_ = std::move(stream);
-}
-
 void FtlMessageReceptionChannel::OnReceiveMessagesStreamClosed(
     const grpc::Status& status) {
   if (state_ == State::STOPPED) {
@@ -170,10 +165,7 @@
 void FtlMessageReceptionChannel::StartReceivingMessagesInternal() {
   DCHECK_EQ(State::STOPPED, state_);
   state_ = State::STARTING;
-  stream_opener_.Run(
-      base::BindOnce(
-          &FtlMessageReceptionChannel::OnReceiveMessagesStreamStarted,
-          weak_factory_.GetWeakPtr()),
+  receive_messages_stream_ = stream_opener_.Run(
       base::BindRepeating(&FtlMessageReceptionChannel::OnMessageReceived,
                           weak_factory_.GetWeakPtr()),
       base::BindOnce(&FtlMessageReceptionChannel::OnReceiveMessagesStreamClosed,
diff --git a/remoting/signaling/ftl_message_reception_channel.h b/remoting/signaling/ftl_message_reception_channel.h
index a105d678..37e2ed1 100644
--- a/remoting/signaling/ftl_message_reception_channel.h
+++ b/remoting/signaling/ftl_message_reception_channel.h
@@ -54,8 +54,6 @@
     STARTED,
   };
 
-  void OnReceiveMessagesStreamStarted(
-      std::unique_ptr<ScopedGrpcServerStream> stream);
   void OnReceiveMessagesStreamClosed(const grpc::Status& status);
   void OnMessageReceived(const ftl::ReceiveMessagesResponse& response);
 
diff --git a/remoting/signaling/ftl_message_reception_channel_unittest.cc b/remoting/signaling/ftl_message_reception_channel_unittest.cc
index 659c8848..63f32fb7 100644
--- a/remoting/signaling/ftl_message_reception_channel_unittest.cc
+++ b/remoting/signaling/ftl_message_reception_channel_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "remoting/signaling/ftl.pb.h"
 #include "remoting/signaling/grpc_support/grpc_test_util.h"
 #include "remoting/signaling/grpc_support/scoped_grpc_server_stream.h"
@@ -33,6 +34,10 @@
 using ::testing::Property;
 using ::testing::Return;
 
+using ReceiveMessagesResponseCallback =
+    base::RepeatingCallback<void(const ftl::ReceiveMessagesResponse&)>;
+using StatusCallback = base::OnceCallback<void(const grpc::Status&)>;
+
 // Fake stream implementation to allow probing if a stream is closed by client.
 class FakeScopedGrpcServerStream : public ScopedGrpcServerStream {
  public:
@@ -64,6 +69,34 @@
       [](const grpc::Status& status) { ASSERT_TRUE(status.ok()); });
 }
 
+// Creates a gmock EXPECT_CALL action that:
+//   1. Creates a fake server stream and returns it as the start stream result
+//   2. Posts a task to call |on_stream_opened| at the end of current sequence
+//   3. Writes the WeakPtr to the fake server stream to |optional_out_stream|
+//      if it is provided.
+template <typename OnStreamOpenedLambda>
+decltype(auto) StartStream(
+    OnStreamOpenedLambda on_stream_opened,
+    base::WeakPtr<FakeScopedGrpcServerStream>* optional_out_stream) {
+  return [=](const ReceiveMessagesResponseCallback& on_incoming_msg,
+             StatusCallback on_channel_closed) {
+    auto fake_stream = CreateFakeServerStream();
+    if (optional_out_stream) {
+      *optional_out_stream = fake_stream->GetWeakPtr();
+    }
+    auto on_stream_opened_cb = base::BindLambdaForTesting(on_stream_opened);
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(on_stream_opened_cb, on_incoming_msg,
+                                  std::move(on_channel_closed)));
+    return fake_stream;
+  };
+}
+
+template <typename OnStreamOpenedLambda>
+decltype(auto) StartStream(OnStreamOpenedLambda on_stream_opened) {
+  return StartStream(on_stream_opened, nullptr);
+}
+
 }  // namespace
 
 class FtlMessageReceptionChannelTest : public testing::Test {
@@ -108,14 +141,10 @@
        TestStartReceivingMessages_StoppedImmediately) {
   base::RunLoop run_loop;
 
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-            std::move(on_stream_started).Run(CreateFakeServerStream());
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             channel_->StopReceivingMessages();
           }));
 
@@ -129,14 +158,10 @@
        TestStartReceivingMessages_NotAuthenticated) {
   base::RunLoop run_loop;
 
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-            std::move(on_stream_started).Run(CreateFakeServerStream());
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             std::move(on_channel_closed)
                 .Run(grpc::Status(grpc::StatusCode::UNAUTHENTICATED, ""));
           }));
@@ -151,14 +176,10 @@
        TestStartReceivingMessages_StreamStarted) {
   base::RunLoop run_loop;
 
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-            std::move(on_stream_started).Run(CreateFakeServerStream());
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             on_incoming_msg.Run(CreateStartOfBatchResponse());
           }));
 
@@ -173,18 +194,11 @@
   base::RunLoop run_loop;
 
   base::WeakPtr<FakeScopedGrpcServerStream> old_stream;
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             // The first open stream attempt fails with UNAVAILABLE error.
-            auto fake_server_stream = CreateFakeServerStream();
-            old_stream = fake_server_stream->GetWeakPtr();
-            std::move(on_stream_started).Run(std::move(fake_server_stream));
-
             ASSERT_EQ(0, GetRetryFailureCount());
 
             std::move(on_channel_closed)
@@ -197,20 +211,17 @@
 
             // This will make the channel reopen the stream.
             scoped_task_environment_.FastForwardBy(GetTimeUntilRetry());
-          }))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
+          },
+          &old_stream))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             // Second open stream attempt succeeds.
 
             // Assert old stream closed.
             ASSERT_FALSE(old_stream);
 
             // Send a StartOfBatch and verify it resets the failure counter.
-            std::move(on_stream_started).Run(CreateFakeServerStream());
             on_incoming_msg.Run(CreateStartOfBatchResponse());
 
             ASSERT_EQ(0, GetRetryFailureCount());
@@ -236,14 +247,10 @@
       .WillOnce(Return())
       .WillOnce(Invoke([&](const grpc::Status& status) { run_loop.Quit(); }));
 
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-            std::move(on_stream_started).Run(CreateFakeServerStream());
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             on_incoming_msg.Run(CreateStartOfBatchResponse());
           }));
 
@@ -272,15 +279,10 @@
               Run(Property(&ftl::InboxMessage::message_id, kMessage2Id)))
       .WillOnce(Invoke([&](const ftl::InboxMessage&) { run_loop.Quit(); }));
 
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-            std::move(on_stream_started).Run(CreateFakeServerStream());
-
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             on_incoming_msg.Run(CreateStartOfBatchResponse());
 
             ftl::ReceiveMessagesResponse response;
@@ -304,16 +306,10 @@
   base::RunLoop run_loop;
 
   base::WeakPtr<FakeScopedGrpcServerStream> old_stream;
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-            auto fake_server_stream = CreateFakeServerStream();
-            old_stream = fake_server_stream->GetWeakPtr();
-            std::move(on_stream_started).Run(std::move(fake_server_stream));
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             on_incoming_msg.Run(CreateStartOfBatchResponse());
             scoped_task_environment_.FastForwardBy(
                 FtlMessageReceptionChannel::kPongTimeout);
@@ -325,20 +321,16 @@
 
             // This will make the channel reopen the stream.
             scoped_task_environment_.FastForwardBy(GetTimeUntilRetry());
-          }))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
+          },
+          &old_stream))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             // Stream is reopened.
 
             // Assert old stream closed.
             ASSERT_FALSE(old_stream);
 
-            std::move(on_stream_started).Run(CreateFakeServerStream());
-
             // Sends a StartOfBatch and verify that it resets the failure
             // counter.
             on_incoming_msg.Run(CreateStartOfBatchResponse());
@@ -354,17 +346,12 @@
 TEST_F(FtlMessageReceptionChannelTest, LifetimeExceeded_ResetsStream) {
   base::RunLoop run_loop;
 
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
+  base::WeakPtr<FakeScopedGrpcServerStream> old_stream;
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             auto fake_server_stream = CreateFakeServerStream();
-            base::WeakPtr<FakeScopedGrpcServerStream> old_stream =
-                fake_server_stream->GetWeakPtr();
-            std::move(on_stream_started).Run(std::move(fake_server_stream));
             on_incoming_msg.Run(CreateStartOfBatchResponse());
 
             // Keep sending pong until lifetime exceeded.
@@ -379,17 +366,15 @@
               scoped_task_environment_.FastForwardBy(pong_period);
               ticked_time += pong_period;
             }
+          },
+          &old_stream))
+      .WillOnce(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             ASSERT_FALSE(old_stream);
-          }))
-      .WillOnce(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-            // Reopening the stream. Send StartOfBatch and verify that it resets
-            // the failure counter.
-            std::move(on_stream_started).Run(CreateFakeServerStream());
+
+            // The stream is reopened. Send StartOfBatch and verify that it
+            // resets the failure counter.
             on_incoming_msg.Run(CreateStartOfBatchResponse());
             ASSERT_EQ(0, GetRetryFailureCount());
             run_loop.Quit();
@@ -405,15 +390,10 @@
 
   int failure_count = 0;
   int hitting_max_delay_count = 0;
-  EXPECT_CALL(mock_stream_opener_, Run(_, _, _))
-      .WillRepeatedly(Invoke(
-          [&](base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-                  on_stream_started,
-              const base::RepeatingCallback<void(
-                  const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
-              base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-            std::move(on_stream_started).Run(CreateFakeServerStream());
-
+  EXPECT_CALL(mock_stream_opener_, Run(_, _))
+      .WillRepeatedly(StartStream(
+          [&](const ReceiveMessagesResponseCallback& on_incoming_msg,
+              StatusCallback on_channel_closed) {
             // Quit if delay is ~kBackoffMaxDelay three times.
             if (hitting_max_delay_count == 3) {
               on_incoming_msg.Run(CreateStartOfBatchResponse());
diff --git a/remoting/signaling/ftl_messaging_client.cc b/remoting/signaling/ftl_messaging_client.cc
index 3421de8..7f72298 100644
--- a/remoting/signaling/ftl_messaging_client.cc
+++ b/remoting/signaling/ftl_messaging_client.cc
@@ -13,6 +13,11 @@
 #include "base/time/time.h"
 #include "remoting/signaling/ftl_grpc_context.h"
 #include "remoting/signaling/ftl_message_reception_channel.h"
+#include "remoting/signaling/grpc_support/grpc_async_server_streaming_request.h"
+#include "remoting/signaling/grpc_support/grpc_async_unary_request.h"
+#include "remoting/signaling/grpc_support/grpc_authenticated_executor.h"
+#include "remoting/signaling/grpc_support/grpc_executor.h"
+#include "remoting/signaling/registration_manager.h"
 
 namespace remoting {
 
@@ -30,16 +35,30 @@
 
 }  // namespace
 
-FtlMessagingClient::FtlMessagingClient(FtlGrpcContext* context)
-    : weak_factory_(this) {
-  context_ = context;
-  messaging_stub_ = Messaging::NewStub(context_->channel());
-  reception_channel_ = std::make_unique<FtlMessageReceptionChannel>();
+FtlMessagingClient::FtlMessagingClient(
+    OAuthTokenGetter* token_getter,
+    RegistrationManager* registration_manager)
+    : FtlMessagingClient(
+          std::make_unique<GrpcAuthenticatedExecutor>(token_getter),
+          registration_manager,
+          std::make_unique<FtlMessageReceptionChannel>()) {}
+
+FtlMessagingClient::FtlMessagingClient(
+    std::unique_ptr<GrpcExecutor> executor,
+    RegistrationManager* registration_manager,
+    std::unique_ptr<MessageReceptionChannel> channel) {
+  DCHECK(executor);
+  DCHECK(registration_manager);
+  DCHECK(channel);
+  executor_ = std::move(executor);
+  registration_manager_ = registration_manager;
+  messaging_stub_ = Messaging::NewStub(FtlGrpcContext::CreateChannel());
+  reception_channel_ = std::move(channel);
   reception_channel_->Initialize(
       base::BindRepeating(&FtlMessagingClient::OpenReceiveMessagesStream,
-                          weak_factory_.GetWeakPtr()),
+                          base::Unretained(this)),
       base::BindRepeating(&FtlMessagingClient::OnMessageReceived,
-                          weak_factory_.GetWeakPtr()));
+                          base::Unretained(this)));
 }
 
 FtlMessagingClient::~FtlMessagingClient() = default;
@@ -50,12 +69,16 @@
 }
 
 void FtlMessagingClient::PullMessages(DoneCallback on_done) {
-  context_->ExecuteRpc(
+  ftl::PullMessagesRequest request;
+  *request.mutable_header() = FtlGrpcContext::CreateRequestHeader(
+      registration_manager_->GetFtlAuthToken());
+  auto grpc_request = CreateGrpcAsyncUnaryRequest(
       base::BindOnce(&Messaging::Stub::AsyncPullMessages,
                      base::Unretained(messaging_stub_.get())),
-      ftl::PullMessagesRequest(),
+      FtlGrpcContext::CreateClientContext(), request,
       base::BindOnce(&FtlMessagingClient::OnPullMessagesResponse,
-                     weak_factory_.GetWeakPtr(), std::move(on_done)));
+                     base::Unretained(this), std::move(on_done)));
+  executor_->ExecuteRpc(std::move(grpc_request));
 }
 
 void FtlMessagingClient::SendMessage(
@@ -64,9 +87,11 @@
     const std::string& message_text,
     DoneCallback on_done) {
   ftl::InboxSendRequest request;
+  *request.mutable_header() = FtlGrpcContext::CreateRequestHeader(
+      registration_manager_->GetFtlAuthToken());
   request.set_time_to_live(kInboxMessageTtl.InMicroseconds());
   // TODO(yuweih): See if we need to set requester_id
-  (*request.mutable_dest_id()) = FtlGrpcContext::BuildIdFromString(destination);
+  *request.mutable_dest_id() = FtlGrpcContext::CreateIdFromString(destination);
 
   ftl::ChromotingMessage crd_message;
   crd_message.set_message(message_text);
@@ -84,12 +109,13 @@
     request.add_dest_registration_ids(destination_registration_id);
   }
 
-  context_->ExecuteRpc(
+  auto grpc_request = CreateGrpcAsyncUnaryRequest(
       base::BindOnce(&Messaging::Stub::AsyncSendMessage,
                      base::Unretained(messaging_stub_.get())),
-      request,
+      FtlGrpcContext::CreateClientContext(), request,
       base::BindOnce(&FtlMessagingClient::OnSendMessageResponse,
-                     weak_factory_.GetWeakPtr(), std::move(on_done)));
+                     base::Unretained(this), std::move(on_done)));
+  executor_->ExecuteRpc(std::move(grpc_request));
 }
 
 void FtlMessagingClient::StartReceivingMessages(DoneCallback on_done) {
@@ -100,16 +126,6 @@
   reception_channel_->StopReceivingMessages();
 }
 
-void FtlMessagingClient::SetMessageReceptionChannelForTesting(
-    std::unique_ptr<MessageReceptionChannel> channel) {
-  reception_channel_ = std::move(channel);
-  reception_channel_->Initialize(
-      base::BindRepeating(&FtlMessagingClient::OpenReceiveMessagesStream,
-                          weak_factory_.GetWeakPtr()),
-      base::BindRepeating(&FtlMessagingClient::OnMessageReceived,
-                          weak_factory_.GetWeakPtr()));
-}
-
 void FtlMessagingClient::OnPullMessagesResponse(
     DoneCallback on_done,
     const grpc::Status& status,
@@ -123,6 +139,8 @@
   }
 
   ftl::AckMessagesRequest ack_request;
+  *ack_request.mutable_header() = FtlGrpcContext::CreateRequestHeader(
+      registration_manager_->GetFtlAuthToken());
   for (const auto& message : response.messages()) {
     RunMessageCallbacks(message);
     AddMessageToAckRequest(message, &ack_request);
@@ -148,12 +166,13 @@
 
 void FtlMessagingClient::AckMessages(const ftl::AckMessagesRequest& request,
                                      DoneCallback on_done) {
-  context_->ExecuteRpc(
+  auto grpc_request = CreateGrpcAsyncUnaryRequest(
       base::BindOnce(&Messaging::Stub::AsyncAckMessages,
                      base::Unretained(messaging_stub_.get())),
-      request,
+      FtlGrpcContext::CreateClientContext(), request,
       base::BindOnce(&FtlMessagingClient::OnAckMessagesResponse,
-                     weak_factory_.GetWeakPtr(), std::move(on_done)));
+                     base::Unretained(this), std::move(on_done)));
+  executor_->ExecuteRpc(std::move(grpc_request));
 }
 
 void FtlMessagingClient::OnAckMessagesResponse(
@@ -164,17 +183,22 @@
   std::move(on_done).Run(status);
 }
 
-void FtlMessagingClient::OpenReceiveMessagesStream(
-    base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-        on_stream_started,
+std::unique_ptr<ScopedGrpcServerStream>
+FtlMessagingClient::OpenReceiveMessagesStream(
     const base::RepeatingCallback<void(const ftl::ReceiveMessagesResponse&)>&
         on_incoming_msg,
     base::OnceCallback<void(const grpc::Status&)> on_channel_closed) {
-  context_->ExecuteServerStreamingRpc(
+  ftl::ReceiveMessagesRequest request;
+  *request.mutable_header() = FtlGrpcContext::CreateRequestHeader(
+      registration_manager_->GetFtlAuthToken());
+  std::unique_ptr<ScopedGrpcServerStream> stream;
+  auto grpc_request = CreateGrpcAsyncServerStreamingRequest(
       base::BindOnce(&Messaging::Stub::AsyncReceiveMessages,
                      base::Unretained(messaging_stub_.get())),
-      ftl::ReceiveMessagesRequest(), std::move(on_stream_started),
-      on_incoming_msg, std::move(on_channel_closed));
+      FtlGrpcContext::CreateClientContext(), request, on_incoming_msg,
+      std::move(on_channel_closed), &stream);
+  executor_->ExecuteRpc(std::move(grpc_request));
+  return stream;
 }
 
 void FtlMessagingClient::RunMessageCallbacks(const ftl::InboxMessage& message) {
@@ -194,6 +218,8 @@
 void FtlMessagingClient::OnMessageReceived(const ftl::InboxMessage& message) {
   RunMessageCallbacks(message);
   ftl::AckMessagesRequest ack_request;
+  *ack_request.mutable_header() = FtlGrpcContext::CreateRequestHeader(
+      registration_manager_->GetFtlAuthToken());
   AddMessageToAckRequest(message, &ack_request);
   AckMessages(ack_request, base::DoNothing());
 }
diff --git a/remoting/signaling/ftl_messaging_client.h b/remoting/signaling/ftl_messaging_client.h
index c77a8c5..97f695b 100644
--- a/remoting/signaling/ftl_messaging_client.h
+++ b/remoting/signaling/ftl_messaging_client.h
@@ -11,13 +11,14 @@
 #include "base/callback_forward.h"
 #include "base/callback_list.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "remoting/signaling/ftl_services.grpc.pb.h"
 
 namespace remoting {
 
-class FtlGrpcContext;
+class GrpcExecutor;
 class MessageReceptionChannel;
+class OAuthTokenGetter;
+class RegistrationManager;
 class ScopedGrpcServerStream;
 
 // A class for sending and receiving messages via the FTL API.
@@ -31,7 +32,9 @@
                               const std::string&)>::Subscription;
   using DoneCallback = base::OnceCallback<void(const grpc::Status& status)>;
 
-  explicit FtlMessagingClient(FtlGrpcContext* context);
+  // |token_getter| and |registration_manager| must outlive |this|.
+  FtlMessagingClient(OAuthTokenGetter* token_getter,
+                     RegistrationManager* registration_manager);
   ~FtlMessagingClient();
 
   // Registers a callback which is run for each new message received.
@@ -59,13 +62,16 @@
   // Stops the stream for continuously receiving new messages.
   void StopReceivingMessages();
 
-  void SetMessageReceptionChannelForTesting(
-      std::unique_ptr<MessageReceptionChannel> channel);
-
  private:
   using Messaging =
       google::internal::communications::instantmessaging::v1::Messaging;
 
+  friend class FtlMessagingClientTest;
+
+  FtlMessagingClient(std::unique_ptr<GrpcExecutor> executor,
+                     RegistrationManager* registration_manager,
+                     std::unique_ptr<MessageReceptionChannel> channel);
+
   void OnPullMessagesResponse(DoneCallback on_done,
                               const grpc::Status& status,
                               const ftl::PullMessagesResponse& response);
@@ -81,9 +87,7 @@
                              const grpc::Status& status,
                              const ftl::AckMessagesResponse& response);
 
-  void OpenReceiveMessagesStream(
-      base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-          on_stream_started,
+  std::unique_ptr<ScopedGrpcServerStream> OpenReceiveMessagesStream(
       const base::RepeatingCallback<void(const ftl::ReceiveMessagesResponse&)>&
           on_incoming_msg,
       base::OnceCallback<void(const grpc::Status&)> on_channel_closed);
@@ -92,13 +96,13 @@
 
   void OnMessageReceived(const ftl::InboxMessage& message);
 
-  FtlGrpcContext* context_;
+  std::unique_ptr<GrpcExecutor> executor_;
+  RegistrationManager* registration_manager_;
   std::unique_ptr<Messaging::Stub> messaging_stub_;
   std::unique_ptr<MessageReceptionChannel> reception_channel_;
   base::CallbackList<void(const std::string&, const std::string&)>
       callback_list_;
 
-  base::WeakPtrFactory<FtlMessagingClient> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(FtlMessagingClient);
 };
 
diff --git a/remoting/signaling/ftl_messaging_client_unittest.cc b/remoting/signaling/ftl_messaging_client_unittest.cc
index e4b91be47..ac7c97f0 100644
--- a/remoting/signaling/ftl_messaging_client_unittest.cc
+++ b/remoting/signaling/ftl_messaging_client_unittest.cc
@@ -18,12 +18,14 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
-#include "remoting/signaling/ftl_grpc_test_environment.h"
+#include "remoting/signaling/ftl_grpc_context.h"
 #include "remoting/signaling/ftl_services.grpc.pb.h"
+#include "remoting/signaling/grpc_support/grpc_async_executor.h"
 #include "remoting/signaling/grpc_support/grpc_async_test_server.h"
 #include "remoting/signaling/grpc_support/grpc_test_util.h"
 #include "remoting/signaling/grpc_support/scoped_grpc_server_stream.h"
 #include "remoting/signaling/message_reception_channel.h"
+#include "remoting/signaling/registration_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -99,6 +101,17 @@
   DISALLOW_COPY_AND_ASSIGN(MockMessageReceptionChannel);
 };
 
+class MockRegistrationManager : public RegistrationManager {
+ public:
+  MockRegistrationManager() = default;
+  ~MockRegistrationManager() override = default;
+
+  MOCK_METHOD1(SignInGaia, void(DoneCallback));
+  MOCK_CONST_METHOD0(IsSignedIn, bool());
+  MOCK_CONST_METHOD0(GetRegistrationId, std::string());
+  MOCK_CONST_METHOD0(GetFtlAuthToken, std::string());
+};
+
 }  // namespace
 
 class FtlMessagingClientTest : public testing::Test {
@@ -127,8 +140,8 @@
   MockMessageReceptionChannel* mock_message_reception_channel_;
 
  private:
-  std::unique_ptr<test::FtlGrpcTestEnvironment> test_environment_;
   base::test::ScopedTaskEnvironment scoped_task_environment_;
+  MockRegistrationManager mock_registration_manager_;
 };
 
 void FtlMessagingClientTest::SetUp() {
@@ -136,18 +149,19 @@
       base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()});
   server_ = std::make_unique<test::GrpcAsyncTestServer>(
       std::make_unique<Messaging::AsyncService>());
-  test_environment_ = std::make_unique<test::FtlGrpcTestEnvironment>(
-      server_->CreateInProcessChannel());
-  messaging_client_ =
-      std::make_unique<FtlMessagingClient>(test_environment_->context());
+  FtlGrpcContext::SetChannelForTesting(server_->CreateInProcessChannel());
+  EXPECT_CALL(mock_registration_manager_, GetFtlAuthToken())
+      .WillRepeatedly(Return("fake_auth_token"));
   auto channel = std::make_unique<MockMessageReceptionChannel>();
   mock_message_reception_channel_ = channel.get();
-  messaging_client_->SetMessageReceptionChannelForTesting(std::move(channel));
+  messaging_client_ = std::unique_ptr<FtlMessagingClient>(
+      new FtlMessagingClient(std::make_unique<GrpcAsyncExecutor>(),
+                             &mock_registration_manager_, std::move(channel)));
 }
 
 void FtlMessagingClientTest::TearDown() {
   messaging_client_.reset();
-  test_environment_.reset();
+  FtlGrpcContext::SetChannelForTesting(nullptr);
   server_task_runner_->DeleteSoon(FROM_HERE, std::move(server_));
 }
 
@@ -423,11 +437,7 @@
         exit_runloop_when_called_twice.Get().Run();
       });
 
-  mock_message_reception_channel_->stream_opener()->Run(
-      base::BindLambdaForTesting(
-          [&](std::unique_ptr<ScopedGrpcServerStream> stream) {
-            scoped_stream = std::move(stream);
-          }),
+  scoped_stream = mock_message_reception_channel_->stream_opener()->Run(
       mock_on_incoming_msg.Get(),
       base::BindOnce([](const grpc::Status&) { NOTREACHED(); }));
 
diff --git a/remoting/signaling/ftl_registration_manager.cc b/remoting/signaling/ftl_registration_manager.cc
index 4b0130d..75c1b7c0 100644
--- a/remoting/signaling/ftl_registration_manager.cc
+++ b/remoting/signaling/ftl_registration_manager.cc
@@ -12,6 +12,9 @@
 #include "base/time/time.h"
 #include "remoting/signaling/ftl_device_id_provider.h"
 #include "remoting/signaling/ftl_grpc_context.h"
+#include "remoting/signaling/grpc_support/grpc_async_unary_request.h"
+#include "remoting/signaling/grpc_support/grpc_authenticated_executor.h"
+#include "remoting/signaling/grpc_support/grpc_executor.h"
 
 namespace remoting {
 
@@ -28,20 +31,19 @@
 }  // namespace
 
 FtlRegistrationManager::FtlRegistrationManager(
-    FtlGrpcContext* context,
+    OAuthTokenGetter* token_getter,
     std::unique_ptr<FtlDeviceIdProvider> device_id_provider)
-    : context_(context),
-      device_id_provider_(std::move(device_id_provider)),
-      weak_factory_(this) {
-  DCHECK(context_);
+    : executor_(std::make_unique<GrpcAuthenticatedExecutor>(token_getter)),
+      device_id_provider_(std::move(device_id_provider)) {
   DCHECK(device_id_provider_);
-  registration_stub_ = Registration::NewStub(context_->channel());
+  registration_stub_ = Registration::NewStub(FtlGrpcContext::CreateChannel());
 }
 
 FtlRegistrationManager::~FtlRegistrationManager() = default;
 
 void FtlRegistrationManager::SignInGaia(DoneCallback on_done) {
   ftl::SignInGaiaRequest request;
+  *request.mutable_header() = FtlGrpcContext::CreateRequestHeader();
   request.set_app(FtlGrpcContext::GetChromotingAppIdentifier());
   request.set_mode(ftl::SignInGaiaMode_Value_DEFAULT_CREATE_ACCOUNT);
 
@@ -56,16 +58,24 @@
     request.mutable_register_data()->add_caps(kFtlCapabilities[i]);
   }
 
-  context_->ExecuteRpc(
+  auto grpc_request = CreateGrpcAsyncUnaryRequest(
       base::BindOnce(&Registration::Stub::AsyncSignInGaia,
                      base::Unretained(registration_stub_.get())),
-      request,
+      FtlGrpcContext::CreateClientContext(), request,
       base::BindOnce(&FtlRegistrationManager::OnSignInGaiaResponse,
-                     weak_factory_.GetWeakPtr(), std::move(on_done)));
+                     base::Unretained(this), std::move(on_done)));
+  executor_->ExecuteRpc(std::move(grpc_request));
 }
 
 bool FtlRegistrationManager::IsSignedIn() const {
-  return !registration_id_.empty();
+  return !ftl_auth_token_.empty();
+}
+
+std::string FtlRegistrationManager::GetRegistrationId() const {
+  return registration_id_;
+}
+std::string FtlRegistrationManager::GetFtlAuthToken() const {
+  return ftl_auth_token_;
 }
 
 void FtlRegistrationManager::OnSignInGaiaResponse(
@@ -90,7 +100,7 @@
   }
 
   // TODO(yuweih): Consider caching auth token.
-  context_->SetAuthToken(response.auth_token().payload());
+  ftl_auth_token_ = response.auth_token().payload();
   VLOG(0) << "Auth token set on FtlClient";
   base::TimeDelta refresh_delay =
       base::TimeDelta::FromMicroseconds(response.auth_token().expires_in());
diff --git a/remoting/signaling/ftl_registration_manager.h b/remoting/signaling/ftl_registration_manager.h
index 6c67d43a..18e5afb 100644
--- a/remoting/signaling/ftl_registration_manager.h
+++ b/remoting/signaling/ftl_registration_manager.h
@@ -10,34 +10,31 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
 #include "remoting/signaling/ftl_services.grpc.pb.h"
+#include "remoting/signaling/registration_manager.h"
 
 namespace remoting {
 
 class FtlDeviceIdProvider;
-class FtlGrpcContext;
+class GrpcExecutor;
+class OAuthTokenGetter;
 
 // Class for registering the user with FTL service.
 // TODO(yuweih): Add unittest
-class FtlRegistrationManager final {
+class FtlRegistrationManager final : public RegistrationManager {
  public:
-  using DoneCallback = base::OnceCallback<void(const grpc::Status& status)>;
-
+  // |token_getter| must outlive |this|.
   FtlRegistrationManager(
-      FtlGrpcContext* context,
+      OAuthTokenGetter* token_getter,
       std::unique_ptr<FtlDeviceIdProvider> device_id_provider);
-  ~FtlRegistrationManager();
+  ~FtlRegistrationManager() override;
 
-  // Performs a SignInGaia call for this device. |on_done| is called once it has
-  // successfully signed in or failed to sign in.
-  void SignInGaia(DoneCallback on_done);
-
-  bool IsSignedIn() const;
-
-  // Returns empty string if user hasn't been signed in.
-  const std::string& registration_id() const { return registration_id_; }
+  // RegistrationManager implementations.
+  void SignInGaia(DoneCallback on_done) override;
+  bool IsSignedIn() const override;
+  std::string GetRegistrationId() const override;
+  std::string GetFtlAuthToken() const override;
 
  private:
   using Registration =
@@ -47,13 +44,13 @@
                             const grpc::Status& status,
                             const ftl::SignInGaiaResponse& response);
 
-  FtlGrpcContext* context_;
+  std::unique_ptr<GrpcExecutor> executor_;
   std::unique_ptr<FtlDeviceIdProvider> device_id_provider_;
   std::unique_ptr<Registration::Stub> registration_stub_;
   base::OneShotTimer sign_in_refresh_timer_;
   std::string registration_id_;
+  std::string ftl_auth_token_;
 
-  base::WeakPtrFactory<FtlRegistrationManager> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(FtlRegistrationManager);
 };
 
diff --git a/remoting/signaling/grpc_support/BUILD.gn b/remoting/signaling/grpc_support/BUILD.gn
index 1c85d7ba..b71884e 100644
--- a/remoting/signaling/grpc_support/BUILD.gn
+++ b/remoting/signaling/grpc_support/BUILD.gn
@@ -13,9 +13,15 @@
     "grpc_async_server_streaming_request.cc",
     "grpc_async_server_streaming_request.h",
     "grpc_async_unary_request.h",
+    "grpc_authenticated_executor.cc",
+    "grpc_authenticated_executor.h",
+    "grpc_channel.cc",
+    "grpc_channel.h",
     "grpc_executor.h",
+    "root_certs_prod.inc",
     "scoped_grpc_server_stream.cc",
     "scoped_grpc_server_stream.h",
+    "using_grpc_channel_shared_ptr.inc",
   ]
 
   deps = [
@@ -51,6 +57,7 @@
 
   sources = [
     "grpc_async_executor_unittest.cc",
+    "grpc_authenticated_executor_unittest.cc",
   ]
   deps = [
     ":grpc_support",
diff --git a/remoting/signaling/grpc_support/README.md b/remoting/signaling/grpc_support/README.md
index 2b8859f..ba79dbb 100644
--- a/remoting/signaling/grpc_support/README.md
+++ b/remoting/signaling/grpc_support/README.md
@@ -78,3 +78,9 @@
   std::unique_ptr<ScopedGrpcServerStream> scoped_hello_stream_;
 };
 ```
+
+## Using GrpcAuthenticatedExecutor
+
+GrpcAuthenticatedExecutor allows you to execute RPCs and authenticate them
+with `remoting::OAuthTokenGetter`. The usage is basically the same as
+`GrpcAsyncExecutor`.
diff --git a/remoting/signaling/grpc_support/grpc_async_test_server.cc b/remoting/signaling/grpc_support/grpc_async_test_server.cc
index bc65ffc39..797a7858 100644
--- a/remoting/signaling/grpc_support/grpc_async_test_server.cc
+++ b/remoting/signaling/grpc_support/grpc_async_test_server.cc
@@ -31,7 +31,7 @@
   }
 }
 
-std::shared_ptr<grpc::Channel> GrpcAsyncTestServer::CreateInProcessChannel() {
+GrpcChannelSharedPtr GrpcAsyncTestServer::CreateInProcessChannel() {
   return server_->InProcessChannel(grpc::ChannelArguments());
 }
 
diff --git a/remoting/signaling/grpc_support/grpc_async_test_server.h b/remoting/signaling/grpc_support/grpc_async_test_server.h
index 82140148..93ed11c 100644
--- a/remoting/signaling/grpc_support/grpc_async_test_server.h
+++ b/remoting/signaling/grpc_support/grpc_async_test_server.h
@@ -8,13 +8,13 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "remoting/signaling/grpc_support/grpc_channel.h"
 #include "remoting/signaling/grpc_support/grpc_test_util.h"
 #include "third_party/grpc/src/include/grpcpp/impl/codegen/service_type.h"
 #include "third_party/grpc/src/include/grpcpp/server.h"
 
 namespace grpc {
 
-class Channel;
 class ServerCompletionQueue;
 class Service;
 
@@ -51,7 +51,7 @@
   explicit GrpcAsyncTestServer(std::unique_ptr<grpc::Service> async_service);
   virtual ~GrpcAsyncTestServer();
 
-  std::shared_ptr<grpc::Channel> CreateInProcessChannel();
+  GrpcChannelSharedPtr CreateInProcessChannel();
 
   // Accepts a request by calling |request_func|, writes the request to
   // |out_request|, and returns a responder for sending response to the client.
diff --git a/remoting/signaling/grpc_support/grpc_authenticated_executor.cc b/remoting/signaling/grpc_support/grpc_authenticated_executor.cc
new file mode 100644
index 0000000..0edba602
--- /dev/null
+++ b/remoting/signaling/grpc_support/grpc_authenticated_executor.cc
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/signaling/grpc_support/grpc_authenticated_executor.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "remoting/signaling/grpc_support/grpc_async_executor.h"
+#include "remoting/signaling/grpc_support/grpc_async_request.h"
+#include "third_party/grpc/src/include/grpcpp/client_context.h"
+#include "third_party/grpc/src/include/grpcpp/security/credentials.h"
+
+namespace remoting {
+
+GrpcAuthenticatedExecutor::GrpcAuthenticatedExecutor(
+    OAuthTokenGetter* token_getter)
+    : weak_factory_(this) {
+  DCHECK(token_getter);
+  token_getter_ = token_getter;
+  executor_ = std::make_unique<GrpcAsyncExecutor>();
+}
+
+GrpcAuthenticatedExecutor::~GrpcAuthenticatedExecutor() = default;
+
+void GrpcAuthenticatedExecutor::ExecuteRpc(
+    std::unique_ptr<GrpcAsyncRequest> request) {
+  token_getter_->CallWithToken(base::BindOnce(
+      &GrpcAuthenticatedExecutor::ExecuteRpcWithFetchedOAuthToken,
+      weak_factory_.GetWeakPtr(), std::move(request)));
+}
+
+void GrpcAuthenticatedExecutor::ExecuteRpcWithFetchedOAuthToken(
+    std::unique_ptr<GrpcAsyncRequest> request,
+    OAuthTokenGetter::Status status,
+    const std::string& user_email,
+    const std::string& access_token) {
+  if (status != OAuthTokenGetter::Status::SUCCESS) {
+    LOG(ERROR) << "Failed to fetch access token. Status: " << status;
+  }
+  if (status == OAuthTokenGetter::Status::SUCCESS && !access_token.empty()) {
+    request->context()->set_credentials(
+        grpc::AccessTokenCredentials(access_token));
+  } else {
+    LOG(WARNING) << "Attempting to execute RPC without access token.";
+  }
+  executor_->ExecuteRpc(std::move(request));
+}
+
+}  // namespace remoting
diff --git a/remoting/signaling/grpc_support/grpc_authenticated_executor.h b/remoting/signaling/grpc_support/grpc_authenticated_executor.h
new file mode 100644
index 0000000..9e8f181
--- /dev/null
+++ b/remoting/signaling/grpc_support/grpc_authenticated_executor.h
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_
+#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "remoting/base/oauth_token_getter.h"
+#include "remoting/signaling/grpc_support/grpc_executor.h"
+
+namespace remoting {
+
+class GrpcAsyncRequest;
+
+// Class to execute gRPC request with OAuth authentication.
+class GrpcAuthenticatedExecutor final : public GrpcExecutor {
+ public:
+  // |token_getter| must outlive |this|.
+  explicit GrpcAuthenticatedExecutor(OAuthTokenGetter* token_getter);
+
+  ~GrpcAuthenticatedExecutor() override;
+
+  // GrpcExecutor implementation.
+  void ExecuteRpc(std::unique_ptr<GrpcAsyncRequest> request) override;
+
+ private:
+  friend class GrpcAuthenticatedExecutorTest;
+
+  void ExecuteRpcWithFetchedOAuthToken(
+      std::unique_ptr<GrpcAsyncRequest> request,
+      OAuthTokenGetter::Status status,
+      const std::string& user_email,
+      const std::string& access_token);
+
+  OAuthTokenGetter* token_getter_;
+  std::unique_ptr<GrpcExecutor> executor_;
+
+  base::WeakPtrFactory<GrpcAuthenticatedExecutor> weak_factory_;
+  DISALLOW_COPY_AND_ASSIGN(GrpcAuthenticatedExecutor);
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_
diff --git a/remoting/signaling/grpc_support/grpc_authenticated_executor_unittest.cc b/remoting/signaling/grpc_support/grpc_authenticated_executor_unittest.cc
new file mode 100644
index 0000000..987be91e
--- /dev/null
+++ b/remoting/signaling/grpc_support/grpc_authenticated_executor_unittest.cc
@@ -0,0 +1,76 @@
+// 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 "remoting/signaling/grpc_support/grpc_authenticated_executor.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/test/scoped_task_environment.h"
+#include "remoting/base/fake_oauth_token_getter.h"
+#include "remoting/base/oauth_token_getter.h"
+#include "remoting/signaling/grpc_support/grpc_async_unary_request.h"
+#include "remoting/signaling/grpc_support/grpc_support_test_services.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace remoting {
+
+namespace {
+
+using testing::_;
+using testing::Invoke;
+
+class MockExecutor : public GrpcExecutor {
+ public:
+  MOCK_METHOD1(ExecuteRpc, void(std::unique_ptr<GrpcAsyncRequest>));
+};
+
+}  // namespace
+
+class GrpcAuthenticatedExecutorTest : public testing::Test {
+ public:
+  void SetUp() override;
+
+ protected:
+  MockExecutor* mock_executor_;
+  std::unique_ptr<GrpcAuthenticatedExecutor> executor_;
+
+ private:
+  FakeOAuthTokenGetter token_getter_{OAuthTokenGetter::Status::SUCCESS,
+                                     "fake_user", "fake_token"};
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
+void GrpcAuthenticatedExecutorTest::SetUp() {
+  executor_ = std::make_unique<GrpcAuthenticatedExecutor>(&token_getter_);
+  auto mock_executor = std::make_unique<MockExecutor>();
+  mock_executor_ = mock_executor.get();
+  executor_->executor_ = std::move(mock_executor);
+}
+
+// Unfortunately we can't verify whether the credentials are set because
+// grpc::ClientContext has not getter for the credentials.
+TEST_F(GrpcAuthenticatedExecutorTest, VerifyExecuteRpcCallIsForwarded) {
+  base::RunLoop run_loop;
+  auto request = CreateGrpcAsyncUnaryRequest(
+      base::BindOnce([](grpc::ClientContext*, const EchoRequest&,
+                        grpc::CompletionQueue*) {
+        return std::unique_ptr<grpc::ClientAsyncResponseReader<EchoResponse>>();
+      }),
+      std::make_unique<grpc::ClientContext>(), EchoRequest(),
+      base::DoNothing::Once<const grpc::Status&, const EchoResponse&>());
+  auto* request_ptr = request.get();
+  EXPECT_CALL(*mock_executor_, ExecuteRpc(_))
+      .WillOnce(Invoke([&](std::unique_ptr<GrpcAsyncRequest> request) {
+        ASSERT_EQ(request_ptr, request.get());
+        run_loop.QuitWhenIdle();
+      }));
+  executor_->ExecuteRpc(std::move(request));
+  run_loop.Run();
+}
+
+}  // namespace remoting
diff --git a/remoting/signaling/grpc_support/grpc_channel.cc b/remoting/signaling/grpc_support/grpc_channel.cc
new file mode 100644
index 0000000..b926a694
--- /dev/null
+++ b/remoting/signaling/grpc_support/grpc_channel.cc
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/signaling/grpc_support/grpc_channel.h"
+
+#include "third_party/grpc/src/include/grpcpp/grpcpp.h"
+
+namespace remoting {
+
+namespace {
+
+#include "remoting/signaling/grpc_support/root_certs_prod.inc"
+
+}  // namespace
+
+GrpcChannelSharedPtr CreateSslChannelForEndpoint(const std::string& endpoint) {
+  static const grpc::SslCredentialsOptions cred_options{certs_pem, {}, {}};
+  auto channel_creds = grpc::SslCredentials(cred_options);
+  return grpc::CreateChannel(endpoint, channel_creds);
+}
+
+}  // namespace remoting
diff --git a/remoting/signaling/grpc_support/grpc_channel.h b/remoting/signaling/grpc_support/grpc_channel.h
new file mode 100644
index 0000000..8631fd3
--- /dev/null
+++ b/remoting/signaling/grpc_support/grpc_channel.h
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_CHANNEL_H_
+#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_CHANNEL_H_
+
+#include <memory>
+
+#include "third_party/grpc/src/include/grpcpp/channel.h"
+
+namespace remoting {
+
+// TODO(yuweih): See if you should create a wrapper for the shared pointer.
+#include "remoting/signaling/grpc_support/using_grpc_channel_shared_ptr.inc"
+
+GrpcChannelSharedPtr CreateSslChannelForEndpoint(const std::string& endpoint);
+
+}  // namespace remoting
+
+#endif  // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_CHANNEL_H_
diff --git a/remoting/signaling/grpc_support/root_certs_prod.inc b/remoting/signaling/grpc_support/root_certs_prod.inc
new file mode 100644
index 0000000..12034d7
--- /dev/null
+++ b/remoting/signaling/grpc_support/root_certs_prod.inc
@@ -0,0 +1,1424 @@
+// 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.
+
+// TODO(yuweih): Delete this file once root certs file is checked into Chromium
+// third_party.
+
+// Downloaded from https://pki.goog/roots.pem
+constexpr char certs_pem[] =
+    "# Operating CA: Comodo Group\n"
+    "# Issuer: CN=AAA Certificate Services O=Comodo CA Limited\n"
+    "# Subject: CN=AAA Certificate Services O=Comodo CA Limited\n"
+    "# Label: \"Comodo AAA Services root\"\n"
+    "# Serial: 1\n"
+    "# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0\n"
+    "# SHA1 Fingerprint: "
+    "d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49\n"
+    "# SHA256 Fingerprint: "
+    "d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:"
+    "2b:c8:3e:e0:ea:69:9e:f4\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\n"
+    "MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\n"
+    "GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\n"
+    "YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\n"
+    "MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n"
+    "BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\n"
+    "GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\n"
+    "ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\n"
+    "BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n"
+    "3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\n"
+    "YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\n"
+    "rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\n"
+    "ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\n"
+    "oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\n"
+    "MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\n"
+    "QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\n"
+    "b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\n"
+    "AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\n"
+    "GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\n"
+    "Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\n"
+    "G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\n"
+    "l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\n"
+    "smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Comodo Group\n"
+    "# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External "
+    "TTP Network\n"
+    "# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust "
+    "External TTP Network\n"
+    "# Label: \"AddTrust External Root\"\n"
+    "# Serial: 1\n"
+    "# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f\n"
+    "# SHA1 Fingerprint: "
+    "02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68\n"
+    "# SHA256 Fingerprint: "
+    "68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:"
+    "fb:83:d9:65:d0:6d:2f:f2\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU\n"
+    "MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs\n"
+    "IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290\n"
+    "MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux\n"
+    "FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h\n"
+    "bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v\n"
+    "dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt\n"
+    "H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9\n"
+    "uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX\n"
+    "mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX\n"
+    "a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN\n"
+    "E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0\n"
+    "WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD\n"
+    "VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0\n"
+    "Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\n"
+    "cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx\n"
+    "IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN\n"
+    "AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH\n"
+    "YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5\n"
+    "6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC\n"
+    "Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX\n"
+    "c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a\n"
+    "mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Comodo Group\n"
+    "# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited\n"
+    "# Subject: CN=COMODO Certification Authority O=COMODO CA Limited\n"
+    "# Label: \"COMODO Certification Authority\"\n"
+    "# Serial: 104350513648249232941998508985834464573\n"
+    "# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75\n"
+    "# SHA1 Fingerprint: "
+    "66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b\n"
+    "# SHA256 Fingerprint: "
+    "0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:"
+    "8c:86:05:03:17:8b:af:66\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB\n"
+    "gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n"
+    "A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV\n"
+    "BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw\n"
+    "MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl\n"
+    "YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P\n"
+    "RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0\n"
+    "aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3\n"
+    "UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI\n"
+    "2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8\n"
+    "Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp\n"
+    "+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+\n"
+    "DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O\n"
+    "nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW\n"
+    "/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g\n"
+    "PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u\n"
+    "QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY\n"
+    "SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv\n"
+    "IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/\n"
+    "RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4\n"
+    "zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd\n"
+    "BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB\n"
+    "ZQ==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Comodo Group\n"
+    "# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited\n"
+    "# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited\n"
+    "# Label: \"COMODO ECC Certification Authority\"\n"
+    "# Serial: 41578283867086692638256921589707938090\n"
+    "# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23\n"
+    "# SHA1 Fingerprint: "
+    "9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11\n"
+    "# SHA256 Fingerprint: "
+    "17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:"
+    "21:ec:15:db:ba:4f:ad:c7\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL\n"
+    "MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n"
+    "BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT\n"
+    "IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw\n"
+    "MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy\n"
+    "ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N\n"
+    "T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv\n"
+    "biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR\n"
+    "FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J\n"
+    "cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW\n"
+    "BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\n"
+    "BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm\n"
+    "fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv\n"
+    "GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Comodo Group\n"
+    "# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited\n"
+    "# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited\n"
+    "# Label: \"COMODO RSA Certification Authority\"\n"
+    "# Serial: 101909084537582093308941363524873193117\n"
+    "# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18\n"
+    "# SHA1 Fingerprint: "
+    "af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4\n"
+    "# SHA256 Fingerprint: "
+    "52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:"
+    "34:63:53:4b:32:b4:02:34\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB\n"
+    "hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n"
+    "A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV\n"
+    "BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5\n"
+    "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT\n"
+    "EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\n"
+    "Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh\n"
+    "dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR\n"
+    "6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X\n"
+    "pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC\n"
+    "9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV\n"
+    "/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf\n"
+    "Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z\n"
+    "+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w\n"
+    "qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah\n"
+    "SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC\n"
+    "u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf\n"
+    "Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq\n"
+    "crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\n"
+    "FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB\n"
+    "/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl\n"
+    "wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM\n"
+    "4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV\n"
+    "2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna\n"
+    "FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ\n"
+    "CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK\n"
+    "boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke\n"
+    "jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL\n"
+    "S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb\n"
+    "QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl\n"
+    "0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB\n"
+    "NVOFBkpdn627G190\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Comodo Group\n"
+    "# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST "
+    "Network\n"
+    "# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST "
+    "Network\n"
+    "# Label: \"USERTrust ECC Certification Authority\"\n"
+    "# Serial: 123013823720199481456569720443997572134\n"
+    "# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1\n"
+    "# SHA1 Fingerprint: "
+    "d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0\n"
+    "# SHA256 Fingerprint: "
+    "4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:"
+    "86:e0:6a:dc:d2:a9:ad:7a\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL\n"
+    "MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\n"
+    "eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\n"
+    "JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx\n"
+    "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n"
+    "Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg\n"
+    "VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm\n"
+    "aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo\n"
+    "I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng\n"
+    "o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G\n"
+    "A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD\n"
+    "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB\n"
+    "zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW\n"
+    "RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Comodo Group\n"
+    "# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST "
+    "Network\n"
+    "# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST "
+    "Network\n"
+    "# Label: \"USERTrust RSA Certification Authority\"\n"
+    "# Serial: 2645093764781058787591871645665788717\n"
+    "# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5\n"
+    "# SHA1 Fingerprint: "
+    "2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e\n"
+    "# SHA256 Fingerprint: "
+    "e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:"
+    "b1:74:6d:46:c3:d4:cb:d2\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB\n"
+    "iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n"
+    "cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n"
+    "BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw\n"
+    "MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV\n"
+    "BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\n"
+    "aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy\n"
+    "dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n"
+    "AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B\n"
+    "3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY\n"
+    "tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/\n"
+    "Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2\n"
+    "VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT\n"
+    "79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6\n"
+    "c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT\n"
+    "Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l\n"
+    "c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee\n"
+    "UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE\n"
+    "Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\n"
+    "BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G\n"
+    "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF\n"
+    "Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO\n"
+    "VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3\n"
+    "ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs\n"
+    "8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR\n"
+    "iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze\n"
+    "Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ\n"
+    "XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/\n"
+    "qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB\n"
+    "VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB\n"
+    "L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG\n"
+    "jjxDah2nGN59PRbxYvnKkKj9\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust\n"
+    "# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust\n"
+    "# Label: \"Baltimore CyberTrust Root\"\n"
+    "# Serial: 33554617\n"
+    "# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4\n"
+    "# SHA1 Fingerprint: "
+    "d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74\n"
+    "# SHA256 Fingerprint: "
+    "16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:"
+    "cd:4b:93:db:f3:f2:6a:eb\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n"
+    "RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\n"
+    "VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\n"
+    "DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\n"
+    "ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\n"
+    "VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\n"
+    "mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\n"
+    "IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\n"
+    "mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\n"
+    "XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\n"
+    "dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\n"
+    "jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\n"
+    "BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\n"
+    "DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n"
+    "9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n"
+    "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\n"
+    "Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n"
+    "ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n"
+    "R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc\n"
+    "# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc\n"
+    "# Label: \"Cybertrust Global Root\"\n"
+    "# Serial: 4835703278459682877484360\n"
+    "# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1\n"
+    "# SHA1 Fingerprint: "
+    "5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6\n"
+    "# SHA256 Fingerprint: "
+    "96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:"
+    "ea:fb:23:49:ab:39:3d:a3\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG\n"
+    "A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh\n"
+    "bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE\n"
+    "ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS\n"
+    "b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5\n"
+    "7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS\n"
+    "J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y\n"
+    "HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP\n"
+    "t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz\n"
+    "FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY\n"
+    "XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/\n"
+    "MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw\n"
+    "hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js\n"
+    "MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA\n"
+    "A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj\n"
+    "Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx\n"
+    "XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o\n"
+    "omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc\n"
+    "A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW\n"
+    "WL1WMRJOEcgh4LMRkWXbtKaIOM5V\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Label: \"DigiCert Assured ID Root CA\"\n"
+    "# Serial: 17154717934120587862167794914071425081\n"
+    "# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72\n"
+    "# SHA1 Fingerprint: "
+    "05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43\n"
+    "# SHA256 Fingerprint: "
+    "3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:"
+    "df:69:56:1e:3d:c6:32:5c\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl\n"
+    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+    "d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv\n"
+    "b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG\n"
+    "EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl\n"
+    "cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi\n"
+    "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c\n"
+    "JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP\n"
+    "mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+\n"
+    "wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4\n"
+    "VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/\n"
+    "AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB\n"
+    "AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW\n"
+    "BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun\n"
+    "pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC\n"
+    "dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf\n"
+    "fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm\n"
+    "NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx\n"
+    "H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe\n"
+    "+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Label: \"DigiCert Assured ID Root G2\"\n"
+    "# Serial: 15385348160840213938643033620894905419\n"
+    "# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d\n"
+    "# SHA1 Fingerprint: "
+    "a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f\n"
+    "# SHA256 Fingerprint: "
+    "7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:"
+    "49:45:2f:ab:7d:2f:c1:85\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl\n"
+    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+    "d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv\n"
+    "b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG\n"
+    "EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl\n"
+    "cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi\n"
+    "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA\n"
+    "n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc\n"
+    "biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp\n"
+    "EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA\n"
+    "bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu\n"
+    "YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB\n"
+    "AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW\n"
+    "BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI\n"
+    "QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I\n"
+    "0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni\n"
+    "lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9\n"
+    "B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv\n"
+    "ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo\n"
+    "IhNzbM8m9Yop5w==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Label: \"DigiCert Assured ID Root G3\"\n"
+    "# Serial: 15459312981008553731928384953135426796\n"
+    "# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb\n"
+    "# SHA1 Fingerprint: "
+    "f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89\n"
+    "# SHA256 Fingerprint: "
+    "7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:"
+    "b1:00:71:7f:43:05:3f:c2\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw\n"
+    "CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\n"
+    "ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg\n"
+    "RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV\n"
+    "UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\n"
+    "Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq\n"
+    "hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf\n"
+    "Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q\n"
+    "RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\n"
+    "BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD\n"
+    "AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY\n"
+    "JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv\n"
+    "6pZjamVFkpUBtA==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com\n"
+    "# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com\n"
+    "# Label: \"DigiCert Global Root CA\"\n"
+    "# Serial: 10944719598952040374951832963794454346\n"
+    "# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e\n"
+    "# SHA1 Fingerprint: "
+    "a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36\n"
+    "# SHA256 Fingerprint: "
+    "43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:"
+    "7f:89:34:a4:43:c7:01:61\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n"
+    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+    "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"
+    "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"
+    "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
+    "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"
+    "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"
+    "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"
+    "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"
+    "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"
+    "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"
+    "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"
+    "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"
+    "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"
+    "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"
+    "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"
+    "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"
+    "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"
+    "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"
+    "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com\n"
+    "# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com\n"
+    "# Label: \"DigiCert Global Root G2\"\n"
+    "# Serial: 4293743540046975378534879503202253541\n"
+    "# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44\n"
+    "# SHA1 Fingerprint: "
+    "df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4\n"
+    "# SHA256 Fingerprint: "
+    "cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:"
+    "ea:27:d4:6a:5a:b1:cb:5f\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\n"
+    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+    "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n"
+    "MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\n"
+    "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
+    "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n"
+    "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n"
+    "2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n"
+    "1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\n"
+    "q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\n"
+    "tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\n"
+    "vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\n"
+    "BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n"
+    "5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n"
+    "1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\n"
+    "NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\n"
+    "Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n"
+    "8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\n"
+    "pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n"
+    "MrY=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com\n"
+    "# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com\n"
+    "# Label: \"DigiCert Global Root G3\"\n"
+    "# Serial: 7089244469030293291760083333884364146\n"
+    "# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca\n"
+    "# SHA1 Fingerprint: "
+    "7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e\n"
+    "# SHA256 Fingerprint: "
+    "31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:"
+    "f9:7c:2a:c9:ef:67:31:d0\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw\n"
+    "CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\n"
+    "ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe\n"
+    "Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw\n"
+    "EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x\n"
+    "IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF\n"
+    "K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG\n"
+    "fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO\n"
+    "Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd\n"
+    "BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx\n"
+    "AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/\n"
+    "oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8\n"
+    "sycX\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Label: \"DigiCert High Assurance EV Root CA\"\n"
+    "# Serial: 3553400076410547919724730734378100087\n"
+    "# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a\n"
+    "# SHA1 Fingerprint: "
+    "5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25\n"
+    "# SHA256 Fingerprint: "
+    "74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:"
+    "ab:d7:80:6e:d3:b1:18:cf\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n"
+    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+    "d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n"
+    "ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n"
+    "MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n"
+    "LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n"
+    "RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n"
+    "+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n"
+    "PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n"
+    "xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n"
+    "Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n"
+    "hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n"
+    "EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n"
+    "MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n"
+    "FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n"
+    "nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n"
+    "eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n"
+    "hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n"
+    "Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n"
+    "vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n"
+    "+OkuE6N36B9K\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com\n"
+    "# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc "
+    "OU=www.digicert.com\n"
+    "# Label: \"DigiCert Trusted Root G4\"\n"
+    "# Serial: 7451500558977370777930084869016614236\n"
+    "# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49\n"
+    "# SHA1 Fingerprint: "
+    "dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4\n"
+    "# SHA256 Fingerprint: "
+    "55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:"
+    "03:d1:d9:d2:0a:c8:99:88\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi\n"
+    "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+    "d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg\n"
+    "RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV\n"
+    "UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\n"
+    "Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG\n"
+    "SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y\n"
+    "ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If\n"
+    "xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV\n"
+    "ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO\n"
+    "DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ\n"
+    "jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/\n"
+    "CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi\n"
+    "EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM\n"
+    "fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY\n"
+    "uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK\n"
+    "chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t\n"
+    "9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB\n"
+    "hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD\n"
+    "ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2\n"
+    "SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd\n"
+    "+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc\n"
+    "fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa\n"
+    "sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N\n"
+    "cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N\n"
+    "0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie\n"
+    "4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI\n"
+    "r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1\n"
+    "/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm\n"
+    "gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: DigiCert\n"
+    "# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc.\n"
+    "# Subject: CN=GeoTrust Global CA O=GeoTrust Inc.\n"
+    "# Label: \"GeoTrust Global CA\"\n"
+    "# Serial: 144470\n"
+    "# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5\n"
+    "# SHA1 Fingerprint: "
+    "de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12\n"
+    "# SHA256 Fingerprint: "
+    "ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:"
+    "2d:e4:d2:b5:db:36:a7:3a\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n"
+    "MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\n"
+    "YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG\n"
+    "EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg\n"
+    "R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9\n"
+    "9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq\n"
+    "fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv\n"
+    "iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU\n"
+    "1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\n"
+    "bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW\n"
+    "MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA\n"
+    "ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l\n"
+    "uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn\n"
+    "Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS\n"
+    "tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n"
+    "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un\n"
+    "hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV\n"
+    "5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Entrust Datacard\n"
+    "# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. "
+    "OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, "
+    "Inc.\n"
+    "# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. "
+    "OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, "
+    "Inc.\n"
+    "# Label: \"Entrust Root Certification Authority\"\n"
+    "# Serial: 1164660820\n"
+    "# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4\n"
+    "# SHA1 Fingerprint: "
+    "b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9\n"
+    "# SHA256 Fingerprint: "
+    "73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:"
+    "14:1a:2b:2c:bc:7d:8e:4c\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC\n"
+    "VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0\n"
+    "Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW\n"
+    "KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl\n"
+    "cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw\n"
+    "NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw\n"
+    "NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy\n"
+    "ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV\n"
+    "BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ\n"
+    "KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo\n"
+    "Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4\n"
+    "4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9\n"
+    "KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI\n"
+    "rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi\n"
+    "94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB\n"
+    "sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi\n"
+    "gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo\n"
+    "kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE\n"
+    "vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\n"
+    "A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t\n"
+    "O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua\n"
+    "AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP\n"
+    "9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/\n"
+    "eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m\n"
+    "0vdXcDazv/wor3ElhVsT/h5/WrQ8\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Entrust Datacard\n"
+    "# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. "
+    "OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for "
+    "authorized use only\n"
+    "# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. "
+    "OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for "
+    "authorized use only\n"
+    "# Label: \"Entrust Root Certification Authority - EC1\"\n"
+    "# Serial: 51543124481930649114116133369\n"
+    "# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc\n"
+    "# SHA1 Fingerprint: "
+    "20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47\n"
+    "# SHA256 Fingerprint: "
+    "02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:"
+    "3b:8e:b0:70:e5:6e:df:f5\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG\n"
+    "A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3\n"
+    "d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu\n"
+    "dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq\n"
+    "RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy\n"
+    "MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD\n"
+    "VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0\n"
+    "L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g\n"
+    "Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD\n"
+    "ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi\n"
+    "A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt\n"
+    "ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH\n"
+    "Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O\n"
+    "BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC\n"
+    "R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX\n"
+    "hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Entrust Datacard\n"
+    "# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. "
+    "OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for "
+    "authorized use only\n"
+    "# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. "
+    "OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for "
+    "authorized use only\n"
+    "# Label: \"Entrust Root Certification Authority - G2\"\n"
+    "# Serial: 1246989352\n"
+    "# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2\n"
+    "# SHA1 Fingerprint: "
+    "8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4\n"
+    "# SHA256 Fingerprint: "
+    "43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:"
+    "38:41:10:3d:3a:a7:f3:39\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC\n"
+    "VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50\n"
+    "cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs\n"
+    "IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz\n"
+    "dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy\n"
+    "NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu\n"
+    "dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt\n"
+    "dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0\n"
+    "aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj\n"
+    "YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n"
+    "AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T\n"
+    "RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN\n"
+    "cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW\n"
+    "wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1\n"
+    "U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0\n"
+    "jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP\n"
+    "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN\n"
+    "BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/\n"
+    "jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ\n"
+    "Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v\n"
+    "1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R\n"
+    "nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH\n"
+    "VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Entrust Datacard\n"
+    "# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net "
+    "OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 "
+    "Entrust.net Limited\n"
+    "# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net "
+    "OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 "
+    "Entrust.net Limited\n"
+    "# Label: \"Entrust.net Premium 2048 Secure Server CA\"\n"
+    "# Serial: 946069240\n"
+    "# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90\n"
+    "# SHA1 Fingerprint: "
+    "50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31\n"
+    "# SHA256 Fingerprint: "
+    "6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:"
+    "10:b9:c8:37:d2:1e:b1:77\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML\n"
+    "RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp\n"
+    "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5\n"
+    "IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp\n"
+    "ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3\n"
+    "MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3\n"
+    "LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp\n"
+    "YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG\n"
+    "A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp\n"
+    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq\n"
+    "K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe\n"
+    "sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX\n"
+    "MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT\n"
+    "XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/\n"
+    "HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n"
+    "4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n"
+    "HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub\n"
+    "j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo\n"
+    "U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf\n"
+    "zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b\n"
+    "u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+\n"
+    "bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er\n"
+    "fF6adulZkMV8gzURZVE=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Entrust Datacard\n"
+    "# Issuer: CN=AffirmTrust Commercial O=AffirmTrust\n"
+    "# Subject: CN=AffirmTrust Commercial O=AffirmTrust\n"
+    "# Label: \"AffirmTrust Commercial\"\n"
+    "# Serial: 8608355977964138876\n"
+    "# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7\n"
+    "# SHA1 Fingerprint: "
+    "f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7\n"
+    "# SHA256 Fingerprint: "
+    "03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:"
+    "9b:8d:48:60:c9:6f:5f:a7\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE\n"
+    "BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz\n"
+    "dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL\n"
+    "MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp\n"
+    "cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n"
+    "AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP\n"
+    "Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr\n"
+    "ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL\n"
+    "MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1\n"
+    "yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr\n"
+    "VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/\n"
+    "nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ\n"
+    "KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG\n"
+    "XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj\n"
+    "vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt\n"
+    "Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g\n"
+    "N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC\n"
+    "nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Entrust Datacard\n"
+    "# Issuer: CN=AffirmTrust Networking O=AffirmTrust\n"
+    "# Subject: CN=AffirmTrust Networking O=AffirmTrust\n"
+    "# Label: \"AffirmTrust Networking\"\n"
+    "# Serial: 8957382827206547757\n"
+    "# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f\n"
+    "# SHA1 Fingerprint: "
+    "29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f\n"
+    "# SHA256 Fingerprint: "
+    "0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:"
+    "05:8b:0e:17:f3:f0:b4:1b\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE\n"
+    "BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz\n"
+    "dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL\n"
+    "MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp\n"
+    "cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n"
+    "AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y\n"
+    "YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua\n"
+    "kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL\n"
+    "QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp\n"
+    "6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG\n"
+    "yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i\n"
+    "QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ\n"
+    "KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO\n"
+    "tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu\n"
+    "QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ\n"
+    "Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u\n"
+    "olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48\n"
+    "x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Entrust Datacard\n"
+    "# Issuer: CN=AffirmTrust Premium O=AffirmTrust\n"
+    "# Subject: CN=AffirmTrust Premium O=AffirmTrust\n"
+    "# Label: \"AffirmTrust Premium\"\n"
+    "# Serial: 7893706540734352110\n"
+    "# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57\n"
+    "# SHA1 Fingerprint: "
+    "d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27\n"
+    "# SHA256 Fingerprint: "
+    "70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:"
+    "f5:25:77:eb:f2:e9:3b:9a\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE\n"
+    "BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz\n"
+    "dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG\n"
+    "A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U\n"
+    "cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf\n"
+    "qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ\n"
+    "JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ\n"
+    "+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS\n"
+    "s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5\n"
+    "HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7\n"
+    "70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG\n"
+    "V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S\n"
+    "qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S\n"
+    "5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia\n"
+    "C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX\n"
+    "OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE\n"
+    "FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\n"
+    "BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2\n"
+    "KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg\n"
+    "Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B\n"
+    "8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ\n"
+    "MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc\n"
+    "0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ\n"
+    "u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF\n"
+    "u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH\n"
+    "YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8\n"
+    "GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO\n"
+    "RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e\n"
+    "KeC2uAloGRwYQw==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Entrust Datacard\n"
+    "# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust\n"
+    "# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust\n"
+    "# Label: \"AffirmTrust Premium ECC\"\n"
+    "# Serial: 8401224907861490260\n"
+    "# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d\n"
+    "# SHA1 Fingerprint: "
+    "b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb\n"
+    "# SHA256 Fingerprint: "
+    "bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:"
+    "ba:9c:5e:84:88:82:14:23\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC\n"
+    "VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ\n"
+    "cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ\n"
+    "BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt\n"
+    "VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D\n"
+    "0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9\n"
+    "ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G\n"
+    "A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G\n"
+    "A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs\n"
+    "aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I\n"
+    "flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: GlobalSign\n"
+    "# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA\n"
+    "# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA\n"
+    "# Label: \"GlobalSign Root CA\"\n"
+    "# Serial: 4835703278459707669005204\n"
+    "# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a\n"
+    "# SHA1 Fingerprint: "
+    "b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c\n"
+    "# SHA256 Fingerprint: "
+    "eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:"
+    "f3:c1:df:6c:d4:33:1c:99\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n"
+    "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n"
+    "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n"
+    "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n"
+    "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n"
+    "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n"
+    "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n"
+    "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n"
+    "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n"
+    "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n"
+    "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n"
+    "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n"
+    "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n"
+    "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n"
+    "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n"
+    "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n"
+    "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n"
+    "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n"
+    "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: GlobalSign\n"
+    "# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3\n"
+    "# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3\n"
+    "# Label: \"GlobalSign Root CA - R3\"\n"
+    "# Serial: 4835703278459759426209954\n"
+    "# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28\n"
+    "# SHA1 Fingerprint: "
+    "d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad\n"
+    "# SHA256 Fingerprint: "
+    "cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:"
+    "7c:f4:72:0d:c9:63:c5:3b\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G\n"
+    "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp\n"
+    "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4\n"
+    "MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG\n"
+    "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n"
+    "hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8\n"
+    "RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT\n"
+    "gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm\n"
+    "KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd\n"
+    "QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ\n"
+    "XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw\n"
+    "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o\n"
+    "LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU\n"
+    "RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp\n"
+    "jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK\n"
+    "6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX\n"
+    "mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs\n"
+    "Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH\n"
+    "WD9f\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: GlobalSign\n"
+    "# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5\n"
+    "# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5\n"
+    "# Label: \"GlobalSign ECC Root CA - R5\"\n"
+    "# Serial: 32785792099990507226680698011560947931244\n"
+    "# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08\n"
+    "# SHA1 Fingerprint: "
+    "1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa\n"
+    "# SHA256 Fingerprint: "
+    "17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:"
+    "13:f6:eb:ec:10:0c:89:24\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk\n"
+    "MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH\n"
+    "bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\n"
+    "DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\n"
+    "QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\n"
+    "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc\n"
+    "8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke\n"
+    "hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD\n"
+    "VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI\n"
+    "KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg\n"
+    "515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO\n"
+    "xwy8p2Fp8fc74SrL+SvzZpA3\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: GlobalSign\n"
+    "# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6\n"
+    "# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6\n"
+    "# Label: \"GlobalSign Root CA - R6\"\n"
+    "# Serial: 1417766617973444989252670301619537\n"
+    "# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae\n"
+    "# SHA1 Fingerprint: "
+    "80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1\n"
+    "# SHA256 Fingerprint: "
+    "2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:"
+    "76:3a:3a:b5:ad:6c:cf:69\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg\n"
+    "MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh\n"
+    "bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx\n"
+    "MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET\n"
+    "MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ\n"
+    "KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI\n"
+    "xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k\n"
+    "ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD\n"
+    "aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw\n"
+    "LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw\n"
+    "1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX\n"
+    "k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2\n"
+    "SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h\n"
+    "bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n\n"
+    "WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY\n"
+    "rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce\n"
+    "MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD\n"
+    "AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu\n"
+    "bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN\n"
+    "nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt\n"
+    "Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61\n"
+    "55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj\n"
+    "vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf\n"
+    "cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz\n"
+    "oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp\n"
+    "nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs\n"
+    "pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v\n"
+    "JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R\n"
+    "8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4\n"
+    "5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Note: \"GlobalSign Root CA - R7\" not added on purpose. It is P-521.\n"
+    "\n"
+    "# Operating CA: GoDaddy\n"
+    "# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, "
+    "Inc.\n"
+    "# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, "
+    "Inc.\n"
+    "# Label: \"Go Daddy Root Certificate Authority - G2\"\n"
+    "# Serial: 0\n"
+    "# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01\n"
+    "# SHA1 Fingerprint: "
+    "47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b\n"
+    "# SHA256 Fingerprint: "
+    "45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:"
+    "74:9d:d3:ac:a9:19:8e:da\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx\n"
+    "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT\n"
+    "EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp\n"
+    "ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz\n"
+    "NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH\n"
+    "EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE\n"
+    "AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw\n"
+    "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD\n"
+    "E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH\n"
+    "/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy\n"
+    "DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh\n"
+    "GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR\n"
+    "tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA\n"
+    "AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\n"
+    "FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX\n"
+    "WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu\n"
+    "9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr\n"
+    "gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo\n"
+    "2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\n"
+    "LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI\n"
+    "4uJEvlz36hz1\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: GoDaddy\n"
+    "# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield "
+    "Technologies, Inc.\n"
+    "# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield "
+    "Technologies, Inc.\n"
+    "# Label: \"Starfield Root Certificate Authority - G2\"\n"
+    "# Serial: 0\n"
+    "# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96\n"
+    "# SHA1 Fingerprint: "
+    "b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e\n"
+    "# SHA256 Fingerprint: "
+    "2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:"
+    "31:9b:83:91:54:db:b7:f5\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n"
+    "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n"
+    "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n"
+    "ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n"
+    "MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n"
+    "b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n"
+    "aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n"
+    "Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
+    "ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n"
+    "nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n"
+    "HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n"
+    "Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n"
+    "dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n"
+    "HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n"
+    "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n"
+    "CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n"
+    "sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n"
+    "4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n"
+    "8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n"
+    "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n"
+    "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: GoDaddy\n"
+    "# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 "
+    "Certification Authority\n"
+    "# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 "
+    "Certification Authority\n"
+    "# Label: \"Starfield Class 2 CA\"\n"
+    "# Serial: 0\n"
+    "# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24\n"
+    "# SHA1 Fingerprint: "
+    "ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a\n"
+    "# SHA256 Fingerprint: "
+    "14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:"
+    "c8:67:75:21:fb:5f:b6:58\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n"
+    "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n"
+    "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n"
+    "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n"
+    "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n"
+    "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n"
+    "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n"
+    "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n"
+    "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n"
+    "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n"
+    "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n"
+    "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n"
+    "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n"
+    "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n"
+    "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n"
+    "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n"
+    "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n"
+    "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n"
+    "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n"
+    "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n"
+    "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n"
+    "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: GoDaddy\n"
+    "# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification "
+    "Authority\n"
+    "# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification "
+    "Authority\n"
+    "# Label: \"Go Daddy Class 2 CA\"\n"
+    "# Serial: 0\n"
+    "# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67\n"
+    "# SHA1 Fingerprint: "
+    "27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4\n"
+    "# SHA256 Fingerprint: "
+    "c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:"
+    "19:35:0e:81:fe:54:6a:e4\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh\n"
+    "MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE\n"
+    "YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3\n"
+    "MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo\n"
+    "ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg\n"
+    "MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN\n"
+    "ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA\n"
+    "PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w\n"
+    "wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi\n"
+    "EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY\n"
+    "avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+\n"
+    "YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE\n"
+    "sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h\n"
+    "/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5\n"
+    "IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj\n"
+    "YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD\n"
+    "ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy\n"
+    "OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P\n"
+    "TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\n"
+    "HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER\n"
+    "dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf\n"
+    "ReYNnyicsbkqWletNw+vHX/bvZ8=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Google Trust Services LLC\n"
+    "# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2\n"
+    "# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2\n"
+    "# Label: \"GlobalSign Root CA - R2\"\n"
+    "# Serial: 4835703278459682885658125\n"
+    "# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30\n"
+    "# SHA1 Fingerprint: "
+    "75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe\n"
+    "# SHA256 Fingerprint: "
+    "ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:"
+    "6f:5b:4c:99:f4:2c:1b:9e\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G\n"
+    "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp\n"
+    "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1\n"
+    "MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG\n"
+    "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n"
+    "hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL\n"
+    "v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8\n"
+    "eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq\n"
+    "tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n"
+    "C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa\n"
+    "zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB\n"
+    "mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH\n"
+    "V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n\n"
+    "bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG\n"
+    "3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs\n"
+    "J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO\n"
+    "291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS\n"
+    "ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n"
+    "AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\n"
+    "TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Google Trust Services LLC\n"
+    "# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4\n"
+    "# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4\n"
+    "# Label: \"GlobalSign ECC Root CA - R4\"\n"
+    "# Serial: 14367148294922964480859022125800977897474\n"
+    "# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e\n"
+    "# SHA1 Fingerprint: "
+    "69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb\n"
+    "# SHA256 Fingerprint: "
+    "be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:"
+    "62:b4:fb:b7:73:de:22:8c\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk\n"
+    "MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH\n"
+    "bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\n"
+    "DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\n"
+    "QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\n"
+    "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ\n"
+    "FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw\n"
+    "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F\n"
+    "uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX\n"
+    "kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs\n"
+    "ewv4n4Q=\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Google Trust Services LLC\n"
+    "# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1\n"
+    "# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R1\n"
+    "# Label: \"GTS Root R1\"\n"
+    "# Serial: 6e:47:a9:c5:4b:47:0c:0d:ec:33:d0:89:b9:1c:f4:e1\n"
+    "# MD5 Fingerprint: 82:1A:EF:D4:D2:4A:F2:9F:E2:3D:97:06:14:70:72:85\n"
+    "# SHA1 Fingerprint: "
+    "E1:C9:50:E6:EF:22:F8:4C:56:45:72:8B:92:20:60:D7:D5:A7:A3:E8\n"
+    "# SHA256 Fingerprint: "
+    "2A:57:54:71:E3:13:40:BC:21:58:1C:BD:2C:F1:3E:15:84:63:20:3E:CE:94:BC:F9:"
+    "D3:CC:19:6B:F0:9A:54:72\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH\n"
+    "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
+    "QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\n"
+    "MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\n"
+    "cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB\n"
+    "AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM\n"
+    "f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX\n"
+    "mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7\n"
+    "zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P\n"
+    "fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc\n"
+    "vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4\n"
+    "Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp\n"
+    "zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO\n"
+    "Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW\n"
+    "k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+\n"
+    "DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF\n"
+    "lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n"
+    "HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW\n"
+    "Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1\n"
+    "d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z\n"
+    "XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR\n"
+    "gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3\n"
+    "d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv\n"
+    "J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg\n"
+    "DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM\n"
+    "+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy\n"
+    "F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9\n"
+    "SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws\n"
+    "E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Google Trust Services LLC\n"
+    "# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R2\n"
+    "# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R2\n"
+    "# Label: \"GTS Root R2\"\n"
+    "# Serial: 6e:47:a9:c6:5a:b3:e7:20:c5:30:9a:3f:68:52:f2:6f\n"
+    "# MD5 Fingerprint: 44:ED:9A:0E:A4:09:3B:00:F2:AE:4C:A3:C6:61:B0:8B\n"
+    "# SHA1 Fingerprint: "
+    "D2:73:96:2A:2A:5E:39:9F:73:3F:E1:C7:1E:64:3F:03:38:34:FC:4D\n"
+    "# SHA256 Fingerprint: "
+    "C4:5D:7B:B0:8E:6D:67:E6:2E:42:35:11:0B:56:4E:5F:78:FD:92:EF:05:8C:84:0A:"
+    "EA:4E:64:55:D7:58:5C:60\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH\n"
+    "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
+    "QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\n"
+    "MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\n"
+    "cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB\n"
+    "AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv\n"
+    "CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg\n"
+    "GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu\n"
+    "XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd\n"
+    "re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu\n"
+    "PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1\n"
+    "mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K\n"
+    "8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj\n"
+    "x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR\n"
+    "nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0\n"
+    "kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok\n"
+    "twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n"
+    "HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp\n"
+    "8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT\n"
+    "vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT\n"
+    "z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA\n"
+    "pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb\n"
+    "pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB\n"
+    "R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R\n"
+    "RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk\n"
+    "0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC\n"
+    "5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF\n"
+    "izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn\n"
+    "yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Google Trust Services LLC\n"
+    "# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R3\n"
+    "# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R3\n"
+    "# Label: \"GTS Root R3\"\n"
+    "# Serial: 6e:47:a9:c7:6c:a9:73:24:40:89:0f:03:55:dd:8d:1d\n"
+    "# MD5 Fingerprint: 1A:79:5B:6B:04:52:9C:5D:C7:74:33:1B:25:9A:F9:25\n"
+    "# SHA1 Fingerprint: "
+    "30:D4:24:6F:07:FF:DB:91:89:8A:0B:E9:49:66:11:EB:8C:5E:46:E5\n"
+    "# SHA256 Fingerprint: "
+    "15:D5:B8:77:46:19:EA:7D:54:CE:1C:A6:D0:B0:C4:03:E0:37:A9:17:F1:31:E8:A0:"
+    "4E:1E:6B:7A:71:BA:BC:E5\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw\n"
+    "CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\n"
+    "MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\n"
+    "MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\n"
+    "Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA\n"
+    "IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout\n"
+    "736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A\n"
+    "DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n"
+    "DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk\n"
+    "fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA\n"
+    "njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd\n"
+    "-----END CERTIFICATE-----\n"
+    "\n"
+    "# Operating CA: Google Trust Services LLC\n"
+    "# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4\n"
+    "# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R4\n"
+    "# Label: \"GTS Root R4\"\n"
+    "# Serial: 6e:47:a9:c8:8b:94:b6:e8:bb:3b:2a:d8:a2:b2:c1:99\n"
+    "# MD5 Fingerprint: 5D:B6:6A:C4:60:17:24:6A:1A:99:A8:4B:EE:5E:B4:26\n"
+    "# SHA1 Fingerprint: "
+    "2A:1D:60:27:D9:4A:B1:0A:1C:4D:91:5C:CD:33:A0:CB:3E:2D:54:CB\n"
+    "# SHA256 Fingerprint: "
+    "71:CC:A5:39:1F:9E:79:4B:04:80:25:30:B3:63:E1:21:DA:8A:30:43:BB:26:66:2F:"
+    "EA:4D:CA:7F:C9:51:A4:BD\n"
+    "-----BEGIN CERTIFICATE-----\n"
+    "MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw\n"
+    "CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\n"
+    "MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\n"
+    "MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\n"
+    "Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA\n"
+    "IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu\n"
+    "hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l\n"
+    "xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n"
+    "DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0\n"
+    "CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx\n"
+    "sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==\n"
+    "-----END CERTIFICATE-----\n";
diff --git a/remoting/signaling/grpc_support/using_grpc_channel_shared_ptr.inc b/remoting/signaling/grpc_support/using_grpc_channel_shared_ptr.inc
new file mode 100644
index 0000000..09deb01
--- /dev/null
+++ b/remoting/signaling/grpc_support/using_grpc_channel_shared_ptr.inc
@@ -0,0 +1,5 @@
+// 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.
+
+using GrpcChannelSharedPtr = std::shared_ptr<grpc::Channel>;
diff --git a/remoting/signaling/message_reception_channel.h b/remoting/signaling/message_reception_channel.h
index 2a746b08..910dcffc 100644
--- a/remoting/signaling/message_reception_channel.h
+++ b/remoting/signaling/message_reception_channel.h
@@ -21,12 +21,11 @@
 // FTL backend.
 class MessageReceptionChannel {
  public:
-  using StreamOpener = base::RepeatingCallback<void(
-      base::OnceCallback<void(std::unique_ptr<ScopedGrpcServerStream>)>
-          on_stream_started,
-      const base::RepeatingCallback<void(const ftl::ReceiveMessagesResponse&)>&
-          on_incoming_msg,
-      base::OnceCallback<void(const grpc::Status&)> on_channel_closed)>;
+  using StreamOpener =
+      base::RepeatingCallback<std::unique_ptr<ScopedGrpcServerStream>(
+          const base::RepeatingCallback<void(
+              const ftl::ReceiveMessagesResponse&)>& on_incoming_msg,
+          base::OnceCallback<void(const grpc::Status&)> on_channel_closed)>;
   using MessageCallback =
       base::RepeatingCallback<void(const ftl::InboxMessage&)>;
   using DoneCallback = base::OnceCallback<void(const grpc::Status& status)>;
diff --git a/remoting/signaling/registration_manager.h b/remoting/signaling/registration_manager.h
new file mode 100644
index 0000000..5994da07
--- /dev/null
+++ b/remoting/signaling/registration_manager.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 REMOTING_SIGNALING_REGISTRATION_MANAGER_H_
+#define REMOTING_SIGNALING_REGISTRATION_MANAGER_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "third_party/grpc/src/include/grpcpp/support/status.h"
+
+namespace remoting {
+
+// Interface for registering the user with signaling service.
+class RegistrationManager {
+ public:
+  using DoneCallback = base::OnceCallback<void(const grpc::Status& status)>;
+
+  virtual ~RegistrationManager() = default;
+
+  // Performs a SignInGaia call for this device. |on_done| is called once it has
+  // successfully signed in or failed to sign in.
+  virtual void SignInGaia(DoneCallback on_done) = 0;
+
+  virtual bool IsSignedIn() const = 0;
+
+  // Returns empty string if user hasn't been signed in.
+  virtual std::string GetRegistrationId() const = 0;
+  virtual std::string GetFtlAuthToken() const = 0;
+
+ protected:
+  RegistrationManager() = default;
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_SIGNALING_REGISTRATION_MANAGER_H_
diff --git a/remoting/test/ftl_signaling_playground.cc b/remoting/test/ftl_signaling_playground.cc
index 8df7321..6039956 100644
--- a/remoting/test/ftl_signaling_playground.cc
+++ b/remoting/test/ftl_signaling_playground.cc
@@ -24,7 +24,9 @@
 #include "remoting/base/fake_oauth_token_getter.h"
 #include "remoting/base/oauth_token_getter_impl.h"
 #include "remoting/signaling/ftl_device_id_provider.h"
+#include "remoting/signaling/ftl_grpc_context.h"
 #include "remoting/signaling/ftl_services.grpc.pb.h"
+#include "remoting/signaling/grpc_support/grpc_async_unary_request.h"
 #include "remoting/test/test_oauth_token_factory.h"
 #include "remoting/test/test_token_storage.h"
 
@@ -116,7 +118,7 @@
   DCHECK(!storage_);
   DCHECK(!token_getter_factory_);
   DCHECK(!token_getter_);
-  DCHECK(!ftl_context_);
+  DCHECK(!executor_);
 
   token_getter_factory_ = std::make_unique<TestOAuthTokenGetterFactory>();
 
@@ -181,17 +183,19 @@
 }
 
 void FtlSignalingPlayground::ResetServices() {
-  ftl_context_ = std::make_unique<FtlGrpcContext>(token_getter_.get());
-  peer_to_peer_stub_ = PeerToPeer::NewStub(ftl_context_->channel());
+  executor_ = std::make_unique<GrpcAuthenticatedExecutor>(token_getter_.get());
+  peer_to_peer_stub_ = PeerToPeer::NewStub(FtlGrpcContext::CreateChannel());
+
+  registration_manager_ = std::make_unique<FtlRegistrationManager>(
+      token_getter_.get(),
+      std::make_unique<FtlDeviceIdProvider>(storage_.get()));
 
   message_subscription_.reset();
-  messaging_client_ = std::make_unique<FtlMessagingClient>(ftl_context_.get());
+  messaging_client_ = std::make_unique<FtlMessagingClient>(
+      token_getter_.get(), registration_manager_.get());
   message_subscription_ = messaging_client_->RegisterMessageCallback(
       base::BindRepeating(&FtlSignalingPlayground::OnMessageReceived,
                           weak_factory_.GetWeakPtr()));
-  registration_manager_ = std::make_unique<FtlRegistrationManager>(
-      ftl_context_.get(),
-      std::make_unique<FtlDeviceIdProvider>(storage_.get()));
 }
 
 void FtlSignalingPlayground::AuthenticateAndResetServices() {
@@ -241,12 +245,15 @@
 void FtlSignalingPlayground::GetIceServer(base::OnceClosure on_done) {
   DCHECK(peer_to_peer_stub_);
   VLOG(0) << "Running GetIceServer...";
-  ftl_context_->ExecuteRpc(
+  ftl::GetICEServerRequest request;
+  *request.mutable_header() = FtlGrpcContext::CreateRequestHeader();
+  auto grpc_request = CreateGrpcAsyncUnaryRequest(
       base::BindOnce(&PeerToPeer::Stub::AsyncGetICEServer,
                      base::Unretained(peer_to_peer_stub_.get())),
-      ftl::GetICEServerRequest(),
+      FtlGrpcContext::CreateClientContext(), request,
       base::BindOnce(&FtlSignalingPlayground::OnGetIceServerResponse,
                      weak_factory_.GetWeakPtr(), std::move(on_done)));
+  executor_->ExecuteRpc(std::move(grpc_request));
 }
 
 void FtlSignalingPlayground::OnGetIceServerResponse(
@@ -288,7 +295,7 @@
                                                   const grpc::Status& status) {
   if (status.ok()) {
     std::string registration_id_base64;
-    base::Base64Encode(registration_manager_->registration_id(),
+    base::Base64Encode(registration_manager_->GetRegistrationId(),
                        &registration_id_base64);
     printf("Service signed in. registration_id(base64)=%s\n",
            registration_id_base64.c_str());
diff --git a/remoting/test/ftl_signaling_playground.h b/remoting/test/ftl_signaling_playground.h
index e17568a..886b3a9 100644
--- a/remoting/test/ftl_signaling_playground.h
+++ b/remoting/test/ftl_signaling_playground.h
@@ -12,9 +12,9 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "remoting/base/oauth_token_getter.h"
-#include "remoting/signaling/ftl_grpc_context.h"
 #include "remoting/signaling/ftl_messaging_client.h"
 #include "remoting/signaling/ftl_registration_manager.h"
+#include "remoting/signaling/grpc_support/grpc_authenticated_executor.h"
 
 namespace remoting {
 
@@ -76,15 +76,15 @@
   std::unique_ptr<test::TestTokenStorage> storage_;
   std::unique_ptr<TestOAuthTokenGetterFactory> token_getter_factory_;
   std::unique_ptr<OAuthTokenGetter> token_getter_;
-  std::unique_ptr<FtlGrpcContext> ftl_context_;
+  std::unique_ptr<GrpcAuthenticatedExecutor> executor_;
+
+  std::unique_ptr<FtlRegistrationManager> registration_manager_;
 
   // Subscription must be deleted before |messaging_client_|.
   std::unique_ptr<FtlMessagingClient> messaging_client_;
   std::unique_ptr<FtlMessagingClient::MessageCallbackSubscription>
       message_subscription_;
 
-  std::unique_ptr<FtlRegistrationManager> registration_manager_;
-
   std::unique_ptr<PeerToPeer::Stub> peer_to_peer_stub_;
 
   base::WeakPtrFactory<FtlSignalingPlayground> weak_factory_;
diff --git a/rlz/lib/machine_id.cc b/rlz/lib/machine_id.cc
index d1aab26..615a2b82b 100644
--- a/rlz/lib/machine_id.cc
+++ b/rlz/lib/machine_id.cc
@@ -6,8 +6,8 @@
 
 #include <stddef.h>
 
+#include "base/hash/sha1.h"
 #include "base/rand_util.h"
-#include "base/sha1.h"
 #include "base/strings/stringprintf.h"
 #include "rlz/lib/assert.h"
 #include "rlz/lib/crc8.h"
diff --git a/sandbox/linux/bpf_dsl/codegen_unittest.cc b/sandbox/linux/bpf_dsl/codegen_unittest.cc
index 56a0dd2..bca3d7a 100644
--- a/sandbox/linux/bpf_dsl/codegen_unittest.cc
+++ b/sandbox/linux/bpf_dsl/codegen_unittest.cc
@@ -11,8 +11,8 @@
 #include <utility>
 #include <vector>
 
+#include "base/hash/md5.h"
 #include "base/macros.h"
-#include "base/md5.h"
 #include "base/strings/string_piece.h"
 #include "sandbox/linux/system_headers/linux_filter.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/services/device/generic_sensor/platform_sensor_reader_linux.cc b/services/device/generic_sensor/platform_sensor_reader_linux.cc
index 6ee9af9..15b8662 100644
--- a/services/device/generic_sensor/platform_sensor_reader_linux.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_linux.cc
@@ -38,11 +38,12 @@
   // Helper class that performs the actual I/O. It must run on a
   // SequencedTaskRunner that is properly configured for blocking I/O
   // operations.
-  class BlockingTaskHelper final {
+  class BlockingTaskRunnerHelper final {
    public:
-    BlockingTaskHelper(base::WeakPtr<PollingSensorReader> polling_sensor_reader,
-                       const SensorInfoLinux& sensor_info);
-    ~BlockingTaskHelper();
+    BlockingTaskRunnerHelper(
+        base::WeakPtr<PollingSensorReader> polling_sensor_reader,
+        const SensorInfoLinux& sensor_info);
+    ~BlockingTaskRunnerHelper();
 
     // Starts polling for data at a given |frequency|, and stops if there is an
     // error while reading or parsing the data.
@@ -73,7 +74,7 @@
 
     SEQUENCE_CHECKER(sequence_checker_);
 
-    DISALLOW_COPY_AND_ASSIGN(BlockingTaskHelper);
+    DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunnerHelper);
   };
 
   // Receives a reading from the platform sensor and forwards it to |sensor_|.
@@ -94,7 +95,7 @@
           {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
 
-  std::unique_ptr<BlockingTaskHelper, base::OnTaskRunnerDeleter>
+  std::unique_ptr<BlockingTaskRunnerHelper, base::OnTaskRunnerDeleter>
       blocking_task_helper_;
 
   base::WeakPtrFactory<PollingSensorReader> weak_factory_;
@@ -102,7 +103,7 @@
   DISALLOW_COPY_AND_ASSIGN(PollingSensorReader);
 };
 
-PollingSensorReader::BlockingTaskHelper::BlockingTaskHelper(
+PollingSensorReader::BlockingTaskRunnerHelper::BlockingTaskRunnerHelper(
     base::WeakPtr<PollingSensorReader> polling_sensor_reader,
     const SensorInfoLinux& sensor_info)
     : polling_sensor_reader_(polling_sensor_reader),
@@ -113,25 +114,27 @@
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
-PollingSensorReader::BlockingTaskHelper::~BlockingTaskHelper() {
+PollingSensorReader::BlockingTaskRunnerHelper::~BlockingTaskRunnerHelper() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void PollingSensorReader::BlockingTaskHelper::StartPolling(double frequency) {
+void PollingSensorReader::BlockingTaskRunnerHelper::StartPolling(
+    double frequency) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!timer_.IsRunning());
   timer_.Start(FROM_HERE,
                base::TimeDelta::FromMicroseconds(
                    base::Time::kMicrosecondsPerSecond / frequency),
-               this, &PollingSensorReader::BlockingTaskHelper::PollForData);
+               this,
+               &PollingSensorReader::BlockingTaskRunnerHelper::PollForData);
 }
 
-void PollingSensorReader::BlockingTaskHelper::StopPolling() {
+void PollingSensorReader::BlockingTaskRunnerHelper::StopPolling() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   timer_.Stop();
 }
 
-void PollingSensorReader::BlockingTaskHelper::StopWithError() {
+void PollingSensorReader::BlockingTaskRunnerHelper::StopWithError() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   StopPolling();
   owner_task_runner_->PostTask(
@@ -139,7 +142,7 @@
                                 polling_sensor_reader_));
 }
 
-void PollingSensorReader::BlockingTaskHelper::PollForData() {
+void PollingSensorReader::BlockingTaskRunnerHelper::PollForData() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   SensorReading readings;
@@ -184,7 +187,7 @@
   // We need to properly initialize |blocking_task_helper_| here because we need
   // |weak_factory_| to be created first.
   blocking_task_helper_.reset(
-      new BlockingTaskHelper(weak_factory_.GetWeakPtr(), sensor_info));
+      new BlockingTaskRunnerHelper(weak_factory_.GetWeakPtr(), sensor_info));
 }
 
 PollingSensorReader::~PollingSensorReader() {
@@ -198,7 +201,7 @@
     StopFetchingData();
   is_reading_active_ = true;
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::StartPolling,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::StartPolling,
                                 base::Unretained(blocking_task_helper_.get()),
                                 configuration.frequency()));
 }
@@ -207,7 +210,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   is_reading_active_ = false;
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::StopPolling,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::StopPolling,
                                 base::Unretained(blocking_task_helper_.get())));
 }
 
diff --git a/services/device/hid/hid_connection_linux.cc b/services/device/hid/hid_connection_linux.cc
index b36ba6bb..ea479b09 100644
--- a/services/device/hid/hid_connection_linux.cc
+++ b/services/device/hid/hid_connection_linux.cc
@@ -32,11 +32,11 @@
 
 namespace device {
 
-class HidConnectionLinux::BlockingTaskHelper {
+class HidConnectionLinux::BlockingTaskRunnerHelper {
  public:
-  BlockingTaskHelper(base::ScopedFD fd,
-                     scoped_refptr<HidDeviceInfo> device_info,
-                     base::WeakPtr<HidConnectionLinux> connection)
+  BlockingTaskRunnerHelper(base::ScopedFD fd,
+                           scoped_refptr<HidDeviceInfo> device_info,
+                           base::WeakPtr<HidConnectionLinux> connection)
       : fd_(std::move(fd)),
         connection_(connection),
         origin_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
@@ -46,7 +46,9 @@
     has_report_id_ = device_info->has_report_id();
   }
 
-  ~BlockingTaskHelper() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
+  ~BlockingTaskRunnerHelper() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
 
   // Starts the FileDescriptorWatcher that reads input events from the device.
   // Must be called on a thread that has a base::MessageLoopForIO.
@@ -54,8 +56,9 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
     file_watcher_ = base::FileDescriptorWatcher::WatchReadable(
-        fd_.get(), base::Bind(&BlockingTaskHelper::OnFileCanReadWithoutBlocking,
-                              base::Unretained(this)));
+        fd_.get(), base::BindRepeating(
+                       &BlockingTaskRunnerHelper::OnFileCanReadWithoutBlocking,
+                       base::Unretained(this)));
   }
 
   void Write(scoped_refptr<base::RefCountedBytes> buffer,
@@ -175,7 +178,7 @@
   const scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
   std::unique_ptr<base::FileDescriptorWatcher::Controller> file_watcher_;
 
-  DISALLOW_COPY_AND_ASSIGN(BlockingTaskHelper);
+  DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunnerHelper);
 };
 
 HidConnectionLinux::HidConnectionLinux(
@@ -185,10 +188,10 @@
     : HidConnection(device_info),
       blocking_task_runner_(std::move(blocking_task_runner)),
       weak_factory_(this) {
-  helper_ = std::make_unique<BlockingTaskHelper>(std::move(fd), device_info,
-                                                 weak_factory_.GetWeakPtr());
+  helper_ = std::make_unique<BlockingTaskRunnerHelper>(
+      std::move(fd), device_info, weak_factory_.GetWeakPtr());
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::Start,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Start,
                                 base::Unretained(helper_.get())));
 }
 
@@ -208,7 +211,7 @@
   // Linux expects the first byte of the buffer to always be a report ID so the
   // buffer can be used directly.
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::Write,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Write,
                                 base::Unretained(helper_.get()), buffer,
                                 std::move(callback)));
 }
@@ -223,7 +226,7 @@
   buffer->data()[0] = report_id;
 
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::GetFeatureReport,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::GetFeatureReport,
                                 base::Unretained(helper_.get()), report_id,
                                 buffer, std::move(callback)));
 }
@@ -234,7 +237,7 @@
   // Linux expects the first byte of the buffer to always be a report ID so the
   // buffer can be used directly.
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::SendFeatureReport,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::SendFeatureReport,
                                 base::Unretained(helper_.get()), buffer,
                                 std::move(callback)));
 }
diff --git a/services/device/hid/hid_connection_linux.h b/services/device/hid/hid_connection_linux.h
index 274128c..b1f2e46 100644
--- a/services/device/hid/hid_connection_linux.h
+++ b/services/device/hid/hid_connection_linux.h
@@ -28,7 +28,7 @@
 
  private:
   friend class base::RefCountedThreadSafe<HidConnectionLinux>;
-  class BlockingTaskHelper;
+  class BlockingTaskRunnerHelper;
 
   ~HidConnectionLinux() override;
 
@@ -44,7 +44,7 @@
   // |helper_| lives on the sequence to which |blocking_task_runner_| posts
   // tasks so all calls must be posted there including this object's
   // destruction.
-  std::unique_ptr<BlockingTaskHelper> helper_;
+  std::unique_ptr<BlockingTaskRunnerHelper> helper_;
 
   const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
 
diff --git a/services/device/hid/hid_service_linux.cc b/services/device/hid/hid_service_linux.cc
index f900828..c1e04c0 100644
--- a/services/device/hid/hid_service_linux.cc
+++ b/services/device/hid/hid_service_linux.cc
@@ -66,15 +66,15 @@
   base::ScopedFD fd;
 };
 
-class HidServiceLinux::BlockingTaskHelper : public UdevWatcher::Observer {
+class HidServiceLinux::BlockingTaskRunnerHelper : public UdevWatcher::Observer {
  public:
-  BlockingTaskHelper(base::WeakPtr<HidServiceLinux> service)
+  BlockingTaskRunnerHelper(base::WeakPtr<HidServiceLinux> service)
       : service_(std::move(service)),
         task_runner_(base::SequencedTaskRunnerHandle::Get()) {
     DETACH_FROM_SEQUENCE(sequence_checker_);
   }
 
-  ~BlockingTaskHelper() override {
+  ~BlockingTaskRunnerHelper() override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   }
 
@@ -187,16 +187,17 @@
   base::WeakPtr<HidServiceLinux> service_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
-  DISALLOW_COPY_AND_ASSIGN(BlockingTaskHelper);
+  DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunnerHelper);
 };
 
 HidServiceLinux::HidServiceLinux()
     : blocking_task_runner_(
           base::CreateSequencedTaskRunnerWithTraits(kBlockingTaskTraits)),
       weak_factory_(this) {
-  helper_ = std::make_unique<BlockingTaskHelper>(weak_factory_.GetWeakPtr());
+  helper_ =
+      std::make_unique<BlockingTaskRunnerHelper>(weak_factory_.GetWeakPtr());
   blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&BlockingTaskHelper::Start,
+      FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Start,
                                 base::Unretained(helper_.get())));
 }
 
diff --git a/services/device/hid/hid_service_linux.h b/services/device/hid/hid_service_linux.h
index b2749db..8db9e16f 100644
--- a/services/device/hid/hid_service_linux.h
+++ b/services/device/hid/hid_service_linux.h
@@ -29,7 +29,7 @@
 
  private:
   struct ConnectParams;
-  class BlockingTaskHelper;
+  class BlockingTaskRunnerHelper;
 
 // These functions implement the process of locating, requesting access to and
 // opening a device. Because this operation crosses multiple threads these
@@ -51,7 +51,7 @@
 
   // |helper_| lives on the sequence |blocking_task_runner_| posts to and holds
   // a weak reference back to the service that owns it.
-  std::unique_ptr<BlockingTaskHelper> helper_;
+  std::unique_ptr<BlockingTaskRunnerHelper> helper_;
   base::WeakPtrFactory<HidServiceLinux> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(HidServiceLinux);
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index 6c67c4b..a2350d0 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -102,164 +102,122 @@
     signin::AccountConsistencyMethod account_consistency,
     TestSigninClient* test_signin_client)
     : IdentityTestEnvironment(
-          /*pref_service=*/nullptr,
-          /*account_tracker_service=*/nullptr,
-          /*account_fetcher_service=*/nullptr,
-          /*token_service=*/nullptr,
-          test_url_loader_factory,
-          account_consistency,
           std::make_unique<IdentityManagerDependenciesOwner>(
               pref_service,
               test_signin_client),
-          /*identity_manager=*/nullptr) {}
+          test_url_loader_factory,
+          account_consistency) {}
 
 IdentityTestEnvironment::IdentityTestEnvironment(
-    PrefService* pref_service,
-    AccountTrackerService* account_tracker_service,
-    AccountFetcherService* account_fetcher_service,
-    FakeProfileOAuth2TokenService* token_service,
-    IdentityManager* identity_manager,
-    network::TestURLLoaderFactory* test_url_loader_factory,
-    signin::AccountConsistencyMethod account_consistency)
-    : IdentityTestEnvironment(pref_service,
-                              account_tracker_service,
-                              account_fetcher_service,
-                              token_service,
-                              test_url_loader_factory,
-                              account_consistency,
-                              /*dependency_owner=*/nullptr,
-                              identity_manager) {}
-
-IdentityTestEnvironment::IdentityTestEnvironment(
-    PrefService* pref_service,
-    AccountTrackerService* account_tracker_service,
-    AccountFetcherService* account_fetcher_service,
-    FakeProfileOAuth2TokenService* token_service,
-    network::TestURLLoaderFactory* test_url_loader_factory,
-    signin::AccountConsistencyMethod account_consistency,
-    std::unique_ptr<IdentityManagerDependenciesOwner> dependencies_owner,
     IdentityManager* identity_manager)
-    : test_url_loader_factory_(test_url_loader_factory),
-      weak_ptr_factory_(this) {
+    : weak_ptr_factory_(this) {
+  DCHECK(identity_manager);
+  raw_identity_manager_ = identity_manager;
+  Initialize();
+}
+
+void IdentityTestEnvironment::Initialize() {
   DCHECK(base::ThreadTaskRunnerHandle::Get())
-      << "IdentityTestEnvironment requires a properly set up task environment. "
+      << "IdentityTestEnvironment requires a properly set up task "
+         "environment. "
          "If your test has an existing one, move it to be initialized before "
          "IdentityTestEnvironment. Otherwise, use "
          "base::test::ScopedTaskEnvironment.";
+  test_identity_manager_observer_ =
+      std::make_unique<TestIdentityManagerObserver>(this->identity_manager());
+  this->identity_manager()->AddDiagnosticsObserver(this);
+}
 
-  TestSigninClient* test_signin_client = nullptr;
-  if (dependencies_owner) {
-    DCHECK(!(account_tracker_service || account_fetcher_service ||
-             token_service || identity_manager));
+IdentityTestEnvironment::IdentityTestEnvironment(
+    std::unique_ptr<IdentityManagerDependenciesOwner> dependencies_owner,
+    network::TestURLLoaderFactory* test_url_loader_factory,
+    signin::AccountConsistencyMethod account_consistency)
+    : test_url_loader_factory_(test_url_loader_factory),
+      weak_ptr_factory_(this) {
+  dependencies_owner_ = std::move(dependencies_owner);
+  TestSigninClient* test_signin_client = dependencies_owner_->signin_client();
+  sync_preferences::TestingPrefServiceSyncable* test_pref_service =
+      dependencies_owner_->pref_service();
 
-    dependencies_owner_ = std::move(dependencies_owner);
-    test_signin_client = dependencies_owner_->signin_client();
-    sync_preferences::TestingPrefServiceSyncable* test_pref_service =
-        dependencies_owner_->pref_service();
-    pref_service = test_pref_service;
+  AccountTrackerService::RegisterPrefs(test_pref_service->registry());
+  AccountFetcherService::RegisterPrefs(test_pref_service->registry());
+  ProfileOAuth2TokenService::RegisterProfilePrefs(
+      test_pref_service->registry());
+  SigninManagerBase::RegisterProfilePrefs(test_pref_service->registry());
+  SigninManagerBase::RegisterPrefs(test_pref_service->registry());
 
-    AccountTrackerService::RegisterPrefs(test_pref_service->registry());
-    AccountFetcherService::RegisterPrefs(test_pref_service->registry());
-    ProfileOAuth2TokenService::RegisterProfilePrefs(
-        test_pref_service->registry());
-    SigninManagerBase::RegisterProfilePrefs(test_pref_service->registry());
-    SigninManagerBase::RegisterPrefs(test_pref_service->registry());
+  owned_token_service_ =
+      std::make_unique<FakeProfileOAuth2TokenService>(test_pref_service);
 
-    owned_token_service_ =
-        std::make_unique<FakeProfileOAuth2TokenService>(test_pref_service);
-    token_service = owned_token_service_.get();
+  owned_account_tracker_service_ = std::make_unique<AccountTrackerService>();
+  owned_account_tracker_service_->Initialize(test_pref_service,
+                                             base::FilePath());
 
-    owned_account_tracker_service_ = std::make_unique<AccountTrackerService>();
-    owned_account_tracker_service_->Initialize(test_pref_service,
-                                               base::FilePath());
-    account_tracker_service = owned_account_tracker_service_.get();
+  owned_account_fetcher_service_ = std::make_unique<AccountFetcherService>();
+  owned_account_fetcher_service_->Initialize(
+      test_signin_client, owned_token_service_.get(),
+      owned_account_tracker_service_.get(),
+      std::make_unique<image_fetcher::FakeImageDecoder>());
 
-    owned_account_fetcher_service_ = std::make_unique<AccountFetcherService>();
-    owned_account_fetcher_service_->Initialize(
-        test_signin_client, token_service, account_tracker_service,
-        std::make_unique<image_fetcher::FakeImageDecoder>());
-    account_fetcher_service = owned_account_fetcher_service_.get();
+#if defined(OS_CHROMEOS)
+  std::unique_ptr<SigninManagerBase> signin_manager =
+      std::make_unique<SigninManagerBase>(test_signin_client,
+                                          owned_token_service_.get(),
+                                          owned_account_tracker_service_.get());
+#else
+  std::unique_ptr<SigninManagerBase> signin_manager =
+      std::make_unique<SigninManager>(
+          test_signin_client, owned_token_service_.get(),
+          owned_account_tracker_service_.get(), nullptr, account_consistency);
+#endif
+  signin_manager->Initialize(test_pref_service);
 
+  std::unique_ptr<GaiaCookieManagerService> gaia_cookie_manager_service;
+  if (test_url_loader_factory != nullptr) {
+    gaia_cookie_manager_service = std::make_unique<GaiaCookieManagerService>(
+        owned_token_service_.get(), test_signin_client,
+        base::BindRepeating(
+            [](network::TestURLLoaderFactory* test_url_loader_factory)
+                -> scoped_refptr<network::SharedURLLoaderFactory> {
+              return test_url_loader_factory->GetSafeWeakWrapper();
+            },
+            test_url_loader_factory));
   } else {
-    owned_signin_client_ = std::make_unique<TestSigninClient>(pref_service);
-    test_signin_client = owned_signin_client_.get();
+    gaia_cookie_manager_service = std::make_unique<GaiaCookieManagerService>(
+        owned_token_service_.get(), test_signin_client);
   }
 
-  // TODO(sdefresne): services should be initialized when this version of
-  // the constructor is used. However, this break a large number of tests
-  // (all those that use an IdentityTestEnvironment and its dependencies
-  // as member fields; they should be changed to before the check can be
-  // enabled).
-  // DCHECK(account_tracker_service_->account_fetcher_service())
-  //     << "IdentityTestEnvironment requires its services to be initialized "
-  //     << "before passing them to the constructor.";
-
-  if (identity_manager) {
-    raw_identity_manager_ = identity_manager;
-  } else {
-    DCHECK(pref_service && account_tracker_service && account_fetcher_service &&
-           token_service);
-#if defined(OS_CHROMEOS)
-    std::unique_ptr<SigninManagerBase> signin_manager =
-        std::make_unique<SigninManagerBase>(test_signin_client, token_service,
-                                            account_tracker_service);
-#else
-    std::unique_ptr<SigninManagerBase> signin_manager =
-        std::make_unique<SigninManager>(test_signin_client, token_service,
-                                        account_tracker_service, nullptr,
-                                        account_consistency);
-#endif
-    signin_manager->Initialize(pref_service);
-
-    std::unique_ptr<GaiaCookieManagerService> gaia_cookie_manager_service;
-    if (test_url_loader_factory != nullptr) {
-      gaia_cookie_manager_service = std::make_unique<GaiaCookieManagerService>(
-          token_service, test_signin_client,
-          base::BindRepeating(
-              [](network::TestURLLoaderFactory* test_url_loader_factory)
-                  -> scoped_refptr<network::SharedURLLoaderFactory> {
-                return test_url_loader_factory->GetSafeWeakWrapper();
-              },
-              test_url_loader_factory));
-    } else {
-      gaia_cookie_manager_service = std::make_unique<GaiaCookieManagerService>(
-          token_service, test_signin_client);
-    }
-
-    std::unique_ptr<PrimaryAccountMutator> primary_account_mutator;
-    std::unique_ptr<AccountsMutator> accounts_mutator;
+  std::unique_ptr<PrimaryAccountMutator> primary_account_mutator;
+  std::unique_ptr<AccountsMutator> accounts_mutator;
 
 #if !defined(OS_CHROMEOS)
-    primary_account_mutator = std::make_unique<PrimaryAccountMutatorImpl>(
-        account_tracker_service,
-        static_cast<SigninManager*>(signin_manager.get()));
+  primary_account_mutator = std::make_unique<PrimaryAccountMutatorImpl>(
+      owned_account_tracker_service_.get(),
+      static_cast<SigninManager*>(signin_manager.get()));
 #endif
 
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
-    accounts_mutator = std::make_unique<AccountsMutatorImpl>(
-        token_service, account_tracker_service, signin_manager.get(),
-        pref_service);
+  accounts_mutator = std::make_unique<AccountsMutatorImpl>(
+      owned_token_service_.get(), owned_account_tracker_service_.get(),
+      signin_manager.get(), test_pref_service);
 #endif
 
-    std::unique_ptr<DiagnosticsProvider> diagnostics_provider =
-        std::make_unique<DiagnosticsProviderImpl>(
-            token_service, gaia_cookie_manager_service.get());
+  std::unique_ptr<DiagnosticsProvider> diagnostics_provider =
+      std::make_unique<DiagnosticsProviderImpl>(
+          owned_token_service_.get(), gaia_cookie_manager_service.get());
 
-    std::unique_ptr<AccountsCookieMutator> accounts_cookie_mutator =
-        std::make_unique<AccountsCookieMutatorImpl>(
-            gaia_cookie_manager_service.get());
+  std::unique_ptr<AccountsCookieMutator> accounts_cookie_mutator =
+      std::make_unique<AccountsCookieMutatorImpl>(
+          gaia_cookie_manager_service.get());
 
-    owned_identity_manager_ = std::make_unique<IdentityManager>(
-        std::move(gaia_cookie_manager_service), std::move(signin_manager),
-        token_service, account_fetcher_service, account_tracker_service,
-        std::move(primary_account_mutator), std::move(accounts_mutator),
-        std::move(accounts_cookie_mutator), std::move(diagnostics_provider));
-  }
+  owned_identity_manager_ = std::make_unique<IdentityManager>(
+      std::move(gaia_cookie_manager_service), std::move(signin_manager),
+      owned_token_service_.get(), owned_account_fetcher_service_.get(),
+      owned_account_tracker_service_.get(), std::move(primary_account_mutator),
+      std::move(accounts_mutator), std::move(accounts_cookie_mutator),
+      std::move(diagnostics_provider));
 
-  test_identity_manager_observer_ =
-      std::make_unique<TestIdentityManagerObserver>(this->identity_manager());
-
-  this->identity_manager()->AddDiagnosticsObserver(this);
+  Initialize();
 }
 
 IdentityTestEnvironment::~IdentityTestEnvironment() {
diff --git a/services/identity/public/cpp/identity_test_environment.h b/services/identity/public/cpp/identity_test_environment.h
index 9f7c612..61a7f71 100644
--- a/services/identity/public/cpp/identity_test_environment.h
+++ b/services/identity/public/cpp/identity_test_environment.h
@@ -286,51 +286,24 @@
     base::OnceClosure on_available;
   };
 
-  // Constructor that takes in an IdentityManager instance as well as instances
-  // of the dependencies of that IdentityManager. For use only in contexts where
-  // IdentityManager and its dependencies are all unavoidably created by the
-  // embedder (e.g., //chrome-level unittests that use the
-  // ProfileKeyedServiceFactory infrastructure).
-  // When using this constructor, the invoker is responsible for ensuring the
-  // following:
-  // - That all of these objects outlive this object
-  // - That the dependencies being passed in were in fact the objects used to
-  //   construct |identity_manager|
-  // - That the passed-in dependencies of |identity_manager| outlive it
+  // Constructs an IdentityTestEnvironment that builds and owns an
+  // IdentityManager. This private constructor is meant to only be called
+  // internally by IdentityTestEnvironment from other constructors.
+  IdentityTestEnvironment(
+      std::unique_ptr<IdentityManagerDependenciesOwner> dependencies_owner,
+      network::TestURLLoaderFactory* test_url_loader_factory,
+      signin::AccountConsistencyMethod account_consistency);
+
+  // Constructs an IdentityTestEnvironment that uses the supplied
+  // |identity_manager|.
+  // For use only in contexts where IdentityManager and its dependencies are all
+  // unavoidably created by the embedder (e.g., //chrome-level unittests that
+  // use the ProfileKeyedServiceFactory infrastructure).
   // NOTE: This constructor is for usage only in the special case of embedder
   // unittests that must use the IdentityManager instance associated with the
   // Profile/ChromeBrowserState. If you think you have another use case for it,
   // contact blundell@chromium.org.
-  IdentityTestEnvironment(
-      PrefService* pref_service,
-      AccountTrackerService* account_tracker_service,
-      AccountFetcherService* account_fetcher_service,
-      FakeProfileOAuth2TokenService* token_service,
-      IdentityManager* identity_manager,
-      network::TestURLLoaderFactory* test_url_loader_factory = nullptr,
-      signin::AccountConsistencyMethod account_consistency =
-          signin::AccountConsistencyMethod::kDisabled);
-
-  // Constructs this object from the supplied
-  // dependencies of IdentityManager and potentially IdentityManager itself.
-  // The supplied dependencies must be either:
-  // (1) non-null instances of the backing classes,
-  // (2) a non-null instance of |dependencies_owner|.
-  // In the case of (1), |identity_manager| can be non-null, in which case it
-  // must point to an object created via these dependencies. In the case of 2,
-  // |identity_manager| must be null. If |identity_manager| is non-null, it will
-  // be the IdentityManager instance associated with this object. Otherwise,
-  // this object will create and own an IdentityManager instance from the
-  // supplied dependencies.
-  IdentityTestEnvironment(
-      PrefService* pref_service,
-      AccountTrackerService* account_tracker_service,
-      AccountFetcherService* account_fetcher_service,
-      FakeProfileOAuth2TokenService* token_service,
-      network::TestURLLoaderFactory* test_url_loader_factory,
-      signin::AccountConsistencyMethod account_consistency,
-      std::unique_ptr<IdentityManagerDependenciesOwner> dependencies_owner,
-      IdentityManager* identity_manager);
+  IdentityTestEnvironment(IdentityManager* identity_manager);
 
   // IdentityManager::DiagnosticsObserver:
   void OnAccessTokenRequested(const std::string& account_id,
@@ -384,6 +357,9 @@
   base::OnceClosure on_access_token_requested_callback_;
   std::vector<AccessTokenRequestState> requesters_;
 
+  // Shared constructor initialization logic.
+  void Initialize();
+
   base::WeakPtrFactory<IdentityTestEnvironment> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(IdentityTestEnvironment);
diff --git a/services/image_annotation/annotator.cc b/services/image_annotation/annotator.cc
index 00db319..000c4e3 100644
--- a/services/image_annotation/annotator.cc
+++ b/services/image_annotation/annotator.cc
@@ -296,6 +296,11 @@
 
 constexpr char Annotator::kGoogApiKeyHeader[];
 
+static_assert(Annotator::kDescMinDimension > 0,
+              "Description engine must accept images of some sizes.");
+static_assert(Annotator::kDescMaxAspectRatio > 0.0,
+              "Description engine must accept images of some aspect ratios.");
+
 Annotator::Annotator(
     GURL server_url,
     std::string api_key,
@@ -373,33 +378,57 @@
 }
 
 // static
+bool Annotator::IsWithinDescPolicy(const int32_t width, const int32_t height) {
+  if (width < kDescMinDimension || height < kDescMinDimension)
+    return false;
+
+  // Can't be 0 or inf because |kDescMinDimension| is guaranteed positive (via a
+  // static_assert).
+  const double aspect_ratio = static_cast<double>(width) / height;
+  if (aspect_ratio < 1.0 / kDescMaxAspectRatio ||
+      aspect_ratio > kDescMaxAspectRatio)
+    return false;
+
+  return true;
+}
+
+// static
 std::string Annotator::FormatJsonRequest(
     const HttpRequestQueue::iterator begin_it,
     const HttpRequestQueue::iterator end_it) {
   base::Value image_request_list(base::Value::Type::LIST);
   for (HttpRequestQueue::iterator it = begin_it; it != end_it; ++it) {
+    const std::string& source_id = std::get<0>(*it);
+    const std::vector<uint8_t>& bytes = std::get<1>(*it);
+    const bool desc = std::get<2>(*it);
+
     // Re-encode image bytes into base64, which can be represented in JSON.
     std::string base64_data;
-    Base64Encode(
-        base::StringPiece(reinterpret_cast<const char*>(it->second.data()),
-                          it->second.size()),
-        &base64_data);
+    Base64Encode(base::StringPiece(reinterpret_cast<const char*>(bytes.data()),
+                                   bytes.size()),
+                 &base64_data);
 
     // TODO(crbug.com/916420): accept and propagate page language info to
     //                         improve OCR accuracy.
     base::Value ocr_engine_params(base::Value::Type::DICTIONARY);
     ocr_engine_params.SetKey("ocrParameters",
                              base::Value(base::Value::Type::DICTIONARY));
-    base::Value desc_engine_params(base::Value::Type::DICTIONARY);
-    desc_engine_params.SetKey("descriptionParameters",
-                              base::Value(base::Value::Type::DICTIONARY));
 
     base::Value engine_params_list(base::Value::Type::LIST);
     engine_params_list.GetList().push_back(std::move(ocr_engine_params));
-    engine_params_list.GetList().push_back(std::move(desc_engine_params));
+
+    // Also add a description annotations request if the image is within model
+    // policy.
+    if (desc) {
+      base::Value desc_engine_params(base::Value::Type::DICTIONARY);
+      desc_engine_params.SetKey("descriptionParameters",
+                                base::Value(base::Value::Type::DICTIONARY));
+      engine_params_list.GetList().push_back(std::move(desc_engine_params));
+    }
+    ReportImageRequestIncludesDesc(desc);
 
     base::Value image_request(base::Value::Type::DICTIONARY);
-    image_request.SetKey("imageId", base::Value(it->first));
+    image_request.SetKey("imageId", base::Value(source_id));
     image_request.SetKey("imageBytes", base::Value(std::move(base64_data)));
     image_request.SetKey("engineParameters", std::move(engine_params_list));
 
@@ -484,7 +513,9 @@
 void Annotator::OnJpgImageDataReceived(
     const std::string& source_id,
     const RequestInfoList::iterator request_info_it,
-    const std::vector<uint8_t>& image_bytes) {
+    const std::vector<uint8_t>& image_bytes,
+    const int32_t width,
+    const int32_t height) {
   ReportPixelFetchSuccess(!image_bytes.empty());
 
   // Failed to retrieve bytes from local processor; remove dead processor and
@@ -498,7 +529,8 @@
   local_processors_.erase(source_id);
 
   // Schedule an HTTP request for this image.
-  http_request_queue_.push_front({source_id, image_bytes});
+  http_request_queue_.push_front(
+      {source_id, image_bytes, IsWithinDescPolicy(width, height)});
   pending_source_ids_.insert(source_id);
 
   // Start sending batches to the server.
@@ -521,7 +553,7 @@
   // The set of source IDs relevant for this request.
   std::set<std::string> source_ids;
   for (HttpRequestQueue::iterator it = begin_it; it != end_it; it++) {
-    source_ids.insert(it->first);
+    source_ids.insert(std::get<0>(*it));
   }
 
   // Kick off server communication.
diff --git a/services/image_annotation/annotator.h b/services/image_annotation/annotator.h
index aec2be8..7adda22 100644
--- a/services/image_annotation/annotator.h
+++ b/services/image_annotation/annotator.h
@@ -46,6 +46,12 @@
   // The HTTP request header in which the API key should be transmitted.
   static constexpr char kGoogApiKeyHeader[] = "X-Goog-Api-Key";
 
+  // The minimum side length needed to request description annotations.
+  static constexpr int32_t kDescMinDimension = 150;
+
+  // The maximum aspect ratio permitted to request description annotations.
+  static constexpr double kDescMaxAspectRatio = 2.5;
+
   // Constructs an annotator.
   //  |server_url|        : the URL of the server with which the annotator
   //                        communicates. The annotator gracefully handles (i.e.
@@ -90,9 +96,16 @@
   using UrlLoaderList = std::list<std::unique_ptr<network::SimpleURLLoader>>;
 
   // A queue of the data needed to make HTTP requests to the image annotation
-  // server. Each entry is a (source ID, image bytes) pair.
+  // server. Each entry is a (source ID, image bytes, desc) triple, where desc
+  // is a bool that specifies whether or not description annotations should be
+  // requested.
   using HttpRequestQueue =
-      std::deque<std::pair<std::string, std::vector<uint8_t>>>;
+      std::deque<std::tuple<std::string, std::vector<uint8_t>, bool>>;
+
+  // Returns true if the given dimensions fit the policy of the description
+  // backend (i.e. the image has size / shape on which it is acceptable to run
+  // the description model).
+  static bool IsWithinDescPolicy(int32_t width, int32_t height);
 
   // Constructs and returns a JSON object containing an request for the
   // given images.
@@ -121,7 +134,9 @@
   // source ID.
   void OnJpgImageDataReceived(const std::string& source_id,
                               RequestInfoList::iterator request_info_it,
-                              const std::vector<uint8_t>& image_bytes);
+                              const std::vector<uint8_t>& image_bytes,
+                              int32_t width,
+                              int32_t height);
 
   // Called periodically to send the next batch of requests to the image
   // annotation server.
diff --git a/services/image_annotation/annotator_unittest.cc b/services/image_annotation/annotator_unittest.cc
index a466615a..ca96a269 100644
--- a/services/image_annotation/annotator_unittest.cc
+++ b/services/image_annotation/annotator_unittest.cc
@@ -226,6 +226,9 @@
 
 constexpr base::TimeDelta kThrottle = base::TimeDelta::FromSeconds(1);
 
+// The minimum dimension required for description annotation.
+constexpr int32_t kDescDim = Annotator::kDescMinDimension;
+
 // An image processor that holds and exposes the callbacks it is passed.
 class TestImageProcessor : public mojom::ImageProcessor {
  public:
@@ -404,7 +407,7 @@
     ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
     // Send back image data.
-    std::move(processor.callbacks()[0]).Run({1, 2, 3});
+    std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
     processor.callbacks().pop_back();
     test_task_env.RunUntilIdle();
 
@@ -507,7 +510,7 @@
   ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3});
+  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor.callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -566,6 +569,8 @@
 
   // Metrics about the description results should have been logged.
   histogram_tester.ExpectUniqueSample(
+      metrics_internal::kImageRequestIncludesDesc, true, 1);
+  histogram_tester.ExpectUniqueSample(
       base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
       0 /* OK RPC status */, 1);
   histogram_tester.ExpectUniqueSample(
@@ -612,7 +617,7 @@
   ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3});
+  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor.callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -727,7 +732,7 @@
   ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3});
+  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor.callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -782,7 +787,7 @@
   ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3});
+  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor.callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -865,7 +870,7 @@
   ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3});
+  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor.callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -959,7 +964,7 @@
   ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3});
+  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor.callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1049,7 +1054,7 @@
   ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3});
+  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor.callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1107,7 +1112,7 @@
   ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor.callbacks()[0]).Run({1, 2, 3});
+  std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor.callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1187,7 +1192,7 @@
   ASSERT_THAT(processor[2].callbacks(), IsEmpty());
 
   // Make processor 1 fail by returning empty bytes.
-  std::move(processor[0].callbacks()[0]).Run({});
+  std::move(processor[0].callbacks()[0]).Run({}, 0, 0);
   processor[0].callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1197,7 +1202,7 @@
   ASSERT_THAT(processor[2].callbacks(), IsEmpty());
 
   // Send back image data.
-  std::move(processor[1].callbacks()[0]).Run({1, 2, 3});
+  std::move(processor[1].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor[1].callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1275,7 +1280,7 @@
   ASSERT_THAT(processor[2].callbacks(), IsEmpty());
 
   // Send back image data.
-  std::move(processor[1].callbacks()[0]).Run({1, 2, 3});
+  std::move(processor[1].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor[1].callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1347,11 +1352,11 @@
   ASSERT_THAT(processor[2].callbacks(), SizeIs(1));
 
   // Send back image data.
-  std::move(processor[0].callbacks()[0]).Run({1, 2, 3});
+  std::move(processor[0].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor[0].callbacks().pop_back();
-  std::move(processor[1].callbacks()[0]).Run({4, 5, 6});
+  std::move(processor[1].callbacks()[0]).Run({4, 5, 6}, kDescDim, kDescDim);
   processor[1].callbacks().pop_back();
-  std::move(processor[2].callbacks()[0]).Run({7, 8, 9});
+  std::move(processor[2].callbacks()[0]).Run({7, 8, 9}, kDescDim, kDescDim);
   processor[2].callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1426,7 +1431,7 @@
   ASSERT_THAT(processor[1].callbacks(), IsEmpty());
 
   // Send back image 1 data.
-  std::move(processor[0].callbacks()[0]).Run({1, 2, 3});
+  std::move(processor[0].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor[0].callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1446,7 +1451,7 @@
   ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
 
   // Send back image 2 data.
-  std::move(processor[1].callbacks()[0]).Run({4, 5, 6});
+  std::move(processor[1].callbacks()[0]).Run({4, 5, 6}, kDescDim, kDescDim);
   processor[1].callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1585,7 +1590,7 @@
   ASSERT_THAT(processor[3].callbacks(), IsEmpty());
 
   // Get processor 1 to reply with bytes for the image.
-  std::move(processor[0].callbacks()[0]).Run({1, 2, 3});
+  std::move(processor[0].callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
   processor[0].callbacks().pop_back();
   test_task_env.RunUntilIdle();
 
@@ -1648,6 +1653,209 @@
                                       true, 1);
 }
 
+// Test that the description engine is not requested for images that violate
+// model policy (i.e. are too small or have too-high an aspect ratio).
+TEST(AnnotatorTest, DescPolicy) {
+  base::test::ScopedTaskEnvironment test_task_env(
+      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
+  TestServerURLLoaderFactory test_url_factory(
+      "https://ia-pa.googleapis.com/v1/");
+  data_decoder::TestDataDecoderService test_dd_service;
+  base::HistogramTester histogram_tester;
+
+  Annotator annotator(
+      GURL(kTestServerUrl), std::string() /* api_key */, kThrottle,
+      3 /* batch_size */, 1.0 /* min_ocr_confidence */,
+      test_url_factory.AsSharedURLLoaderFactory(), test_dd_service.connector());
+
+  TestImageProcessor processor[3];
+  base::Optional<mojom::AnnotateImageError> error[3];
+  std::vector<mojom::Annotation> annotations[3];
+
+  // Request annotation for images 1, 2 and 3.
+  annotator.AnnotateImage(
+      kImage1Url, processor[0].GetPtr(),
+      base::BindOnce(&ReportResult, &error[0], &annotations[0]));
+  annotator.AnnotateImage(
+      kImage2Url, processor[1].GetPtr(),
+      base::BindOnce(&ReportResult, &error[1], &annotations[1]));
+  annotator.AnnotateImage(
+      kImage3Url, processor[2].GetPtr(),
+      base::BindOnce(&ReportResult, &error[2], &annotations[2]));
+  test_task_env.RunUntilIdle();
+
+  // Annotator should have asked processor 1 for image 1's pixels, processor
+  // 2 for image 2's pixels and processor 3 for image 3's pixels.
+  ASSERT_THAT(processor[0].callbacks(), SizeIs(1));
+  ASSERT_THAT(processor[1].callbacks(), SizeIs(1));
+  ASSERT_THAT(processor[2].callbacks(), SizeIs(1));
+
+  // Send back image data.
+  //
+  // Image 1 is (just) within policy. Image 2 violates policy because it is too
+  // small. Image 3 is large enough, but violates policy because of its aspect
+  // ratio.
+  std::move(processor[0].callbacks()[0])
+      .Run({1, 2, 3}, Annotator::kDescMinDimension,
+           Annotator::kDescMinDimension);
+  processor[0].callbacks().pop_back();
+  std::move(processor[1].callbacks()[0])
+      .Run({4, 5, 6}, Annotator::kDescMinDimension,
+           Annotator::kDescMinDimension - 1);
+  processor[1].callbacks().pop_back();
+  std::move(processor[2].callbacks()[0])
+      .Run({7, 8, 9},
+           static_cast<int32_t>(Annotator::kDescMinDimension *
+                                Annotator::kDescMaxAspectRatio) +
+               1,
+           Annotator::kDescMinDimension);
+  processor[2].callbacks().pop_back();
+  test_task_env.RunUntilIdle();
+
+  // No request should be sent yet (because service is waiting to batch up
+  // multiple requests).
+  EXPECT_THAT(test_url_factory.requests(), IsEmpty());
+  test_task_env.FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+  // A single HTTP request for all images should have been sent.
+  test_url_factory.ExpectRequestAndSimulateResponse(
+      "annotation", {} /* expected_headers */,
+      // Only image 1 includes a description request (as the other two violate
+      // one of the policies).
+      ReformatJson(R"(
+        {
+          "imageRequests": [
+            {
+              "imageId": "https://www.example.com/image3.jpg",
+              "imageBytes": "BwgJ",
+              "engineParameters": [
+                {"ocrParameters": {}}
+              ]
+            },
+            {
+              "imageId": "https://www.example.com/image2.jpg",
+              "imageBytes": "BAUG",
+              "engineParameters": [
+                {"ocrParameters": {}}
+              ]
+            },
+            {
+              "imageId": "https://www.example.com/image1.jpg",
+              "imageBytes": "AQID",
+              "engineParameters": [
+                {"ocrParameters": {}},
+                {"descriptionParameters": {}}
+              ]
+            }
+          ]
+        }
+      )"),
+      R"(
+        {
+          "results": [
+            {
+              "imageId": "https://www.example.com/image2.jpg",
+              "engineResults": [
+                {
+                  "status": {},
+                  "ocrEngine": {
+                    "ocrRegions": [{
+                      "words": [{
+                        "detectedText": "2",
+                        "confidenceScore": 1.0
+                      }]
+                    }]
+                  }
+                }
+              ]
+            },
+            {
+              "imageId": "https://www.example.com/image1.jpg",
+              "engineResults": [
+                {
+                  "status": {},
+                  "ocrEngine": {
+                    "ocrRegions": [{
+                      "words": [{
+                        "detectedText": "1",
+                        "confidenceScore": 1.0
+                      }]
+                    }]
+                  }
+                },
+                {
+                  "status": {},
+                  "descriptionEngine": {
+                    "descriptionList": {
+                      "descriptions": [{
+                        "type": "CAPTION",
+                        "text": "This is an example image.",
+                        "score": 1.0
+                      }]
+                    }
+                  }
+                }
+              ]
+            },
+            {
+              "imageId": "https://www.example.com/image3.jpg",
+              "engineResults": [
+                {
+                  "status": {},
+                  "ocrEngine": {
+                    "ocrRegions": [{
+                      "words": [{
+                        "detectedText": "3",
+                        "confidenceScore": 1.0
+                      }]
+                    }]
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      )",
+      net::HTTP_OK);
+  test_task_env.RunUntilIdle();
+
+  // Annotator should have called each callback with its corresponding results.
+  ASSERT_THAT(error, ElementsAre(base::nullopt, base::nullopt, base::nullopt));
+  EXPECT_THAT(
+      annotations[0],
+      UnorderedElementsAre(AnnotatorEq(mojom::AnnotationType::kOcr, 1.0, "1"),
+                           AnnotatorEq(mojom::AnnotationType::kCaption, 1.0,
+                                       "This is an example image.")));
+  EXPECT_THAT(annotations[1], UnorderedElementsAre(AnnotatorEq(
+                                  mojom::AnnotationType::kOcr, 1.0, "2")));
+  EXPECT_THAT(annotations[2], UnorderedElementsAre(AnnotatorEq(
+                                  mojom::AnnotationType::kOcr, 1.0, "3")));
+
+  // Metrics should have been logged for the 3 OCR results and 1 description
+  // result.
+  EXPECT_THAT(histogram_tester.GetAllSamples(
+                  metrics_internal::kImageRequestIncludesDesc),
+              UnorderedElementsAre(Bucket(false, 2), Bucket(true, 1)));
+  histogram_tester.ExpectUniqueSample(
+      base::StringPrintf(metrics_internal::kAnnotationStatus, "Ocr"),
+      0 /* OK RPC status */, 3);
+  histogram_tester.ExpectUniqueSample(
+      base::StringPrintf(metrics_internal::kAnnotationStatus, "Desc"),
+      0 /* OK RPC status */, 1);
+  histogram_tester.ExpectUniqueSample(
+      base::StringPrintf(metrics_internal::kAnnotationConfidence, "Ocr"), 100,
+      3);
+  histogram_tester.ExpectUniqueSample(
+      base::StringPrintf(metrics_internal::kAnnotationConfidence,
+                         "DescCaption"),
+      100, 1);
+  histogram_tester.ExpectUniqueSample(
+      base::StringPrintf(metrics_internal::kAnnotationEmpty, "Ocr"), false, 3);
+  histogram_tester.ExpectUniqueSample(
+      base::StringPrintf(metrics_internal::kAnnotationEmpty, "DescCaption"),
+      false, 1);
+}
+
 // Test that the specified API key is sent, but only to Google-associated server
 // domains.
 TEST(AnnotatorTest, ApiKey) {
@@ -1674,7 +1882,7 @@
     ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
     // Send back image data.
-    std::move(processor.callbacks()[0]).Run({1, 2, 3});
+    std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
     processor.callbacks().pop_back();
     test_task_env.FastForwardBy(base::TimeDelta::FromSeconds(1));
     test_task_env.RunUntilIdle();
@@ -1707,7 +1915,7 @@
     ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
     // Send back image data.
-    std::move(processor.callbacks()[0]).Run({1, 2, 3});
+    std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
     processor.callbacks().pop_back();
     test_task_env.FastForwardBy(base::TimeDelta::FromSeconds(1));
     test_task_env.RunUntilIdle();
@@ -1737,7 +1945,7 @@
     ASSERT_THAT(processor.callbacks(), SizeIs(1));
 
     // Send back image data.
-    std::move(processor.callbacks()[0]).Run({1, 2, 3});
+    std::move(processor.callbacks()[0]).Run({1, 2, 3}, kDescDim, kDescDim);
     processor.callbacks().pop_back();
     test_task_env.FastForwardBy(base::TimeDelta::FromSeconds(1));
     test_task_env.RunUntilIdle();
diff --git a/services/image_annotation/image_annotation_metrics.cc b/services/image_annotation/image_annotation_metrics.cc
index 03be0b94c..205480a 100644
--- a/services/image_annotation/image_annotation_metrics.cc
+++ b/services/image_annotation/image_annotation_metrics.cc
@@ -81,6 +81,10 @@
                              base::TimeDelta::FromSeconds(30), 50);
 }
 
+void ReportImageRequestIncludesDesc(const bool includes_desc) {
+  UMA_HISTOGRAM_BOOLEAN(kImageRequestIncludesDesc, includes_desc);
+}
+
 void ReportServerRequestSizeKB(const size_t size_kb) {
   // Use a custom memory histogram with ~10 buckets per order of magnitude
   // between 1KB and 30MB.
diff --git a/services/image_annotation/image_annotation_metrics.h b/services/image_annotation/image_annotation_metrics.h
index 6893c7a..e12c113 100644
--- a/services/image_annotation/image_annotation_metrics.h
+++ b/services/image_annotation/image_annotation_metrics.h
@@ -37,6 +37,8 @@
     "ImageAnnotationService.AccessibilityV1.ServerHttpResponseCode";
 constexpr char kServerLatency[] =
     "ImageAnnotationService.AccessibilityV1.ServerLatencyMs";
+constexpr char kImageRequestIncludesDesc[] =
+    "ImageAnnotationService.AccessibilityV1.ImageRequestIncludesDesc";
 constexpr char kServerRequestSize[] =
     "ImageAnnotationService.AccessibilityV1.ServerRequestSizeKB";
 constexpr char kServerResponseSize[] =
@@ -93,6 +95,11 @@
 // server.
 void ReportServerLatency(base::TimeDelta latency);
 
+// Report whether or not a request for image annotation includes parameters for
+// the description engine; requests for images that violate the description
+// engine policy (e.g. are too small) will not.
+void ReportImageRequestIncludesDesc(bool includes_desc);
+
 // Report the size of the request sent to the image annotation server.
 void ReportServerRequestSizeKB(size_t size_kb);
 
diff --git a/services/image_annotation/public/cpp/image_processor.cc b/services/image_annotation/public/cpp/image_processor.cc
index 4b88098b..c22bcbf 100644
--- a/services/image_annotation/public/cpp/image_processor.cc
+++ b/services/image_annotation/public/cpp/image_processor.cc
@@ -33,15 +33,22 @@
   return dest;
 }
 
-// Returns the bytes for a scaled and re-encoded version of the given bitmap.
-std::vector<uint8_t> ScaleAndEncodeImage(const SkBitmap& image,
-                                         const int max_pixels,
-                                         const int jpg_quality) {
+// Runs the given callback with the image data for a scaled and re-encoded
+// version of the given bitmap.
+void ScaleAndEncodeImage(scoped_refptr<base::SequencedTaskRunner> task_runner,
+                         ImageProcessor::GetJpgImageDataCallback callback,
+                         const SkBitmap& image,
+                         const int max_pixels,
+                         const int jpg_quality) {
   const int num_pixels = image.width() * image.height();
   ReportSourcePixelCount(num_pixels);
 
-  if (num_pixels == 0)
-    return {};
+  if (num_pixels == 0) {
+    task_runner->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback), std::vector<uint8_t>(), 0, 0));
+    return;
+  }
 
   const SkBitmap scaled_image =
       num_pixels <= max_pixels
@@ -49,11 +56,18 @@
           : ScaleImage(image, std::sqrt(1.0 * max_pixels / num_pixels));
 
   std::vector<uint8_t> encoded;
-  if (!gfx::JPEGCodec::Encode(scaled_image, jpg_quality, &encoded))
-    encoded.clear();
-  ReportEncodedJpegSize(encoded.size());
+  if (!gfx::JPEGCodec::Encode(scaled_image, jpg_quality, &encoded)) {
+    ReportEncodedJpegSize(0u);
+    task_runner->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback), std::vector<uint8_t>(), 0, 0));
+    return;
+  }
 
-  return encoded;
+  ReportEncodedJpegSize(encoded.size());
+  task_runner->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(encoded),
+                                scaled_image.width(), scaled_image.height()));
 }
 
 }  // namespace
@@ -77,11 +91,13 @@
 }
 
 void ImageProcessor::GetJpgImageData(GetJpgImageDataCallback callback) {
-  PostTaskAndReplyWithResult(
-      background_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&ScaleAndEncodeImage, get_pixels_.Run(), kMaxPixels,
-                     kJpgQuality),
-      std::move(callback));
+  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+
+  background_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&ScaleAndEncodeImage,
+                                base::SequencedTaskRunnerHandle::Get(),
+                                std::move(callback), get_pixels_.Run(),
+                                kMaxPixels, kJpgQuality));
 }
 
 }  // namespace image_annotation
diff --git a/services/image_annotation/public/cpp/image_processor_unittest.cc b/services/image_annotation/public/cpp/image_processor_unittest.cc
index d6b6af2..38154df 100644
--- a/services/image_annotation/public/cpp/image_processor_unittest.cc
+++ b/services/image_annotation/public/cpp/image_processor_unittest.cc
@@ -55,8 +55,7 @@
 // in the original and compressed images.
 double CalcImageError(const SkBitmap& orig, const SkBitmap& comp) {
   // Only valid to call on images of matching size.
-  if (orig.width() != comp.width() || orig.height() != comp.height())
-    return std::numeric_limits<double>::infinity();
+  CHECK(orig.width() == comp.width() && orig.height() == comp.height());
 
   double sum = 0;
   for (int row = 0; row < orig.width(); ++row) {
@@ -77,12 +76,16 @@
 // mean sum of squared distance between their pixels.
 void OutputImageError(double* const error,
                       const SkBitmap& expected,
-                      const std::vector<uint8_t>& result) {
+                      const std::vector<uint8_t>& result,
+                      const int32_t width,
+                      const int32_t height) {
   const std::unique_ptr<SkBitmap> comp =
       gfx::JPEGCodec::Decode(result.data(), result.size());
   CHECK(comp);
 
-  *error = CalcImageError(expected, *comp);
+  *error = width == expected.width() && height == expected.height()
+               ? CalcImageError(expected, *comp)
+               : std::numeric_limits<double>::infinity();
 }
 
 }  // namespace
@@ -97,8 +100,9 @@
   // pixels.
   ImageProcessor(base::BindRepeating([]() { return SkBitmap(); }))
       .GetJpgImageData(base::BindOnce(
-          [](bool* const empty_bytes, const std::vector<uint8_t>& bytes) {
-            *empty_bytes = bytes.empty();
+          [](bool* const empty_bytes, const std::vector<uint8_t>& bytes,
+             const int32_t w, const int32_t h) {
+            *empty_bytes = bytes.empty() && w == 0 && h == 0;
           },
           &empty_bytes));
   test_task_env.RunUntilIdle();
diff --git a/services/image_annotation/public/mojom/image_annotation.mojom b/services/image_annotation/public/mojom/image_annotation.mojom
index 5f676384..9970aab 100644
--- a/services/image_annotation/public/mojom/image_annotation.mojom
+++ b/services/image_annotation/public/mojom/image_annotation.mojom
@@ -5,11 +5,12 @@
 module image_annotation.mojom;
 
 interface ImageProcessor {
-  // Returns the (potentially resized and compressed) pixels for the image.
+  // Returns the (potentially resized and compressed) pixels for the image,
+  // along with its new width and height.
   //
   // TODO(crbug.com/916420): expand this signature to include arguments when we
   //                         require more sophisticated render-side processing.
-  GetJpgImageData() => (array<uint8> bytes);
+  GetJpgImageData() => (array<uint8> bytes, int32 width, int32 height);
 };
 
 // The ways in which an annotation request can fail.
diff --git a/services/media_session/public/cpp/media_image_manager.cc b/services/media_session/public/cpp/media_image_manager.cc
index b4b825c..54abae8 100644
--- a/services/media_session/public/cpp/media_image_manager.cc
+++ b/services/media_session/public/cpp/media_image_manager.cc
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace media_session {
diff --git a/services/media_session/public/cpp/media_image_manager_unittest.cc b/services/media_session/public/cpp/media_image_manager_unittest.cc
index b0f9014..3ba2b69 100644
--- a/services/media_session/public/cpp/media_image_manager_unittest.cc
+++ b/services/media_session/public/cpp/media_image_manager_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "services/media_session/public/cpp/media_image_manager.h"
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/services/metrics/public/cpp/ukm_source.cc b/services/metrics/public/cpp/ukm_source.cc
index 64d47c8..e9f0aa4 100644
--- a/services/metrics/public/cpp/ukm_source.cc
+++ b/services/metrics/public/cpp/ukm_source.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/atomicops.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "third_party/metrics_proto/ukm/source.pb.h"
 
diff --git a/services/network/cross_origin_read_blocking.cc b/services/network/cross_origin_read_blocking.cc
index 0b7e91a..43a06b1 100644
--- a/services/network/cross_origin_read_blocking.cc
+++ b/services/network/cross_origin_read_blocking.cc
@@ -577,7 +577,6 @@
   content_length_ = response.head.content_length;
   http_response_code_ =
       response.head.headers ? response.head.headers->response_code() : 0;
-  http_method_ = request.method();
   request_initiator_site_lock_ = request_initiator_site_lock;
 
   should_block_based_on_headers_ =
@@ -898,17 +897,6 @@
   if (400 <= http_response_code() && http_response_code() <= 599)
     return false;
 
-  // Requests using HTTP methods other than GET (e.g. OPTIONS used for CORS
-  // preflight or POST used for form submissions) do not need to report warning
-  // messages about CORB, because:
-  // - For XHR/fetch the *CORS* message should be sufficient
-  // - If no-cors mode was forced for XHR/fetch, then the response is opaque
-  //   and therefore CORB warning message is not needed
-  // - Other subresource requests (e.g. for img or script) tag should
-  //   only use the GET method.
-  if (!base::EqualsCaseInsensitiveASCII(http_method_, "GET"))
-    return false;
-
   return true;
 }
 
diff --git a/services/network/cross_origin_read_blocking.h b/services/network/cross_origin_read_blocking.h
index 307828a..6bef66e 100644
--- a/services/network/cross_origin_read_blocking.h
+++ b/services/network/cross_origin_read_blocking.h
@@ -160,9 +160,6 @@
     // resource request.
     int http_response_code_ = 0;
 
-    // The HTTP method of the request (e.g. "GET", "OPTIONS", "POST", etc.).
-    std::string http_method_;
-
     // Whether |request_initiator| was compatible with
     // |request_initiator_site_lock|.  For safety initialized to kIncorrectLock,
     // but in practice it will always be explicitly set by the constructor.
diff --git a/services/network/public/cpp/server/web_socket.cc b/services/network/public/cpp/server/web_socket.cc
index b43622bf..e9a7f71 100644
--- a/services/network/public/cpp/server/web_socket.cc
+++ b/services/network/public/cpp/server/web_socket.cc
@@ -7,8 +7,8 @@
 #include <vector>
 
 #include "base/base64.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_byteorder.h"
diff --git a/services/network/test/test_network_service_client.cc b/services/network/test/test_network_service_client.cc
index b1678e7c..e406716 100644
--- a/services/network/test/test_network_service_client.cc
+++ b/services/network/test/test_network_service_client.cc
@@ -10,23 +10,14 @@
 
 namespace network {
 
-TestNetworkServiceClient::TestNetworkServiceClient()
-    : enable_uploads_(true), binding_(nullptr) {}
+TestNetworkServiceClient::TestNetworkServiceClient() : binding_(nullptr) {}
 
 TestNetworkServiceClient::TestNetworkServiceClient(
     mojom::NetworkServiceClientRequest request)
-    : enable_uploads_(true), binding_(this, std::move(request)) {}
+    : binding_(this, std::move(request)) {}
 
 TestNetworkServiceClient::~TestNetworkServiceClient() {}
 
-void TestNetworkServiceClient::DisableUploads() {
-  enable_uploads_ = false;
-}
-
-void TestNetworkServiceClient::EnableUploads() {
-  enable_uploads_ = true;
-}
-
 void TestNetworkServiceClient::OnAuthRequired(
     uint32_t process_id,
     uint32_t routing_id,
@@ -94,7 +85,7 @@
     bool async,
     const std::vector<base::FilePath>& file_paths,
     OnFileUploadRequestedCallback callback) {
-  if (!enable_uploads_) {
+  if (upload_files_invalid_) {
     std::move(callback).Run(net::ERR_ACCESS_DENIED, std::vector<base::File>());
     return;
   }
@@ -111,6 +102,12 @@
       return;
     }
   }
+
+  if (ignore_last_upload_file_) {
+    // Make the TestNetworkServiceClient respond one less file as requested.
+    files.pop_back();
+  }
+
   std::move(callback).Run(net::OK, std::move(files));
 }
 
diff --git a/services/network/test/test_network_service_client.h b/services/network/test/test_network_service_client.h
index e79f32e9..cc70741 100644
--- a/services/network/test/test_network_service_client.h
+++ b/services/network/test/test_network_service_client.h
@@ -20,8 +20,12 @@
   explicit TestNetworkServiceClient(mojom::NetworkServiceClientRequest request);
   ~TestNetworkServiceClient() override;
 
-  void DisableUploads();
-  void EnableUploads();
+  void set_upload_files_invalid(bool upload_files_invalid) {
+    upload_files_invalid_ = upload_files_invalid;
+  }
+  void set_ignore_last_upload_file(bool ignore_last_upload_file) {
+    ignore_last_upload_file_ = ignore_last_upload_file;
+  }
 
   // network::mojom::NetworkServiceClient implementation:
   void OnAuthRequired(
@@ -91,7 +95,8 @@
 #endif
 
  private:
-  bool enable_uploads_;
+  bool upload_files_invalid_ = false;
+  bool ignore_last_upload_file_ = false;
   mojo::Binding<mojom::NetworkServiceClient> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(TestNetworkServiceClient);
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 98539f1..a71b604 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -57,8 +57,6 @@
 // mojo::core::Core::CreateDataPipe
 constexpr size_t kBlockedBodyAllocationSize = 1;
 
-constexpr size_t kMaxFileUploadRequestsPerBatch = 64;
-
 // TODO: this duplicates some of PopulateResourceResponse in
 // content/browser/loader/resource_loader.cc
 void PopulateResourceResponse(net::URLRequest* request,
@@ -588,7 +586,11 @@
                             std::vector<base::File> opened_files) {
   if (error_code != net::OK) {
     DCHECK(opened_files.empty());
-    NotifyCompleted(error_code);
+    // Defer calling NotifyCompleted to make sure the URLLoader finishes
+    // initializing before getting deleted.
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&URLLoader::NotifyCompleted,
+                                  base::Unretained(this), error_code));
     return;
   }
   scoped_refptr<base::SequencedTaskRunner> task_runner =
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index 83f24c58..0b4934e 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -40,6 +40,8 @@
 
 namespace network {
 
+constexpr size_t kMaxFileUploadRequestsPerBatch = 64;
+
 class NetToMojoPendingBuffer;
 class NetworkUsageAccumulator;
 class KeepaliveStatisticsRecorder;
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 2e73c43..07e8640 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -421,8 +421,12 @@
       options |= mojom::kURLLoadOptionSendSSLInfoForCertificateError;
 
     std::unique_ptr<TestNetworkServiceClient> network_service_client;
-    if (allow_file_uploads_)
+    if (allow_file_uploads_) {
       network_service_client = std::make_unique<TestNetworkServiceClient>();
+      network_service_client->set_upload_files_invalid(upload_files_invalid_);
+      network_service_client->set_ignore_last_upload_file(
+          ignore_last_upload_file_);
+    }
 
     if (request_body_)
       request.request_body = request_body_;
@@ -574,6 +578,14 @@
     DCHECK(!ran_);
     allow_file_uploads_ = true;
   }
+  void set_upload_files_invalid(bool upload_files_invalid) {
+    DCHECK(!ran_);
+    upload_files_invalid_ = upload_files_invalid;
+  }
+  void set_ignore_last_upload_file(bool ignore_last_upload_file) {
+    DCHECK(!ran_);
+    ignore_last_upload_file_ = ignore_last_upload_file;
+  }
   void set_sniff() {
     DCHECK(!ran_);
     sniff_ = true;
@@ -695,6 +707,8 @@
 
   // Options applied to the created request in Load().
   bool allow_file_uploads_ = false;
+  bool upload_files_invalid_ = false;
+  bool ignore_last_upload_file_ = false;
   bool sniff_ = false;
   bool send_ssl_with_response_ = false;
   bool send_ssl_for_cert_error_ = false;
@@ -1391,7 +1405,77 @@
   EXPECT_EQ(expected_body1 + expected_body2, response_body);
 }
 
+TEST_F(URLLoaderTest, UploadTwoBatchesOfFiles) {
+  allow_file_uploads();
+  base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+  std::string expected_body;
+  size_t num_files = 2 * kMaxFileUploadRequestsPerBatch;
+  for (size_t i = 0; i < num_files; ++i) {
+    std::string tmp_expected_body;
+    ASSERT_TRUE(base::ReadFileToString(file_path, &tmp_expected_body))
+        << "File not found: " << file_path.value();
+    expected_body += tmp_expected_body;
+  }
+
+  scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+  for (size_t i = 0; i < num_files; ++i) {
+    request_body->AppendFileRange(
+        file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
+  }
+  set_request_body(std::move(request_body));
+
+  std::string response_body;
+  EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+  EXPECT_EQ(expected_body, response_body);
+}
+
+TEST_F(URLLoaderTest, UploadTwoBatchesOfFilesWithRespondInvalidFile) {
+  allow_file_uploads();
+  set_upload_files_invalid(true);
+  base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+  scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+  size_t num_files = 2 * kMaxFileUploadRequestsPerBatch;
+  for (size_t i = 0; i < num_files; ++i) {
+    request_body->AppendFileRange(
+        file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
+  }
+  set_request_body(std::move(request_body));
+
+  EXPECT_EQ(net::ERR_ACCESS_DENIED, Load(test_server()->GetURL("/echo")));
+}
+
+TEST_F(URLLoaderTest, UploadTwoBatchesOfFilesWithRespondDifferentNumOfFiles) {
+  allow_file_uploads();
+  set_ignore_last_upload_file(true);
+  base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+  scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+  size_t num_files = 2 * kMaxFileUploadRequestsPerBatch;
+  for (size_t i = 0; i < num_files; ++i) {
+    request_body->AppendFileRange(
+        file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
+  }
+  set_request_body(std::move(request_body));
+
+  EXPECT_EQ(net::ERR_FAILED, Load(test_server()->GetURL("/echo")));
+}
+
 TEST_F(URLLoaderTest, UploadInvalidFile) {
+  allow_file_uploads();
+  set_upload_files_invalid(true);
+  base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+  scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+  request_body->AppendFileRange(
+      file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
+  set_request_body(std::move(request_body));
+
+  EXPECT_EQ(net::ERR_ACCESS_DENIED, Load(test_server()->GetURL("/echo")));
+}
+
+TEST_F(URLLoaderTest, UploadFileWithoutNetworkServiceClient) {
   // Don't call allow_file_uploads();
   base::FilePath file_path = GetTestFilePath("simple_page.html");
 
diff --git a/services/resource_coordinator/public/cpp/coordination_unit_id.h b/services/resource_coordinator/public/cpp/coordination_unit_id.h
index a94a2a1..77b39c9 100644
--- a/services/resource_coordinator/public/cpp/coordination_unit_id.h
+++ b/services/resource_coordinator/public/cpp/coordination_unit_id.h
@@ -1,9 +1,11 @@
 // Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
 #ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_ID_H_
 #define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_ID_H_
 
+#include <functional>
 #include <string>
 #include <tuple>
 
diff --git a/services/service_manager/sandbox/win/sandbox_win.cc b/services/service_manager/sandbox/win/sandbox_win.cc
index f4c3eed..2d994b72 100644
--- a/services/service_manager/sandbox/win/sandbox_win.cc
+++ b/services/service_manager/sandbox/win/sandbox_win.cc
@@ -15,7 +15,8 @@
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
+#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/memory/shared_memory.h"
 #include "base/metrics/field_trial.h"
@@ -23,7 +24,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
-#include "base/sha1.h"
 #include "base/stl_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string16.h"
diff --git a/services/tracing/perfetto/consumer_host.cc b/services/tracing/perfetto/consumer_host.cc
index 114aa08..e72cfe8 100644
--- a/services/tracing/perfetto/consumer_host.cc
+++ b/services/tracing/perfetto/consumer_host.cc
@@ -33,8 +33,11 @@
   return base::StringToUint(input, reinterpret_cast<uint32_t*>(output));
 }
 
-bool ParsePidFromProducerName(const std::string& producer_name,
-                              base::ProcessId* pid) {
+}  // namespace
+
+// static
+bool ConsumerHost::ParsePidFromProducerName(const std::string& producer_name,
+                                            base::ProcessId* pid) {
   if (!base::StartsWith(producer_name, mojom::kPerfettoProducerNamePrefix,
                         base::CompareCase::SENSITIVE)) {
     LOG(DFATAL) << "Unexpected producer name: " << producer_name;
@@ -50,8 +53,6 @@
   return true;
 }
 
-}  // namespace
-
 // static
 void ConsumerHost::BindConsumerRequest(
     PerfettoService* service,
diff --git a/services/tracing/perfetto/consumer_host.h b/services/tracing/perfetto/consumer_host.h
index 3505d8f..633cacc6 100644
--- a/services/tracing/perfetto/consumer_host.h
+++ b/services/tracing/perfetto/consumer_host.h
@@ -34,6 +34,9 @@
       mojom::ConsumerHostRequest request,
       const service_manager::BindSourceInfo& source_info);
 
+  static bool ParsePidFromProducerName(const std::string& producer_name,
+                                       base::ProcessId* pid);
+
   // The owner of ConsumerHost should make sure to destroy
   // |service| after destroying this.
   explicit ConsumerHost(PerfettoService* service);
diff --git a/services/tracing/perfetto/consumer_host_unittest.cc b/services/tracing/perfetto/consumer_host_unittest.cc
index 05aae1a..eb3f0e8 100644
--- a/services/tracing/perfetto/consumer_host_unittest.cc
+++ b/services/tracing/perfetto/consumer_host_unittest.cc
@@ -111,7 +111,7 @@
                                 size_t num_packets) {
     producer_ = std::make_unique<MockProducer>(
         base::StrCat({mojom::kPerfettoProducerNamePrefix,
-                      base::IntToString(kProducerPid)}),
+                      base::NumberToString(kProducerPid)}),
         data_source_name, perfetto_service_->GetService(),
         std::move(on_datasource_registered), std::move(on_tracing_started),
         num_packets);
@@ -454,7 +454,7 @@
   auto config = GetDefaultTraceConfig(mojom::kTraceEventDataSourceName);
   *config.mutable_data_sources()->front().add_producer_name_filter() =
       base::StrCat({mojom::kPerfettoProducerNamePrefix,
-                    base::IntToString(kProducerPid)});
+                    base::NumberToString(kProducerPid)});
   threaded_perfetto_service()->EnableTracingWithConfig(config);
 
   // Tracing is only marked as enabled once the expected producer has acked that
@@ -479,7 +479,7 @@
   auto config = GetDefaultTraceConfig(mojom::kTraceEventDataSourceName);
   *config.mutable_data_sources()->front().add_producer_name_filter() =
       base::StrCat({mojom::kPerfettoProducerNamePrefix,
-                    base::IntToString(kProducerPid + 1)});
+                    base::NumberToString(kProducerPid + 1)});
   threaded_perfetto_service()->EnableTracingWithConfig(config);
 
   // Tracing should already have been enabled even though the host was told
diff --git a/services/tracing/perfetto/perfetto_tracing_coordinator.cc b/services/tracing/perfetto/perfetto_tracing_coordinator.cc
index b74652e..f3b1f1f 100644
--- a/services/tracing/perfetto/perfetto_tracing_coordinator.cc
+++ b/services/tracing/perfetto/perfetto_tracing_coordinator.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/command_line.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
@@ -16,6 +17,7 @@
 #include "build/build_config.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "mojo/public/cpp/system/data_pipe_utils.h"
+#include "services/tracing/perfetto/consumer_host.h"
 #include "services/tracing/perfetto/perfetto_service.h"
 #include "services/tracing/perfetto/track_event_json_exporter.h"
 #include "services/tracing/public/cpp/trace_event_args_whitelist.h"
@@ -37,8 +39,11 @@
 class PerfettoTracingCoordinator::TracingSession : public perfetto::Consumer {
  public:
   TracingSession(const base::trace_event::TraceConfig& chrome_config,
-                 base::OnceClosure tracing_over_callback)
-      : tracing_over_callback_(std::move(tracing_over_callback)) {
+                 base::OnceClosure tracing_over_callback,
+                 const base::RepeatingCallback<void(base::ProcessId)>&
+                     on_pid_started_tracing)
+      : tracing_over_callback_(std::move(tracing_over_callback)),
+        on_pid_started_tracing_(std::move(on_pid_started_tracing)) {
     // In legacy backend, the trace event agent sets the predicate used by
     // TraceLog. For perfetto backend, ensure that predicate is always set
     // before creating the exporter. The agent can be created later than this
@@ -64,6 +69,9 @@
     perfetto::TracingService* service =
         PerfettoService::GetInstance()->GetService();
     consumer_endpoint_ = service->ConnectConsumer(this, /*uid=*/0);
+    consumer_endpoint_->ObserveEvents(
+        perfetto::TracingService::ConsumerEndpoint::ObservableEventType::
+            kDataSourceInstances);
 
     // Start tracing.
     auto perfetto_config = CreatePerfettoConfiguration(chrome_config);
@@ -238,7 +246,28 @@
         .Run(true, percent_full, 0 /*approx_event_count*/);
   }
 
-  void OnObservableEvents(const perfetto::ObservableEvents&) override {}
+  void OnObservableEvents(const perfetto::ObservableEvents& events) override {
+    for (const auto& state_change : events.instance_state_changes()) {
+      if (state_change.state() !=
+          perfetto::ObservableEvents::DataSourceInstanceStateChange::
+              DATA_SOURCE_INSTANCE_STATE_STARTED) {
+        continue;
+      }
+
+      if (state_change.data_source_name() != mojom::kTraceEventDataSourceName) {
+        continue;
+      }
+
+      // Attempt to parse the PID out of the producer name.
+      base::ProcessId pid;
+      if (!ConsumerHost::ParsePidFromProducerName(state_change.producer_name(),
+                                                  &pid)) {
+        continue;
+      }
+
+      on_pid_started_tracing_.Run(pid);
+    }
+  }
 
  private:
   mojo::ScopedDataPipeProducerHandle stream_;
@@ -246,6 +275,7 @@
   StopAndFlushCallback stop_and_flush_callback_;
   base::OnceClosure tracing_over_callback_;
   RequestBufferUsageCallback request_buffer_usage_callback_;
+  base::RepeatingCallback<void(base::ProcessId)> on_pid_started_tracing_;
 
 #if DCHECK_IS_ON()
   base::trace_event::TraceConfig last_config_for_perfetto_;
@@ -300,55 +330,75 @@
     return;
   }
 
+  base::trace_event::TraceConfig old_parsed_config(parsed_config_);
   parsed_config_ = new_parsed_config;
+
   if (!tracing_session_) {
     tracing_session_ = std::make_unique<TracingSession>(
         parsed_config_,
         base::BindOnce(&PerfettoTracingCoordinator::OnTracingOverCallback,
-                       weak_factory_.GetWeakPtr()));
+                       base::Unretained(this)),
+        base::BindRepeating(&PerfettoTracingCoordinator::OnPIDStartedTracing,
+                            base::Unretained(this)));
+
+    agent_registry_->SetAgentInitializationCallback(
+        base::BindRepeating(
+            &PerfettoTracingCoordinator::WaitForAgentToBeginTracing,
+            weak_factory_.GetWeakPtr()),
+        false /* call_on_new_agents_only */);
+
   } else {
+    agent_registry_->ForAllAgents(
+        [this, &old_parsed_config,
+         &new_parsed_config](AgentRegistry::AgentEntry* agent_entry) {
+          if (!old_parsed_config.process_filter_config().IsEnabled(
+                  agent_entry->pid()) &&
+              new_parsed_config.process_filter_config().IsEnabled(
+                  agent_entry->pid())) {
+            WaitForAgentToBeginTracing(agent_entry);
+          }
+        });
+
     tracing_session_->ChangeTraceConfig(parsed_config_);
   }
 
-  agent_registry_->SetAgentInitializationCallback(
-      base::BindRepeating(&PerfettoTracingCoordinator::PingAgent,
-                          weak_factory_.GetWeakPtr()),
-      false /* call_on_new_agents_only */);
-
   SetStartTracingCallback(std::move(callback));
 }
 
-void PerfettoTracingCoordinator::PingAgent(
+void PerfettoTracingCoordinator::OnPIDStartedTracing(base::ProcessId pid) {
+  agent_registry_->ForAllAgents(
+      [this, pid](AgentRegistry::AgentEntry* agent_entry) {
+        if (pid == agent_entry->pid()) {
+          OnAgentStartedTracing(agent_entry);
+        }
+      });
+}
+
+void PerfettoTracingCoordinator::OnAgentStartedTracing(
     AgentRegistry::AgentEntry* agent_entry) {
-  if (!parsed_config_.process_filter_config().IsEnabled(agent_entry->pid()))
+  agent_entry->RemoveDisconnectClosure(GetStartTracingClosureName());
+  CallStartTracingCallbackIfNeeded();
+}
+
+void PerfettoTracingCoordinator::WaitForAgentToBeginTracing(
+    AgentRegistry::AgentEntry* agent_entry) {
+  if (!agent_entry->pid() ||
+      !parsed_config_.process_filter_config().IsEnabled(agent_entry->pid()))
     return;
 
-  // TODO(oysteine): While we're still using the Agent
-  // system as a fallback when using Perfetto, rather than
-  // the browser directly using a Consumer interface, we have to
-  // attempt to linearize with newly connected agents so we only
-  // call the BeginTracing callback when we can be sure
-  // that all current agents have registered with Perfetto and
-  // started tracing if requested. We do this linearization
-  // explicitly using WaitForTracingEnabled() which will wait
-  // for the TraceLog to be enabled before calling its provided
-  // callback.
-  auto closure = base::BindRepeating(
-      [](base::WeakPtr<PerfettoTracingCoordinator> coordinator,
-         AgentRegistry::AgentEntry* agent_entry) {
-        bool removed =
-            agent_entry->RemoveDisconnectClosure(GetStartTracingClosureName());
-        DCHECK(removed);
+  // TODO(oysteine): While we're still using the Agent system as a fallback when
+  // using Perfetto, rather than the browser directly using a Consumer
+  // interface, we have to attempt to linearize with newly connected agents so
+  // we only call the BeginTracing callback when we can be sure that all current
+  // agents have registered with Perfetto and started tracing if requested. We
+  // do this by adding a disconnect closure to all newly connected agents and
+  // then wait for Perfetto to tell us their data sources are connected.
+  agent_entry->AddDisconnectClosure(
+      GetStartTracingClosureName(),
+      base::BindOnce(&PerfettoTracingCoordinator::OnAgentStartedTracing,
+                     weak_factory_.GetWeakPtr(),
+                     base::Unretained(agent_entry)));
 
-        if (coordinator) {
-          coordinator->CallStartTracingCallbackIfNeeded();
-        }
-      },
-      weak_factory_.GetWeakPtr(), base::Unretained(agent_entry));
-
-  agent_entry->AddDisconnectClosure(GetStartTracingClosureName(), closure);
-
-  agent_entry->agent()->WaitForTracingEnabled(closure);
   RemoveExpectedPID(agent_entry->pid());
 }
 
diff --git a/services/tracing/perfetto/perfetto_tracing_coordinator.h b/services/tracing/perfetto/perfetto_tracing_coordinator.h
index 422a97a..4bdeb2e 100644
--- a/services/tracing/perfetto/perfetto_tracing_coordinator.h
+++ b/services/tracing/perfetto/perfetto_tracing_coordinator.h
@@ -48,9 +48,11 @@
   void RequestBufferUsage(RequestBufferUsageCallback callback) override;
 
  private:
+  void OnPIDStartedTracing(base::ProcessId pid);
+  void OnAgentStartedTracing(AgentRegistry::AgentEntry* agent_entry);
   void OnTracingOverCallback();
   void OnClientConnectionError() override;
-  void PingAgent(AgentRegistry::AgentEntry* agent_entry);
+  void WaitForAgentToBeginTracing(AgentRegistry::AgentEntry* agent_entry);
   void StopAndFlushInternal(mojo::ScopedDataPipeProducerHandle stream,
                             const std::string& agent_label,
                             StopAndFlushCallback callback);
diff --git a/services/tracing/public/cpp/base_agent.cc b/services/tracing/public/cpp/base_agent.cc
index 661aac6..ee7ac41 100644
--- a/services/tracing/public/cpp/base_agent.cc
+++ b/services/tracing/public/cpp/base_agent.cc
@@ -59,11 +59,6 @@
   std::move(callback).Run(0 /* capacity */, 0 /* count */);
 }
 
-void BaseAgent::WaitForTracingEnabled(
-    Agent::WaitForTracingEnabledCallback callback) {
-  std::move(callback).Run();
-}
-
 bool BaseAgent::IsBoundForTesting() const {
   return binding_.is_bound();
 }
diff --git a/services/tracing/public/cpp/base_agent.h b/services/tracing/public/cpp/base_agent.h
index 6fd6c43..b421df1 100644
--- a/services/tracing/public/cpp/base_agent.h
+++ b/services/tracing/public/cpp/base_agent.h
@@ -42,8 +42,6 @@
   void StopAndFlush(tracing::mojom::RecorderPtr recorder) override;
   void RequestBufferStatus(
       Agent::RequestBufferStatusCallback callback) override;
-  void WaitForTracingEnabled(
-      Agent::WaitForTracingEnabledCallback callback) override;
 
   mojo::Binding<tracing::mojom::Agent> binding_;
 
diff --git a/services/tracing/public/cpp/perfetto/traced_value_proto_writer.cc b/services/tracing/public/cpp/perfetto/traced_value_proto_writer.cc
index dbab564..562c8b07 100644
--- a/services/tracing/public/cpp/perfetto/traced_value_proto_writer.cc
+++ b/services/tracing/public/cpp/perfetto/traced_value_proto_writer.cc
@@ -6,7 +6,7 @@
 #include <memory>
 #include <stack>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/json/string_escape.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
diff --git a/services/tracing/public/cpp/trace_event_agent.cc b/services/tracing/public/cpp/trace_event_agent.cc
index 2d3fa64..510cb9d 100644
--- a/services/tracing/public/cpp/trace_event_agent.cc
+++ b/services/tracing/public/cpp/trace_event_agent.cc
@@ -56,15 +56,10 @@
         base::BindRepeating(&IsMetadataWhitelisted));
   }
 
-  base::trace_event::TraceLog::GetInstance()->AddAsyncEnabledStateObserver(
-      weak_ptr_factory_.GetWeakPtr());
-
   ProducerClient::Get()->AddDataSource(TraceEventDataSource::GetInstance());
 }
 
-TraceEventAgent::~TraceEventAgent() {
-  DCHECK(!tracing_enabled_callback_);
-}
+TraceEventAgent::~TraceEventAgent() = default;
 
 void TraceEventAgent::GetCategories(std::set<std::string>* category_set) {
   for (size_t i = base::trace_event::BuiltinCategories::kVisibleCategoryStart;
@@ -94,7 +89,6 @@
                                    StartTracingCallback callback) {
   DCHECK(!IsBoundForTesting() || !TracingUsesPerfettoBackend());
   DCHECK(!recorder_);
-  DCHECK(!tracing_enabled_callback_);
 #if defined(__native_client__)
   // NaCl and system times are offset by a bit, so subtract some time from
   // the captured timestamps. The value might be off by a bit due to messaging
@@ -137,29 +131,6 @@
   std::move(callback).Run(status.event_capacity, status.event_count);
 }
 
-void TraceEventAgent::WaitForTracingEnabled(
-    Agent::WaitForTracingEnabledCallback callback) {
-  DCHECK(TracingUsesPerfettoBackend());
-  DCHECK(!tracing_enabled_callback_);
-  tracing_enabled_callback_ = std::move(callback);
-  if (base::trace_event::TraceLog::GetInstance()->IsEnabled()) {
-    std::move(tracing_enabled_callback_).Run();
-    return;
-  }
-}
-
-// This callback will always come on the same sequence
-// that TraceLog::AddAsyncEnabledStateObserver was called
-// on to begin with, i.e. the same as any WaitForTracingEnabled()
-// calls are run on.
-void TraceEventAgent::OnTraceLogEnabled() {
-  if (tracing_enabled_callback_) {
-    std::move(tracing_enabled_callback_).Run();
-  }
-}
-
-void TraceEventAgent::OnTraceLogDisabled() {}
-
 void TraceEventAgent::OnTraceLogFlush(
     const scoped_refptr<base::RefCountedString>& events_str,
     bool has_more_events) {
diff --git a/services/tracing/public/cpp/trace_event_agent.h b/services/tracing/public/cpp/trace_event_agent.h
index 3f62b45..2b532c3 100644
--- a/services/tracing/public/cpp/trace_event_agent.h
+++ b/services/tracing/public/cpp/trace_event_agent.h
@@ -15,7 +15,6 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "base/trace_event/trace_log.h"
 #include "base/values.h"
 #include "services/tracing/public/cpp/base_agent.h"
 #include "services/tracing/public/mojom/tracing.mojom.h"
@@ -31,9 +30,7 @@
 // most of the mojom::Agent functions will never be used
 // as the control signals will go through the Perfetto
 // interface instead.
-class COMPONENT_EXPORT(TRACING_CPP) TraceEventAgent
-    : public BaseAgent,
-      public base::trace_event::TraceLog::AsyncEnabledStateObserver {
+class COMPONENT_EXPORT(TRACING_CPP) TraceEventAgent : public BaseAgent {
  public:
   static TraceEventAgent* GetInstance();
 
@@ -61,17 +58,10 @@
 
   void OnTraceLogFlush(const scoped_refptr<base::RefCountedString>& events_str,
                        bool has_more_events);
-  void WaitForTracingEnabled(
-      Agent::WaitForTracingEnabledCallback callback) override;
-
-  // base::trace_event::TraceLog::AsyncEnabledStateObserver
-  void OnTraceLogEnabled() override;
-  void OnTraceLogDisabled() override;
 
   uint8_t enabled_tracing_modes_;
   mojom::RecorderPtr recorder_;
   std::vector<MetadataGeneratorFunction> metadata_generator_functions_;
-  Agent::WaitForTracingEnabledCallback tracing_enabled_callback_;
 
   THREAD_CHECKER(thread_checker_);
   base::WeakPtrFactory<TraceEventAgent> weak_ptr_factory_;
diff --git a/services/tracing/public/mojom/tracing.mojom b/services/tracing/public/mojom/tracing.mojom
index 1e9014e4..3c282c4 100644
--- a/services/tracing/public/mojom/tracing.mojom
+++ b/services/tracing/public/mojom/tracing.mojom
@@ -43,16 +43,6 @@
       => (bool success);
   StopAndFlush(Recorder recorder);
   RequestBufferStatus() => (uint32 capacity, uint32 count);
-  // This is only ever needed when the legacy Coordinator uses Perfetto to
-  // start tracing, rather than calling StartTracing on each agent through
-  // this interface. In that case, the Coordinator still needs a way of
-  // deferring the success callback until we know that tracing has started
-  // in each relevant process. This is a temporary thing until all clients
-  // of the TracingController in the browser (which uses the
-  // Coordinator interface) have been migrated to use the Perfetto
-  // Consumer interface directly instead, and the Coordinator/Agent
-  // interfaces can be removed.
-  WaitForTracingEnabled() => ();
 };
 
 // An agent can make several calls to |AddChunk|. Chunks will be concatenated
diff --git a/services/tracing/test_util.cc b/services/tracing/test_util.cc
index b6674a8..fe0b288 100644
--- a/services/tracing/test_util.cc
+++ b/services/tracing/test_util.cc
@@ -43,9 +43,4 @@
                     trace_log_status_.event_count);
 }
 
-void MockAgent::WaitForTracingEnabled(
-    Agent::WaitForTracingEnabledCallback callback) {
-  std::move(callback).Run();
-}
-
 }  // namespace tracing
diff --git a/services/tracing/test_util.h b/services/tracing/test_util.h
index fa72baf..821a7eb0 100644
--- a/services/tracing/test_util.h
+++ b/services/tracing/test_util.h
@@ -41,8 +41,6 @@
                     StartTracingCallback cb) override;
   void StopAndFlush(mojom::RecorderPtr recorder) override;
   void RequestBufferStatus(RequestBufferStatusCallback cb) override;
-  void WaitForTracingEnabled(
-      Agent::WaitForTracingEnabledCallback callback) override;
 
   mojo::Binding<mojom::Agent> binding_;
   std::vector<std::string> call_stat_;
diff --git a/services/video_capture/test/device_factory_provider_test.cc b/services/video_capture/test/device_factory_provider_test.cc
index 1e3588fbc..a447b7f1 100644
--- a/services/video_capture/test/device_factory_provider_test.cc
+++ b/services/video_capture/test/device_factory_provider_test.cc
@@ -42,7 +42,7 @@
 
 void DeviceFactoryProviderTest::SetUp() {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kUseFakeJpegDecodeAccelerator);
+      switches::kUseFakeMjpegDecodeAccelerator);
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kUseFakeDeviceForMediaStream, "device-count=3");
 
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 793d9b1..4788b3f 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -544,7 +544,7 @@
 
   if (is_android) {
     deps += [
-      "//third_party/android_tools:cpu_features",
+      "//third_party/android_sdk:cpu_features",
       "//third_party/expat",
     ]
   }
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn
index 97dbb48..5e98f38 100644
--- a/storage/browser/BUILD.gn
+++ b/storage/browser/BUILD.gn
@@ -282,8 +282,8 @@
     "fileapi/copy_or_move_operation_delegate_unittest.cc",
     "fileapi/dragged_file_util_unittest.cc",
     "fileapi/external_mount_points_unittest.cc",
-    "fileapi/file_stream_reader_test_utils.cc",
-    "fileapi/file_stream_reader_test_utils.h",
+    "fileapi/file_stream_test_utils.cc",
+    "fileapi/file_stream_test_utils.h",
     "fileapi/file_system_context_unittest.cc",
     "fileapi/file_system_dir_url_request_job_unittest.cc",
     "fileapi/file_system_file_stream_reader_unittest.cc",
@@ -300,6 +300,7 @@
     "fileapi/local_file_stream_writer_unittest.cc",
     "fileapi/local_file_util_unittest.cc",
     "fileapi/memory_file_stream_reader_unittest.cc",
+    "fileapi/memory_file_stream_writer_unittest.cc",
     "fileapi/native_file_util_unittest.cc",
     "fileapi/obfuscated_file_util_memory_delegate_unittest.cc",
     "fileapi/obfuscated_file_util_unittest.cc",
diff --git a/storage/browser/blob/shareable_blob_data_item.h b/storage/browser/blob/shareable_blob_data_item.h
index fe4ea5b..f16df2aa 100644
--- a/storage/browser/blob/shareable_blob_data_item.h
+++ b/storage/browser/blob/shareable_blob_data_item.h
@@ -9,7 +9,7 @@
 
 #include "base/callback_helpers.h"
 #include "base/component_export.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "storage/browser/blob/blob_memory_controller.h"
diff --git a/storage/browser/fileapi/file_stream_reader_test_utils.cc b/storage/browser/fileapi/file_stream_reader_test_utils.cc
deleted file mode 100644
index 6504f05e..0000000
--- a/storage/browser/fileapi/file_stream_reader_test_utils.cc
+++ /dev/null
@@ -1,41 +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 "storage/browser/fileapi/file_stream_reader_test_utils.h"
-
-#include <string>
-
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "storage/browser/fileapi/file_stream_reader.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace storage {
-
-void ReadFromReader(FileStreamReader* reader,
-                    std::string* data,
-                    size_t size,
-                    int* result) {
-  ASSERT_TRUE(reader != nullptr);
-  ASSERT_TRUE(result != nullptr);
-  *result = net::OK;
-  size_t total_bytes_read = 0;
-  while (total_bytes_read < size) {
-    scoped_refptr<net::IOBufferWithSize> buf(
-        base::MakeRefCounted<net::IOBufferWithSize>(size - total_bytes_read));
-    net::TestCompletionCallback callback;
-    int rv = reader->Read(buf.get(), buf->size(), callback.callback());
-    if (rv == net::ERR_IO_PENDING)
-      rv = callback.WaitForResult();
-    if (rv < 0)
-      *result = rv;
-    if (rv <= 0)
-      break;
-    total_bytes_read += rv;
-    data->append(buf->data(), rv);
-  }
-}
-
-}  // namespace storage
diff --git a/storage/browser/fileapi/file_stream_test_utils.cc b/storage/browser/fileapi/file_stream_test_utils.cc
new file mode 100644
index 0000000..127fee1
--- /dev/null
+++ b/storage/browser/fileapi/file_stream_test_utils.cc
@@ -0,0 +1,62 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "storage/browser/fileapi/file_stream_test_utils.h"
+
+#include <string>
+#include <utility>
+
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "storage/browser/fileapi/file_stream_reader.h"
+#include "storage/browser/fileapi/file_stream_writer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace storage {
+
+void ReadFromReader(FileStreamReader* reader,
+                    std::string* data,
+                    size_t size,
+                    int* result) {
+  ASSERT_TRUE(reader != nullptr);
+  ASSERT_TRUE(result != nullptr);
+  *result = net::OK;
+  size_t total_bytes_read = 0;
+  while (total_bytes_read < size) {
+    scoped_refptr<net::IOBufferWithSize> buf(
+        base::MakeRefCounted<net::IOBufferWithSize>(size - total_bytes_read));
+    net::TestCompletionCallback callback;
+    int rv = reader->Read(buf.get(), buf->size(), callback.callback());
+    if (rv == net::ERR_IO_PENDING)
+      rv = callback.WaitForResult();
+    if (rv < 0)
+      *result = rv;
+    if (rv <= 0)
+      break;
+    total_bytes_read += rv;
+    data->append(buf->data(), rv);
+  }
+}
+
+int WriteStringToWriter(FileStreamWriter* writer, const std::string& data) {
+  scoped_refptr<net::StringIOBuffer> buffer =
+      base::MakeRefCounted<net::StringIOBuffer>(data);
+  scoped_refptr<net::DrainableIOBuffer> drainable =
+      base::MakeRefCounted<net::DrainableIOBuffer>(std::move(buffer),
+                                                   data.size());
+  while (drainable->BytesRemaining() > 0) {
+    net::TestCompletionCallback callback;
+    int result = writer->Write(drainable.get(), drainable->BytesRemaining(),
+                               callback.callback());
+    if (result == net::ERR_IO_PENDING)
+      result = callback.WaitForResult();
+    if (result <= 0)
+      return result;
+    drainable->DidConsume(result);
+  }
+  return net::OK;
+}
+
+}  // namespace storage
diff --git a/storage/browser/fileapi/file_stream_reader_test_utils.h b/storage/browser/fileapi/file_stream_test_utils.h
similarity index 61%
rename from storage/browser/fileapi/file_stream_reader_test_utils.h
rename to storage/browser/fileapi/file_stream_test_utils.h
index 0cd3e74..ed67e09 100644
--- a/storage/browser/fileapi/file_stream_reader_test_utils.h
+++ b/storage/browser/fileapi/file_stream_test_utils.h
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef STORAGE_BROWSER_FILEAPI_FILE_STREAM_READER_TEST_UTILS_H_
-#define STORAGE_BROWSER_FILEAPI_FILE_STREAM_READER_TEST_UTILS_H_
+#ifndef STORAGE_BROWSER_FILEAPI_FILE_STREAM_TEST_UTILS_H_
+#define STORAGE_BROWSER_FILEAPI_FILE_STREAM_TEST_UTILS_H_
 
 #include <string>
 
 namespace storage {
 
 class FileStreamReader;
+class FileStreamWriter;
 
 // Reads upto |size| bytes of data from |reader|, an initialized
 // FileStreamReader. The read bytes will be written to |data| and the actual
@@ -19,6 +20,10 @@
                     size_t size,
                     int* result);
 
+// Writes |data| to |writer|, an intialized FileStreamWriter. Returns net::OK if
+// successful, otherwise a net error.
+int WriteStringToWriter(FileStreamWriter* writer, const std::string& data);
+
 }  // namespace storage
 
-#endif  // STORAGE_BROWSER_FILEAPI_FILE_STREAM_READER_TEST_UTILS_H_
\ No newline at end of file
+#endif  // STORAGE_BROWSER_FILEAPI_FILE_STREAM_TEST_UTILS_H_
\ No newline at end of file
diff --git a/storage/browser/fileapi/file_system_file_stream_reader_unittest.cc b/storage/browser/fileapi/file_system_file_stream_reader_unittest.cc
index dbd4830..6fe5ee6 100644
--- a/storage/browser/fileapi/file_system_file_stream_reader_unittest.cc
+++ b/storage/browser/fileapi/file_system_file_stream_reader_unittest.cc
@@ -21,7 +21,7 @@
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
 #include "storage/browser/fileapi/external_mount_points.h"
-#include "storage/browser/fileapi/file_stream_reader_test_utils.h"
+#include "storage/browser/fileapi/file_stream_test_utils.h"
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_file_util.h"
 #include "storage/browser/test/async_file_test_helper.h"
diff --git a/storage/browser/fileapi/local_file_stream_reader_unittest.cc b/storage/browser/fileapi/local_file_stream_reader_unittest.cc
index f21dafe..baf8ec9 100644
--- a/storage/browser/fileapi/local_file_stream_reader_unittest.cc
+++ b/storage/browser/fileapi/local_file_stream_reader_unittest.cc
@@ -26,7 +26,7 @@
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
-#include "storage/browser/fileapi/file_stream_reader_test_utils.h"
+#include "storage/browser/fileapi/file_stream_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using storage::LocalFileStreamReader;
diff --git a/storage/browser/fileapi/local_file_stream_writer_unittest.cc b/storage/browser/fileapi/local_file_stream_writer_unittest.cc
index c5aceca..3ae26b9 100644
--- a/storage/browser/fileapi/local_file_stream_writer_unittest.cc
+++ b/storage/browser/fileapi/local_file_stream_writer_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/threading/thread.h"
 #include "net/base/io_buffer.h"
 #include "net/base/test_completion_callback.h"
+#include "storage/browser/fileapi/file_stream_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using storage::FileStreamWriter;
@@ -48,27 +49,6 @@
     return temp_dir_.GetPath().AppendASCII(name);
   }
 
-  int WriteStringToWriter(LocalFileStreamWriter* writer,
-                          const std::string& data) {
-    scoped_refptr<net::StringIOBuffer> buffer =
-        base::MakeRefCounted<net::StringIOBuffer>(data);
-    scoped_refptr<net::DrainableIOBuffer> drainable =
-        base::MakeRefCounted<net::DrainableIOBuffer>(std::move(buffer),
-                                                     data.size());
-
-    while (drainable->BytesRemaining() > 0) {
-      net::TestCompletionCallback callback;
-      int result = writer->Write(
-          drainable.get(), drainable->BytesRemaining(), callback.callback());
-      if (result == net::ERR_IO_PENDING)
-        result = callback.WaitForResult();
-      if (result <= 0)
-        return result;
-      drainable->DidConsume(result);
-    }
-    return net::OK;
-  }
-
   std::string GetFileContent(const base::FilePath& path) {
     std::string content;
     base::ReadFileToString(path, &content);
diff --git a/storage/browser/fileapi/memory_file_stream_reader_unittest.cc b/storage/browser/fileapi/memory_file_stream_reader_unittest.cc
index dc5a26b..cf04849 100644
--- a/storage/browser/fileapi/memory_file_stream_reader_unittest.cc
+++ b/storage/browser/fileapi/memory_file_stream_reader_unittest.cc
@@ -20,7 +20,7 @@
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "storage/browser/fileapi/file_stream_reader.h"
-#include "storage/browser/fileapi/file_stream_reader_test_utils.h"
+#include "storage/browser/fileapi/file_stream_test_utils.h"
 #include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/storage/browser/fileapi/memory_file_stream_writer.cc b/storage/browser/fileapi/memory_file_stream_writer.cc
index c9dcdd8..37f1e6d 100644
--- a/storage/browser/fileapi/memory_file_stream_writer.cc
+++ b/storage/browser/fileapi/memory_file_stream_writer.cc
@@ -5,8 +5,10 @@
 #include "storage/browser/fileapi/memory_file_stream_writer.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "net/base/net_errors.h"
 
 namespace storage {
 
@@ -19,33 +21,39 @@
       std::move(memory_file_util), file_path, initial_offset, open_or_create));
 }
 
-MemoryFileStreamWriter::~MemoryFileStreamWriter() = default;
-
-int MemoryFileStreamWriter::Write(net::IOBuffer* buf,
-                                  int buf_len,
-                                  net::CompletionOnceCallback callback) {
-  // TODO(https://crbug.com/93417): Implement!
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-int MemoryFileStreamWriter::Cancel(net::CompletionOnceCallback callback) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-int MemoryFileStreamWriter::Flush(net::CompletionOnceCallback callback) {
-  NOTIMPLEMENTED();
-
-  return 0;
-}
-
 MemoryFileStreamWriter::MemoryFileStreamWriter(
     base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
     const base::FilePath& file_path,
     int64_t initial_offset,
     OpenOrCreate open_or_create)
-    : memory_file_util_(std::move(memory_file_util)) {
+    : memory_file_util_(std::move(memory_file_util)),
+      file_path_(file_path),
+      offset_(initial_offset) {
   DCHECK(memory_file_util_);
 }
+
+MemoryFileStreamWriter::~MemoryFileStreamWriter() = default;
+
+int MemoryFileStreamWriter::Write(net::IOBuffer* buf,
+                                  int buf_len,
+                                  net::CompletionOnceCallback /*callback*/) {
+  base::File::Info file_info;
+  if (memory_file_util_->GetFileInfo(file_path_, &file_info) !=
+      base::File::FILE_OK) {
+    return net::ERR_FILE_NOT_FOUND;
+  }
+
+  int result = memory_file_util_->WriteFile(file_path_, offset_, buf, buf_len);
+  if (result > 0)
+    offset_ += result;
+  return result;
+}
+
+int MemoryFileStreamWriter::Cancel(net::CompletionOnceCallback /*callback*/) {
+  return net::ERR_UNEXPECTED;
+}
+
+int MemoryFileStreamWriter::Flush(net::CompletionOnceCallback /*callback*/) {
+  return net::OK;
+}
 }  // namespace storage
diff --git a/storage/browser/fileapi/memory_file_stream_writer.h b/storage/browser/fileapi/memory_file_stream_writer.h
index de6b39f..0d518f6 100644
--- a/storage/browser/fileapi/memory_file_stream_writer.h
+++ b/storage/browser/fileapi/memory_file_stream_writer.h
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "storage/browser/fileapi/file_stream_writer.h"
+#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h"
 
 namespace storage {
 
@@ -36,6 +37,9 @@
 
   base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_;
 
+  const base::FilePath file_path_;
+  int64_t offset_;
+
   DISALLOW_COPY_AND_ASSIGN(MemoryFileStreamWriter);
 };
 
diff --git a/storage/browser/fileapi/memory_file_stream_writer_unittest.cc b/storage/browser/fileapi/memory_file_stream_writer_unittest.cc
new file mode 100644
index 0000000..b2f8b270
--- /dev/null
+++ b/storage/browser/fileapi/memory_file_stream_writer_unittest.cc
@@ -0,0 +1,186 @@
+// 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 "storage/browser/fileapi/memory_file_stream_writer.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "storage/browser/fileapi/file_stream_test_utils.h"
+#include "storage/browser/fileapi/file_stream_writer.h"
+#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace storage {
+
+class MemoryFileStreamWriterTest : public testing::Test {
+ public:
+  MemoryFileStreamWriterTest() {}
+
+  void SetUp() override {
+    ASSERT_TRUE(file_system_directory_.CreateUniqueTempDir());
+    file_util_ = std::make_unique<storage::ObfuscatedFileUtilMemoryDelegate>(
+        file_system_directory_.GetPath());
+  }
+
+  void TearDown() override {
+    // In memory operations should not have any residue in file system
+    // directory.
+    EXPECT_TRUE(base::IsDirectoryEmpty(file_system_directory_.GetPath()));
+  }
+
+  storage::ObfuscatedFileUtilMemoryDelegate* file_util() {
+    return file_util_.get();
+  }
+
+ protected:
+  base::FilePath Path(const std::string& name) {
+    return file_system_directory_.GetPath().AppendASCII(name);
+  }
+
+  std::string GetFileContent(const base::FilePath& path) {
+    base::File::Info info;
+    EXPECT_EQ(base::File::FILE_OK, file_util()->GetFileInfo(path, &info));
+
+    scoped_refptr<net::IOBuffer> content =
+        base::MakeRefCounted<net::IOBuffer>(static_cast<size_t>(info.size));
+    EXPECT_EQ(info.size,
+              file_util_->ReadFile(path, 0, content.get(), info.size));
+
+    return std::string(content->data(), info.size);
+  }
+
+  std::unique_ptr<FileStreamWriter> CreateWriter(const base::FilePath& path,
+                                                 int64_t offset) {
+    return FileStreamWriter::CreateForMemoryFile(
+        file_util_->GetWeakPtr(), path, offset,
+        FileStreamWriter::OPEN_EXISTING_FILE);
+  }
+
+ private:
+  base::ScopedTempDir file_system_directory_;
+  std::unique_ptr<storage::ObfuscatedFileUtilMemoryDelegate> file_util_;
+};
+
+TEST_F(MemoryFileStreamWriterTest, Write) {
+  base::FilePath path = Path("file_a");
+  bool created;
+  EXPECT_EQ(base::File::FILE_OK, file_util()->EnsureFileExists(path, &created));
+
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 0));
+  EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "foo"));
+  EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "bar"));
+  EXPECT_TRUE(file_util()->PathExists(path));
+  EXPECT_EQ("foobar", GetFileContent(path));
+}
+
+TEST_F(MemoryFileStreamWriterTest, WriteMiddle) {
+  base::FilePath path = Path("file_a");
+  EXPECT_EQ(base::File::FILE_OK,
+            file_util()->CreateFileForTesting(path, std::string("foobar")));
+
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 2));
+  EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
+  EXPECT_TRUE(file_util()->PathExists(path));
+  EXPECT_EQ("foxxxr", GetFileContent(path));
+}
+
+TEST_F(MemoryFileStreamWriterTest, WriteNearEnd) {
+  base::FilePath path = Path("file_a");
+  EXPECT_EQ(base::File::FILE_OK,
+            file_util()->CreateFileForTesting(path, std::string("foobar")));
+
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 5));
+  EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
+  EXPECT_TRUE(file_util()->PathExists(path));
+  EXPECT_EQ("foobaxxx", GetFileContent(path));
+}
+
+TEST_F(MemoryFileStreamWriterTest, WriteEnd) {
+  base::FilePath path = Path("file_a");
+  EXPECT_EQ(base::File::FILE_OK,
+            file_util()->CreateFileForTesting(path, std::string("foobar")));
+
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 6));
+  EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
+  EXPECT_TRUE(file_util()->PathExists(path));
+  EXPECT_EQ("foobarxxx", GetFileContent(path));
+}
+
+TEST_F(MemoryFileStreamWriterTest, WriteAfterEnd) {
+  base::FilePath path = Path("file_a");
+  EXPECT_EQ(base::File::FILE_OK,
+            file_util()->CreateFileForTesting(path, std::string("foobar")));
+
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 7));
+  EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE,
+            WriteStringToWriter(writer.get(), "xxx"));
+  EXPECT_TRUE(file_util()->PathExists(path));
+  EXPECT_EQ("foobar", GetFileContent(path));
+}
+
+TEST_F(MemoryFileStreamWriterTest, WriteFailForNonexistingFile) {
+  base::FilePath path = Path("file_a");
+  ASSERT_FALSE(file_util()->PathExists(path));
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 0));
+  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, WriteStringToWriter(writer.get(), "foo"));
+  EXPECT_FALSE(file_util()->PathExists(path));
+}
+
+TEST_F(MemoryFileStreamWriterTest, CancelBeforeOperation) {
+  base::FilePath path = Path("file_a");
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 0));
+  // Cancel immediately fails when there's no in-flight operation.
+  EXPECT_EQ(net::ERR_UNEXPECTED, writer->Cancel(base::DoNothing()));
+}
+
+TEST_F(MemoryFileStreamWriterTest, CancelAfterFinishedOperation) {
+  base::FilePath path = Path("file_a");
+  bool created;
+  EXPECT_EQ(base::File::FILE_OK, file_util()->EnsureFileExists(path, &created));
+
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 0));
+  EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "foo"));
+
+  // Cancel immediately fails when there's no in-flight operation.
+  EXPECT_EQ(net::ERR_UNEXPECTED, writer->Cancel(base::DoNothing()));
+
+  // Write operation is already completed.
+  EXPECT_TRUE(file_util()->PathExists(path));
+  EXPECT_EQ("foo", GetFileContent(path));
+}
+
+TEST_F(MemoryFileStreamWriterTest, FlushBeforeWriting) {
+  base::FilePath path = Path("file_a");
+  bool created;
+  EXPECT_EQ(base::File::FILE_OK, file_util()->EnsureFileExists(path, &created));
+
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 0));
+
+  EXPECT_EQ(net::OK, writer->Flush(base::DoNothing()));
+  EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "foo"));
+  EXPECT_EQ("foo", GetFileContent(path));
+}
+
+TEST_F(MemoryFileStreamWriterTest, FlushAfterWriting) {
+  base::FilePath path = Path("file_a");
+  bool created;
+  EXPECT_EQ(base::File::FILE_OK, file_util()->EnsureFileExists(path, &created));
+
+  std::unique_ptr<FileStreamWriter> writer(CreateWriter(path, 0));
+
+  EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "foo"));
+  EXPECT_EQ(net::OK, writer->Flush(base::DoNothing()));
+  EXPECT_EQ("foo", GetFileContent(path));
+}
+
+}  // namespace storage
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
index 4bd6dd6..6112f03 100644
--- a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
+++ b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
@@ -421,6 +421,37 @@
   return buf_len;
 }
 
+int ObfuscatedFileUtilMemoryDelegate::WriteFile(const base::FilePath& path,
+                                                int64_t offset,
+                                                net::IOBuffer* buf,
+                                                int buf_len) {
+  base::Optional<DecomposedPath> dp = ParsePath(path);
+
+  if (!dp || dp->entry->type != Entry::kFile)
+    return net::ERR_FILE_NOT_FOUND;
+
+  size_t offset_u = static_cast<size_t>(offset);
+  // Fail if |offset| or |buf_len| not valid.
+  if (offset < 0 || buf_len < 0 || offset_u > dp->entry->file_content.size())
+    return net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
+
+  // Fail if result doesn't fit in a std::vector.
+  if (std::numeric_limits<size_t>::max() - offset_u <
+      static_cast<size_t>(buf_len))
+    return net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
+
+  if (offset_u == dp->entry->file_content.size()) {
+    dp->entry->file_content.insert(dp->entry->file_content.end(), buf->data(),
+                                   buf->data() + buf_len);
+  } else {
+    if (offset_u + buf_len > dp->entry->file_content.size())
+      dp->entry->file_content.resize(offset_u + buf_len);
+
+    memcpy(dp->entry->file_content.data() + offset, buf->data(), buf_len);
+  }
+  return buf_len;
+}
+
 base::File::Error ObfuscatedFileUtilMemoryDelegate::CreateFileForTesting(
     const base::FilePath& path,
     base::span<const char> content) {
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
index 5458847..fc90d21 100644
--- a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
+++ b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
@@ -81,6 +81,14 @@
                net::IOBuffer* buf,
                int buf_len);
 
+  // Writes |buf_len| bytes to the file at |path|, starting from |offset|.
+  // If successful, returns the actual number of written bytes, otherwise a
+  // net::Error value is returned.
+  int WriteFile(const base::FilePath& path,
+                int64_t offset,
+                net::IOBuffer* buf,
+                int buf_len);
+
   base::File::Error CreateFileForTesting(const base::FilePath& path,
                                          base::span<const char> content);
 
diff --git a/testing/android/reporter/BUILD.gn b/testing/android/reporter/BUILD.gn
index fac1b03..3b12b2ad 100644
--- a/testing/android/reporter/BUILD.gn
+++ b/testing/android/reporter/BUILD.gn
@@ -10,7 +10,7 @@
 
   deps = [
     "//base:base_java",
-    "//third_party/android_tools:android_test_base_java",
+    "//third_party/android_sdk:android_test_base_java",
   ]
 
   java_files = [
diff --git a/testing/buildbot/chromium.chrome.json b/testing/buildbot/chromium.chrome.json
index 945eaac..9a8f625 100644
--- a/testing/buildbot/chromium.chrome.json
+++ b/testing/buildbot/chromium.chrome.json
@@ -12,6 +12,1337 @@
       "chrome_sandbox",
       "linux_symbols",
       "symupload"
+    ],
+    "gtest_tests": [
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "accessibility_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "app_list_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "app_shell_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ash_unittests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "experiment_percentage": 100,
+        "name": "non_single_process_mash_ash_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ash_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "aura_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "base_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "blink_common_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "blink_heap_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "blink_platform_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "name": "webkit_unit_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "blink_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "boringssl_crypto_tests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "boringssl_ssl_tests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--enable-features=Mash",
+          "--disable-features=SingleProcessMash",
+          "--override-use-software-gl-for-tests",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter"
+        ],
+        "experiment_percentage": 100,
+        "name": "mash_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "hard_timeout": 1800
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash",
+          "--override-use-software-gl-for-tests"
+        ],
+        "experiment_percentage": 100,
+        "name": "non_single_process_mash_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--enable-features=VizDisplayCompositor"
+        ],
+        "experiment_percentage": 100,
+        "name": "viz_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--disable-features=WebUIPolymer2",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer1_browser_tests.filter"
+        ],
+        "experiment_percentage": 100,
+        "name": "webui_polymer1_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "browser_tests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "args": [
+          "--gtest_filter=-*UsingRealWebcam*"
+        ],
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "capture_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "cast_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "cc_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "chrome_app_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "chromedriver_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "chromeos_components_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "chromeos_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "components_browsertests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "components_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "compositor_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 6
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash",
+          "--override-use-software-gl-for-tests"
+        ],
+        "experiment_percentage": 100,
+        "name": "non_single_process_mash_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 5
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
+          "--disable-perfetto",
+          "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*"
+        ],
+        "experiment_percentage": 100,
+        "name": "nonperfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
+          "--enable-features=VizDisplayCompositor"
+        ],
+        "experiment_percentage": 100,
+        "name": "viz_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 10
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "content_unittests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "experiment_percentage": 100,
+        "name": "non_single_process_mash_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "content_unittests"
+      },
+      {
+        "args": [
+          "--enable-features=VizDisplayCompositor"
+        ],
+        "experiment_percentage": 100,
+        "name": "viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "content_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "crypto_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "dbus_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "device_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "display_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "events_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "exo_unittests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "experiment_percentage": 100,
+        "name": "non_single_process_mash_exo_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "exo_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "extensions_browsertests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "extensions_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "filesystem_service_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "gcm_unit_tests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "gfx_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "gin_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "gl_unittests_ozone"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "google_apis_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 3
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "experiment_percentage": 100,
+        "name": "non_single_process_mash_interactive_ui_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ],
+          "shards": 3
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "args": [
+          "--disable-features=WebUIPolymer2",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer1_interactive_ui_tests.filter"
+        ],
+        "experiment_percentage": 100,
+        "name": "webui_polymer1_interactive_ui_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ipc_tests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "jingle_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "keyboard_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "latency_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "leveldb_service_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "libjingle_xmpp_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "media_blink_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "media_service_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "media_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "message_center_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "midi_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "mojo_core_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "mojo_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "nacl_loader_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "native_theme_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "net_unittests"
+      },
+      {
+        "args": [
+          "--ozone-platform=headless"
+        ],
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ozone_gl_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ozone_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ozone_x11_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "pdf_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "perfetto_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ppapi_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "printing_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "remoting_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "sandbox_linux_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "service_manager_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "services_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "shell_dialogs_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "skia_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "snapshot_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "sql_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "storage_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "sync_integration_tests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ui_base_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ui_chromeos_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "ui_touch_selection_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "unit_tests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "experiment_percentage": 100,
+        "name": "non_single_process_mash_unit_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "unit_tests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "url_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "usage_time_limit_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "views_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "viz_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "wayland_client_perftests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "wm_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "pool": "chrome.tests"
+            }
+          ]
+        },
+        "test": "wtf_unittests"
+      }
     ]
   },
   "linux-google-rel": {
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 72e33ca..32b7e65c 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -157,9 +157,19 @@
       },
     },
   },
+  'chrome-swarming-pool': {
+    'swarming': {
+      'dimensions': {
+        'pool': 'chrome.tests',
+      },
+    },
+  },
   'code-coverage': {
     'isolate_coverage_data': True,
   },
+  'experimental': {
+    'experiment_percentage': 100,
+  },
   'flounder': {
     # Nexus 9
     'swarming': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 2024391..e712278 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -630,6 +630,13 @@
           'linux_symbols',
           'symupload'
         ],
+        'mixins': [
+          'chrome-swarming-pool',
+          'experimental',
+        ],
+        'test_suites': {
+          'gtest_tests': 'linux_chromeos_gtests',
+        },
       },
       'linux-google-rel': {
         'additional_compile_targets': [
diff --git a/testing/libfuzzer/fuzzers/hash_fuzzer.cc b/testing/libfuzzer/fuzzers/hash_fuzzer.cc
index eb84938..cf7217c 100644
--- a/testing/libfuzzer/fuzzers/hash_fuzzer.cc
+++ b/testing/libfuzzer/fuzzers/hash_fuzzer.cc
@@ -5,7 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 
 // Entry point for LibFuzzer.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/testing/libfuzzer/fuzzers/sha1_fuzzer.cc b/testing/libfuzzer/fuzzers/sha1_fuzzer.cc
index 26224331..4dfc52e4 100644
--- a/testing/libfuzzer/fuzzers/sha1_fuzzer.cc
+++ b/testing/libfuzzer/fuzzers/sha1_fuzzer.cc
@@ -5,7 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 
 // Entry point for LibFuzzer.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index bae24eac..b74da9f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5260,6 +5260,25 @@
             ]
         }
     ],
+    "UseAlternateFakeboxOnNtp": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "UseAlternateFakeboxOnNtp",
+                    "enable_features": [
+                        "FakeboxSearchIconOnNtp",
+                        "UseAlternateFakeboxOnNtp"
+                    ]
+                }
+            ]
+        }
+    ],
     "UseGoogleLocalNtp": [
         {
             "platforms": [
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn
index 6e0276f5..2b89de9 100644
--- a/third_party/android_deps/BUILD.gn
+++ b/third_party/android_deps/BUILD.gn
@@ -197,9 +197,9 @@
     ":androidx_test_runner_java",
   ]
   deps += [
-    "//third_party/android_tools:android_test_base_java",
-    "//third_party/android_tools:android_test_mock_java",
-    "//third_party/android_tools:android_test_runner_java",
+    "//third_party/android_sdk:android_test_base_java",
+    "//third_party/android_sdk:android_test_mock_java",
+    "//third_party/android_sdk:android_test_runner_java",
   ]
 }
 
diff --git a/build/secondary/third_party/android_platform/development/scripts/BUILD.gn b/third_party/android_platform/development/scripts/BUILD.gn
similarity index 68%
rename from build/secondary/third_party/android_platform/development/scripts/BUILD.gn
rename to third_party/android_platform/development/scripts/BUILD.gn
index 2c9758e..e302a27 100644
--- a/build/secondary/third_party/android_platform/development/scripts/BUILD.gn
+++ b/third_party/android_platform/development/scripts/BUILD.gn
@@ -6,9 +6,9 @@
 import("//build/config/python.gni")
 
 python_library("stack_py") {
-  pydeps_file = "//build/secondary/third_party/android_platform/development/scripts/stack.pydeps"
+  pydeps_file = "stack.pydeps"
   data = [
-    "//third_party/android_platform/development/scripts/stack",
+    "stack",
     "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer",
   ]
 }
diff --git a/build/secondary/third_party/android_platform/development/scripts/stack.pydeps b/third_party/android_platform/development/scripts/stack.pydeps
similarity index 84%
rename from build/secondary/third_party/android_platform/development/scripts/stack.pydeps
rename to third_party/android_platform/development/scripts/stack.pydeps
index a8972fd..b188ee0 100644
--- a/build/secondary/third_party/android_platform/development/scripts/stack.pydeps
+++ b/third_party/android_platform/development/scripts/stack.pydeps
@@ -1,5 +1,5 @@
 # Generated by running:
-#   build/print_python_deps.py --root third_party/android_platform/development/scripts --output build/secondary/third_party/android_platform/development/scripts/stack.pydeps third_party/android_platform/development/scripts/stack.py
+#   build/print_python_deps.py --root third_party/android_platform/development/scripts --output third_party/android_platform/development/scripts/stack.pydeps third_party/android_platform/development/scripts/stack.py
 ../../../../build/android/pylib/__init__.py
 ../../../../build/android/pylib/constants/__init__.py
 ../../../../build/android/pylib/constants/host_paths.py
diff --git a/build/secondary/third_party/android_tools/AndroidManifest.xml.jinja2 b/third_party/android_sdk/AndroidManifest.xml.jinja2
similarity index 100%
rename from build/secondary/third_party/android_tools/AndroidManifest.xml.jinja2
rename to third_party/android_sdk/AndroidManifest.xml.jinja2
diff --git a/third_party/android_sdk/BUILD.gn b/third_party/android_sdk/BUILD.gn
new file mode 100644
index 0000000..e70d925f
--- /dev/null
+++ b/third_party/android_sdk/BUILD.gn
@@ -0,0 +1,107 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+config("cpu_features_include") {
+  include_dirs = [ "$android_ndk_root/sources/android/cpufeatures" ]
+}
+
+config("cpu_features_warnings") {
+  if (is_clang) {
+    # cpu-features.c has few unused functions on x86 b/26403333
+    cflags = [ "-Wno-unused-function" ]
+  }
+}
+
+source_set("cpu_features") {
+  sources = [
+    "$android_ndk_root/sources/android/cpufeatures/cpu-features.c",
+  ]
+  public_configs = [ ":cpu_features_include" ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+
+    # Must be after no_chromium_code for warning flags to be ordered correctly.
+    ":cpu_features_warnings",
+  ]
+}
+
+if (enable_java_templates) {
+  android_system_java_prebuilt("public_framework_system_java") {
+    jar_path = "//third_party/android_system_sdk/android_system.jar"
+  }
+
+  android_system_java_prebuilt("android_sdk_java") {
+    jar_path = android_sdk_jar
+  }
+
+  template("android_test_jar_with_manifest") {
+    _manifest_output_path = "$target_gen_dir/$target_name/AndroidManifest.xml"
+    _manifest_target = "${target_name}__manifest"
+    jinja_template(_manifest_target) {
+      testonly = true
+      input = "//third_party/android_sdk/AndroidManifest.xml.jinja2"
+      output = _manifest_output_path
+      variables = [ "library_name=${invoker.library_name}" ]
+    }
+
+    _resources_target = "${target_name}__resources"
+    android_resources(_resources_target) {
+      testonly = true
+      resource_dirs = []
+      android_manifest = _manifest_output_path
+      android_manifest_dep = ":$_manifest_target"
+    }
+
+    java_group(target_name) {
+      testonly = true
+      deps = [
+        ":$_resources_target",
+      ]
+      input_jars_paths = [ "${android_sdk}/optional/${invoker.jar_name}" ]
+    }
+  }
+
+  # The android test libraries below are part of the main SDK jar
+  # and are linked by default on O and below. Starting in P, they
+  # exist in their own libraries that are present on device and are
+  # available to be linked against but aren't linked by default.
+  android_test_jar_with_manifest("android_test_base_java") {
+    library_name = "base"
+    jar_name = "android.test.base.jar"
+  }
+  android_test_jar_with_manifest("android_test_mock_java") {
+    library_name = "mock"
+    jar_name = "android.test.mock.jar"
+  }
+  android_test_jar_with_manifest("android_test_runner_java") {
+    library_name = "runner"
+    jar_name = "android.test.runner.jar"
+  }
+
+  android_library("android_support_chromium_java") {
+    testonly = true
+    java_files = [ "//third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java" ]
+  }
+  android_java_prebuilt("android_gcm_java") {
+    jar_path = "//third_party/android_sdk/public/extras/google/gcm/gcm-client/dist/gcm.jar"
+  }
+  android_java_prebuilt("emma_device_java") {
+    jar_path = "//third_party/android_sdk/public/tools/lib/emma_device.jar"
+    include_java_resources = true
+  }
+
+  # The current version of //third_party/byte_buddy relies on an older
+  # version of dx.
+  java_prebuilt("dx_25_0_2_java") {
+    supports_android = true
+    requires_android = true
+    no_build_hooks = true
+    testonly = true
+    jar_path = "//third_party/android_sdk/public/build-tools/25.0.2/lib/dx.jar"
+  }
+}
diff --git a/third_party/android_support_test_runner/BUILD.gn b/third_party/android_support_test_runner/BUILD.gn
index 71ff270..66bb1d6 100644
--- a/third_party/android_support_test_runner/BUILD.gn
+++ b/third_party/android_support_test_runner/BUILD.gn
@@ -9,7 +9,7 @@
   jar_path = "lib/runner-release-no-dep.jar"
   deps = [
     ":exposed_instrumentation_api_publish_java",
-    "//third_party/android_tools:android_test_base_java",
+    "//third_party/android_sdk:android_test_base_java",
     "//third_party/guava:guava_android_java",
     "//third_party/junit",
   ]
diff --git a/third_party/blink/common/feature_policy/feature_policy.cc b/third_party/blink/common/feature_policy/feature_policy.cc
index f5c1d0e..a22cc83 100644
--- a/third_party/blink/common/feature_policy/feature_policy.cc
+++ b/third_party/blink/common/feature_policy/feature_policy.cc
@@ -387,9 +387,6 @@
        {mojom::FeaturePolicyFeature::kLazyLoad,
         FeatureDefaultValue(FeaturePolicy::FeatureDefault::EnableForAll,
                             mojom::PolicyValueType::kBool)},
-       {mojom::FeaturePolicyFeature::kLegacyImageFormats,
-        FeatureDefaultValue(FeaturePolicy::FeatureDefault::EnableForAll,
-                            mojom::PolicyValueType::kBool)},
        {mojom::FeaturePolicyFeature::kMagnetometer,
         FeatureDefaultValue(FeaturePolicy::FeatureDefault::EnableForSelf,
                             mojom::PolicyValueType::kBool)},
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index e8bc2d53..e1b9c29a 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -449,7 +449,6 @@
     "web/web_frame_serializer.h",
     "web/web_frame_serializer_client.h",
     "web/web_frame_widget.h",
-    "web/web_global_object_reuse_policy.h",
     "web/web_heap.h",
     "web/web_history_commit_type.h",
     "web/web_history_item.h",
@@ -463,6 +462,7 @@
     "web/web_language_detection_details.h",
     "web/web_local_frame.h",
     "web/web_local_frame_client.h",
+    "web/web_manifest_parser.h",
     "web/web_meaningful_layout.h",
     "web/web_media_player_action.h",
     "web/web_memory_statistics.h",
diff --git a/third_party/blink/public/common/manifest/manifest.h b/third_party/blink/public/common/manifest/manifest.h
index 2203a9b4..f62b327 100644
--- a/third_party/blink/public/common/manifest/manifest.h
+++ b/third_party/blink/public/common/manifest/manifest.h
@@ -199,6 +199,13 @@
   GURL scope;
 };
 
+struct BLINK_COMMON_EXPORT ManifestError {
+  std::string message;
+  bool critical;
+  uint32_t line;
+  uint32_t column;
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MANIFEST_MANIFEST_H_
diff --git a/third_party/blink/public/mojom/appcache/appcache.mojom b/third_party/blink/public/mojom/appcache/appcache.mojom
index 33c3e9e..d900153f 100644
--- a/third_party/blink/public/mojom/appcache/appcache.mojom
+++ b/third_party/blink/public/mojom/appcache/appcache.mojom
@@ -33,9 +33,15 @@
   APPCACHE_UNKNOWN_ERROR,
 };
 
+// Per-resource information displayed in DevTools.
 struct AppCacheResourceInfo {
   url.mojom.Url url;
-  int64 size;
+  // Disk space consumed by this resource.
+  int64 response_size;
+  // Padding added when the Quota API counts this resource.
+  //
+  // Non-zero only for opaque responses.
+  int64 padding_size;
   bool is_master;
   bool is_manifest;
   bool is_intercept;
diff --git a/third_party/blink/public/mojom/appcache/appcache_info.mojom b/third_party/blink/public/mojom/appcache/appcache_info.mojom
index 8f17fd2..bd231522 100644
--- a/third_party/blink/public/mojom/appcache/appcache_info.mojom
+++ b/third_party/blink/public/mojom/appcache/appcache_info.mojom
@@ -21,6 +21,7 @@
   APPCACHE_STATUS_OBSOLETE = 5,
 };
 
+// Cache-wide information displayed in DevTools.
 struct AppCacheInfo {
   url.mojom.Url manifest_url;
   mojo_base.mojom.Time creation_time;
@@ -29,6 +30,9 @@
   int64 cache_id;
   int64 group_id;
   AppCacheStatus status;
-  int64 size;
+  // Sums up the sizes of all the responses in this cache.
+  int64 response_sizes;
+  // Sums up the padding sizes for all opaque responses in the cache.
+  int64 padding_sizes;
   bool is_complete;
 };
diff --git a/third_party/blink/public/mojom/feature_policy/feature_policy.mojom b/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
index ca35c35..b5aa3fb 100644
--- a/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
+++ b/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
@@ -80,8 +80,6 @@
   // Controls the layout size of intrinsically sized images and videos. When
   // disabled, default size (300 x 150) is used to prevent relayout.
   kUnsizedMedia = 21,
-  // Controls which image formats are allowed to be used in the document.
-  kLegacyImageFormats = 22,
   // When disallowed, restricts source image size to be no more 2x larger than
   // the image's containing block.
   kOversizedImages = 25,
@@ -127,6 +125,7 @@
   kUnoptimizedLossyImages = 45,
 
   // Don't change assigned numbers of any item, and don't reuse removed slots.
+  // Add new features at the end of the enum.
   // Also, run update_feature_policy_enum.py in
   // chromium/src/tools/metrics/histograms/ to update the UMA mapping.
 };
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_container.mojom b/third_party/blink/public/mojom/service_worker/service_worker_container.mojom
index 2f176e2..719910d 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker_container.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker_container.mojom
@@ -106,10 +106,6 @@
   // Informs the host that the context is execution ready.
   // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-execution-ready-flag
   OnExecutionReady();
-
-  // Used only in case of a document to inform the host that the renderer-side
-  // provider has been created successfully.
-  OnProviderCreated();
 };
 
 // ServiceWorkerContainer is an interface implemented by the renderer process.
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index aa2a043..9e3f2cd 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -1451,7 +1451,6 @@
   kCrossOriginPropertyAccess = 1977,
   kCrossOriginPropertyAccessFromOpener = 1978,
   kCredentialManagerCreate = 1979,
-  kWebDatabaseCreateDropFTS3Table = 1980,
   kFieldEditInSecureContext = 1981,
   kFieldEditInNonSecureContext = 1982,
   kCredentialManagerGetMediationRequired = 1984,
diff --git a/third_party/blink/public/platform/task_type.h b/third_party/blink/public/platform/task_type.h
index 9771124..32333c1 100644
--- a/third_party/blink/public/platform/task_type.h
+++ b/third_party/blink/public/platform/task_type.h
@@ -14,7 +14,7 @@
 //
 // When a new task type is created, use kCount value as a new value,
 // the tools/metrics/histograms/enums.xml shall also be updated.
-enum class TaskType : unsigned {
+enum class TaskType : unsigned char {
   ///////////////////////////////////////
   // Speced tasks should use one of the following task types
   ///////////////////////////////////////
diff --git a/third_party/blink/public/platform/web_application_cache_host.h b/third_party/blink/public/platform/web_application_cache_host.h
index 5576c57..e9032c1 100644
--- a/third_party/blink/public/platform/web_application_cache_host.h
+++ b/third_party/blink/public/platform/web_application_cache_host.h
@@ -83,19 +83,32 @@
     WebURL manifest_url;  // Empty if there is no associated cache.
     double creation_time;
     double update_time;
-    int64_t total_size;
-    CacheInfo() : creation_time(0), update_time(0), total_size(0) {}
+    // Sums up the sizes of all the responses in this cache.
+    int64_t response_sizes;
+    // Sums up the padding sizes for all opaque responses in the cache.
+    int64_t padding_sizes;
+    CacheInfo()
+        : creation_time(0),
+          update_time(0),
+          response_sizes(0),
+          padding_sizes(0) {}
   };
   struct ResourceInfo {
     WebURL url;
-    int64_t size;
+    // Disk space consumed by this resource.
+    int64_t response_size;
+    // Padding added when the Quota API counts this resource.
+    //
+    // Non-zero only for opaque responses.
+    int64_t padding_size;
     bool is_master;
     bool is_manifest;
     bool is_explicit;
     bool is_foreign;
     bool is_fallback;
     ResourceInfo()
-        : size(0),
+        : response_size(0),
+          padding_size(0),
           is_master(false),
           is_manifest(false),
           is_explicit(false),
diff --git a/third_party/blink/public/platform/web_layer_tree_view.h b/third_party/blink/public/platform/web_layer_tree_view.h
index 762eca8a..aa78e4a 100644
--- a/third_party/blink/public/platform/web_layer_tree_view.h
+++ b/third_party/blink/public/platform/web_layer_tree_view.h
@@ -100,11 +100,6 @@
   virtual void CompositeAndReadbackAsync(
       base::OnceCallback<void(const SkBitmap&)> callback) {}
 
-  // Synchronously performs the complete set of document lifecycle phases,
-  // including updates to the compositor state, optionally including
-  // rasterization.
-  virtual void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) {}
-
   // Prevents any updates to the input for the layer tree, and the layer tree
   // itself, and the layer tree from becoming visible.
   virtual std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
diff --git a/third_party/blink/public/web/web_document.h b/third_party/blink/public/web/web_document.h
index 79cfdabf..fe2179d6 100644
--- a/third_party/blink/public/web/web_document.h
+++ b/third_party/blink/public/web/web_document.h
@@ -74,7 +74,7 @@
   BLINK_EXPORT WebString Encoding() const;
   BLINK_EXPORT WebString ContentLanguage() const;
   BLINK_EXPORT WebString GetReferrer() const;
-  BLINK_EXPORT SkColor ThemeColor() const;
+  BLINK_EXPORT base::Optional<SkColor> ThemeColor() const;
   // The url of the OpenSearch Desription Document (if any).
   BLINK_EXPORT WebURL OpenSearchDescriptionURL() const;
 
diff --git a/third_party/blink/public/web/web_global_object_reuse_policy.h b/third_party/blink/public/web/web_global_object_reuse_policy.h
deleted file mode 100644
index 83336766..0000000
--- a/third_party/blink/public/web/web_global_object_reuse_policy.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_GLOBAL_OBJECT_REUSE_POLICY_H_
-#define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_GLOBAL_OBJECT_REUSE_POLICY_H_
-
-namespace blink {
-
-// Indicates whether the global object (i.e. Window instance) associated with
-// the previous document in a browsing context was replaced or reused for the
-// new Document corresponding to the just-committed navigation; effective in the
-// main world and all isolated worlds. WindowProxies are not affected.
-//
-// TODO(dcheng): Investigate removing the need for this by moving the
-// InterfaceProvider plumbing from DidCommitProvisionalLoad to
-// RenderFrameImpl::CommitNavigation.
-enum class WebGlobalObjectReusePolicy { kCreateNew, kUseExisting };
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/public/web/web_manifest_parser.h b/third_party/blink/public/web/web_manifest_parser.h
new file mode 100644
index 0000000..dbfa43b4
--- /dev/null
+++ b/third_party/blink/public/web/web_manifest_parser.h
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_MANIFEST_PARSER_H_
+#define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_MANIFEST_PARSER_H_
+
+#include "base/strings/string_piece.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_vector.h"
+
+namespace blink {
+
+struct Manifest;
+struct ManifestError;
+class WebURL;
+
+class WebManifestParser {
+ public:
+  // Updates only Manifest if parsing did not fail.
+  BLINK_EXPORT static bool ParseManifest(const base::StringPiece&,
+                                         const WebURL&,
+                                         const WebURL&,
+                                         Manifest*,
+                                         WebVector<ManifestError>*);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_MANIFEST_PARSER_H_
diff --git a/third_party/blink/public/web/web_page_popup.h b/third_party/blink/public/web/web_page_popup.h
index de177560..2131be0 100644
--- a/third_party/blink/public/web/web_page_popup.h
+++ b/third_party/blink/public/web/web_page_popup.h
@@ -53,6 +53,10 @@
   // be released when the popup is closed via Close().
   BLINK_EXPORT static WebPagePopup* Create(WebPagePopupClient*);
   virtual WebPoint PositionRelativeToOwner() = 0;
+
+  // Web tests require access to the client for a WebPagePopup in order
+  // to synchronously composite.
+  virtual WebPagePopupClient* GetClientForTesting() const = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/web/web_widget.h b/third_party/blink/public/web/web_widget.h
index b0f66af..8615579 100644
--- a/third_party/blink/public/web/web_widget.h
+++ b/third_party/blink/public/web/web_widget.h
@@ -143,11 +143,6 @@
   virtual void UpdateLifecycle(LifecycleUpdate requested_update,
                                LifecycleUpdateReason reason) {}
 
-  // Synchronously performs the complete set of document lifecycle phases,
-  // including updates to the compositor state, optionally including
-  // rasterization.
-  virtual void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) {}
-
   // Called to paint the rectangular region within the WebWidget
   // onto the specified canvas at (view_port.x, view_port.y).
   //
diff --git a/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc b/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc
index 58974b4..d0e9fe4 100644
--- a/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc
+++ b/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc
@@ -5,10 +5,12 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_native.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_wrapper.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "v8/include/v8.h"
 
 namespace blink {
@@ -30,13 +32,6 @@
   ScriptValue strategy = ScriptValue(ScriptState::Current(info.GetIsolate()),
                                      v8::Undefined(info.GetIsolate()));
   int num_args = info.Length();
-  // TODO(ricea): Switch implementation based on StreamsNative feature flag
-  // here.
-  auto* impl = MakeGarbageCollected<ReadableStreamWrapper>();
-  v8::Local<v8::Object> wrapper = info.Holder();
-  wrapper = impl->AssociateWithWrapper(
-      info.GetIsolate(), V8ReadableStream::GetWrapperTypeInfo(), wrapper);
-
   if (num_args >= 1) {
     underlying_source =
         ScriptValue(ScriptState::Current(info.GetIsolate()), info[0]);
@@ -44,9 +39,24 @@
   if (num_args >= 2)
     strategy = ScriptValue(ScriptState::Current(info.GetIsolate()), info[1]);
 
-  impl->Init(script_state, underlying_source, strategy, exception_state);
-  if (exception_state.HadException()) {
-    return;
+  v8::Local<v8::Object> wrapper = info.Holder();
+  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
+    auto* impl = MakeGarbageCollected<ReadableStreamNative>(
+        script_state, underlying_source, strategy, false, exception_state);
+    if (exception_state.HadException()) {
+      return;
+    }
+    wrapper = impl->AssociateWithWrapper(
+        info.GetIsolate(), V8ReadableStream::GetWrapperTypeInfo(), wrapper);
+  } else {
+    auto* impl = MakeGarbageCollected<ReadableStreamWrapper>();
+    wrapper = impl->AssociateWithWrapper(
+        info.GetIsolate(), V8ReadableStream::GetWrapperTypeInfo(), wrapper);
+
+    impl->Init(script_state, underlying_source, strategy, exception_state);
+    if (exception_state.HadException()) {
+      return;
+    }
   }
   V8SetReturnValue(info, wrapper);
 }
diff --git a/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc b/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
index 07591f1..5db5765 100644
--- a/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
+++ b/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
@@ -168,7 +168,7 @@
 
   const bool apply_policy = RuntimeEnabledFeatures::IsolatedWorldCSPEnabled();
 
-  ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+  auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
 
   IsolatedWorldCSPDelegate* delegate =
       MakeGarbageCollected<IsolatedWorldCSPDelegate>(
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
index 4c6ec62..d506787 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
@@ -261,7 +261,7 @@
       uint32_t length;
       if (!ReadUint32(&length))
         return nullptr;
-      FileList* file_list = FileList::Create();
+      auto* file_list = MakeGarbageCollected<FileList>();
       for (uint32_t i = 0; i < length; i++) {
         if (File* file = ReadFile())
           file_list->Append(file);
@@ -276,7 +276,7 @@
       uint32_t length;
       if (!ReadUint32(&length))
         return nullptr;
-      FileList* file_list = FileList::Create();
+      auto* file_list = MakeGarbageCollected<FileList>();
       for (uint32_t i = 0; i < length; i++) {
         if (File* file = ReadFileIndex())
           file_list->Append(file);
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
index ed716cf..e071acf 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -1680,7 +1680,7 @@
 
 TEST(V8ScriptValueSerializerTest, RoundTripFileList) {
   V8TestingScope scope;
-  FileList* file_list = FileList::Create();
+  auto* file_list = MakeGarbageCollected<FileList>();
   file_list->Append(File::Create("/native/path"));
   file_list->Append(File::Create("/native/path2"));
   v8::Local<v8::Value> wrapper = ToV8(file_list, scope.GetScriptState());
@@ -1741,7 +1741,7 @@
 
 TEST(V8ScriptValueSerializerTest, RoundTripFileListIndex) {
   V8TestingScope scope;
-  FileList* file_list = FileList::Create();
+  auto* file_list = MakeGarbageCollected<FileList>();
   file_list->Append(File::Create("/native/path"));
   file_list->Append(File::Create("/native/path2"));
   v8::Local<v8::Value> wrapper = ToV8(file_list, scope.GetScriptState());
diff --git a/third_party/blink/renderer/core/clipboard/data_transfer.cc b/third_party/blink/renderer/core/clipboard/data_transfer.cc
index 1a1bcc5..4e7038d 100644
--- a/third_party/blink/renderer/core/clipboard/data_transfer.cc
+++ b/third_party/blink/renderer/core/clipboard/data_transfer.cc
@@ -320,7 +320,7 @@
 }
 
 FileList* DataTransfer::files() const {
-  FileList* files = FileList::Create();
+  auto* files = MakeGarbageCollected<FileList>();
   if (!CanReadData())
     return files;
 
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc b/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc
index d5df4b9..78ebb25 100644
--- a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc
@@ -182,25 +182,28 @@
 
   DCHECK(!!resolved_data == !!resolved_value);
 
-  // If so enabled by options, and the resolved_data isn't absolutized already
-  // (which is the case when resolved_data was inherited from the parent style),
-  // perform absolutization now.
-  if (options.absolutize) {
-    if (resolved_value && !resolved_data->IsAbsolutized()) {
-      resolved_value = &StyleBuilderConverter::ConvertRegisteredPropertyValue(
-          state_, *resolved_value);
-      resolved_data =
-          StyleBuilderConverter::ConvertRegisteredPropertyVariableData(
-              *resolved_value, resolved_data->IsAnimationTainted());
-      DCHECK(resolved_data->IsAbsolutized());
-    }
-    if (resolved_data != variable_data)
-      SetVariable(name, registration, resolved_data);
+  // Registered custom properties substitute as token sequences equivalent to
+  // their computed values. CSSVariableData instances which represent such token
+  // sequences are called "absolutized".
+  if (resolved_value && !resolved_data->IsAbsolutized()) {
+    resolved_value = &StyleBuilderConverter::ConvertRegisteredPropertyValue(
+        state_, *resolved_value);
+    resolved_data =
+        StyleBuilderConverter::ConvertRegisteredPropertyVariableData(
+            *resolved_value, resolved_data->IsAnimationTainted());
+    DCHECK(resolved_data->IsAbsolutized());
   }
 
-  // Even if options.absolutize=false, we store the resolved_value if we
-  // parsed it. This is required to calculate the animations update before
-  // the absolutization pass.
+  // If options.absolutize=false, we want to keep the original (non-absolute)
+  // token sequence to retain any var()-references. This makes it possible to
+  // resolve the var()-reference again, using a different (e.g. animated) value.
+  if (options.absolutize && resolved_data != variable_data)
+    SetVariable(name, registration, resolved_data);
+
+  // The options.absolutize flag does not apply to the computed value, only
+  // to the tokens used for substitution. Hence, store the computed value on
+  // ComputedStyle, regardless of the flag. This is needed to correctly
+  // calculate animations.
   if (value != resolved_value)
     SetRegisteredVariable(name, *registration, resolved_value);
 
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.h b/third_party/blink/renderer/core/css/resolver/css_variable_resolver.h
index 853aa01..cd3bbf3 100644
--- a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/css_variable_resolver.h
@@ -101,11 +101,11 @@
     // properties themselves (e.g. color). When a high-priority property refers
     // to a custom property with an (inner) var()-reference, that custom
     // property is resolved "on the fly" with absolutize=false. This means that
-    // 1) a non- absolute value is returned, and 2) the resolved token stream
-    // for that custom property is not stored on the ComputedStyle. Storing the
-    // token stream on the ComputedStyle can only be done with absolutize=true,
-    // otherwise can permanently end up with the wrong token stream if one
-    // unregistered property reference a registered property, for instance.
+    // the equivalent token stream for the computed value of that custom
+    // property is not stored on ComputedStyle. Storing the token stream on
+    // ComputedStyle can only be done with absolutize=true, otherwise we can
+    // permanently end up with the wrong token stream if an unregistered
+    // property references a registered property, for instance.
     bool absolutize = false;
   };
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 8583d23..21dfccaf 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -114,6 +114,12 @@
         state.AnimationUpdate());
 }
 
+bool HasAnimationsOrTransitions(const StyleResolverState& state,
+                                const Element* animating_element) {
+  return state.Style()->Animations() || state.Style()->Transitions() ||
+         (animating_element && animating_element->HasAnimations());
+}
+
 }  // namespace
 
 using namespace html_names;
@@ -808,8 +814,7 @@
     if (state.HasDirAutoAttribute())
       state.Style()->SetSelfOrAncestorHasDirAutoAttribute(true);
 
-    ApplyMatchedPropertiesAndCustomPropertyAnimations(
-        state, collector.MatchedResult(), element);
+    ApplyMatchedProperties(state, collector.MatchedResult(), element);
     ApplyCallbackSelectors(state);
 
     // Cache our original display.
@@ -921,8 +926,7 @@
     if (!collector.MatchedResult().HasMatchedProperties())
       return false;
 
-    ApplyMatchedPropertiesAndCustomPropertyAnimations(
-        state, collector.MatchedResult(), pseudo_element);
+    ApplyMatchedProperties(state, collector.MatchedResult(), pseudo_element);
     ApplyCallbackSelectors(state);
 
     // Cache our original display.
@@ -1635,33 +1639,6 @@
   was_viewport_resized_ = false;
 }
 
-void StyleResolver::ApplyMatchedPropertiesAndCustomPropertyAnimations(
-    StyleResolverState& state,
-    const MatchResult& match_result,
-    const Element* animating_element) {
-  CacheSuccess cache_success = ApplyMatchedCache(state, match_result);
-  NeedsApplyPass needs_apply_pass;
-  if (!cache_success.IsFullCacheHit()) {
-    ApplyCustomProperties(state, match_result, kExcludeAnimations,
-                          cache_success, needs_apply_pass);
-    ApplyMatchedAnimationProperties(state, match_result, cache_success,
-                                    needs_apply_pass);
-  }
-  if (state.Style()->Animations() || state.Style()->Transitions() ||
-      (animating_element && animating_element->HasAnimations())) {
-    CalculateAnimationUpdate(state, animating_element);
-    if (state.IsAnimatingCustomProperties()) {
-      cache_success.SetFailed();
-      ApplyCustomProperties(state, match_result, kIncludeAnimations,
-                            cache_success, needs_apply_pass);
-    }
-  }
-  if (!cache_success.IsFullCacheHit()) {
-    ApplyMatchedStandardProperties(state, match_result, cache_success,
-                                   needs_apply_pass);
-  }
-}
-
 StyleResolver::CacheSuccess StyleResolver::ApplyMatchedCache(
     StyleResolverState& state,
     const MatchResult& match_result) {
@@ -1721,7 +1698,6 @@
 
 void StyleResolver::ApplyCustomProperties(StyleResolverState& state,
                                           const MatchResult& match_result,
-                                          ApplyAnimations apply_animations,
                                           const CacheSuccess& cache_success,
                                           NeedsApplyPass& needs_apply_pass) {
   DCHECK(!cache_success.IsFullCacheHit());
@@ -1741,13 +1717,6 @@
   ApplyMatchedProperties<kResolveVariables, kCheckNeedsApplyPass>(
       state, match_result.UserRules(), true, apply_inherited_only,
       needs_apply_pass);
-
-  CSSVariableResolver(state).ComputeRegisteredVariables();
-
-  if (apply_animations == kIncludeAnimations &&
-      state.IsAnimatingCustomProperties()) {
-    CSSVariableAnimator(state).ApplyAll();
-  }
 }
 
 void StyleResolver::ApplyMatchedAnimationProperties(
@@ -1794,17 +1763,12 @@
   }
 }
 
-void StyleResolver::ApplyMatchedStandardProperties(
+void StyleResolver::ApplyMatchedHighPriorityProperties(
     StyleResolverState& state,
     const MatchResult& match_result,
     const CacheSuccess& cache_success,
+    bool& apply_inherited_only,
     NeedsApplyPass& needs_apply_pass) {
-  INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
-                                matched_property_apply, 1);
-
-  DCHECK(!cache_success.IsFullCacheHit());
-  bool apply_inherited_only = cache_success.ShouldApplyInheritedOnly();
-
   // Now we have all of the matched rules in the appropriate order. Walk the
   // rules and apply high-priority properties first, i.e., those properties that
   // other properties depend on.  The order is (1) high-priority not important,
@@ -1855,6 +1819,52 @@
       cache_success.cached_matched_properties->computed_style
               ->GetFontDescription() != state.Style()->GetFontDescription())
     apply_inherited_only = false;
+}
+
+void StyleResolver::ApplyMatchedProperties(StyleResolverState& state,
+                                           const MatchResult& match_result,
+                                           const Element* animating_element) {
+  INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
+                                matched_property_apply, 1);
+
+  CacheSuccess cache_success = ApplyMatchedCache(state, match_result);
+  bool apply_inherited_only = cache_success.ShouldApplyInheritedOnly();
+  NeedsApplyPass needs_apply_pass;
+
+  if (!cache_success.IsFullCacheHit()) {
+    ApplyCustomProperties(state, match_result, cache_success, needs_apply_pass);
+    ApplyMatchedAnimationProperties(state, match_result, cache_success,
+                                    needs_apply_pass);
+    ApplyMatchedHighPriorityProperties(state, match_result, cache_success,
+                                       apply_inherited_only, needs_apply_pass);
+  }
+
+  if (HasAnimationsOrTransitions(state, animating_element)) {
+    // Calculate pre-animated computed values for all registered properties.
+    // This is needed to calculate the animation update.
+    CSSVariableResolver(state).ComputeRegisteredVariables();
+
+    // Animation update calculation must happen after application of high
+    // priority properties, otherwise we can't resolve em' units, making it
+    // impossible to know if we should transition in some cases.
+    CalculateAnimationUpdate(state, animating_element);
+
+    if (state.IsAnimatingCustomProperties()) {
+      cache_success.SetFailed();
+
+      CSSVariableAnimator(state).ApplyAll();
+
+      // Apply high priority properties again to re-resolve var() references
+      // to (now-)animated custom properties.
+      // TODO(andruud): Avoid this with https://crbug.com/947004
+      ApplyMatchedHighPriorityProperties(state, match_result, cache_success,
+                                         apply_inherited_only,
+                                         needs_apply_pass);
+    }
+  }
+
+  if (cache_success.IsFullCacheHit())
+    return;
 
   CSSVariableResolver(state).ResolveVariableDefinitions();
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h
index 52989e06..7fc9504 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -219,27 +219,27 @@
     kUpdateNeedsApplyPass = true,
   };
 
-  void ApplyMatchedPropertiesAndCustomPropertyAnimations(
-      StyleResolverState&,
-      const MatchResult&,
-      const Element* animating_element);
   CacheSuccess ApplyMatchedCache(StyleResolverState&, const MatchResult&);
-  enum ApplyAnimations { kExcludeAnimations, kIncludeAnimations };
   void ApplyCustomProperties(StyleResolverState&,
                              const MatchResult&,
-                             ApplyAnimations,
                              const CacheSuccess&,
                              NeedsApplyPass&);
   void ApplyMatchedAnimationProperties(StyleResolverState&,
                                        const MatchResult&,
                                        const CacheSuccess&,
                                        NeedsApplyPass&);
-  void ApplyMatchedStandardProperties(StyleResolverState&,
-                                      const MatchResult&,
-                                      const CacheSuccess&,
-                                      NeedsApplyPass&);
+  void ApplyMatchedHighPriorityProperties(StyleResolverState&,
+                                          const MatchResult&,
+                                          const CacheSuccess&,
+                                          bool& apply_inherited_only,
+                                          NeedsApplyPass&);
+  void ApplyMatchedProperties(StyleResolverState&,
+                              const MatchResult&,
+                              const Element* animating_element);
+
   void CalculateAnimationUpdate(StyleResolverState&,
                                 const Element* animating_element);
+
   bool ApplyAnimatedStandardProperties(StyleResolverState&, const Element*);
 
   void ApplyCallbackSelectors(StyleResolverState&);
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 82fde0c..eff4391 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -698,9 +698,6 @@
       logged_field_edit_(false),
       secure_context_state_(SecureContextState::kUnknown),
       ukm_source_id_(ukm::UkmRecorder::GetNewSourceID()),
-#if DCHECK_IS_ON()
-      slot_assignment_recalc_forbidden_recursion_depth_(0),
-#endif
       needs_to_record_ukm_outlive_time_(false),
       viewport_data_(MakeGarbageCollected<ViewportData>(*this)),
       agent_cluster_id_(base::UnguessableToken::Create()),
@@ -6162,19 +6159,19 @@
   return icon_urls;
 }
 
-Color Document::ThemeColor() const {
+base::Optional<Color> Document::ThemeColor() const {
   auto* root_element = documentElement();
   if (!root_element)
-    return Color();
+    return base::nullopt;
   for (HTMLMetaElement& meta_element :
        Traversal<HTMLMetaElement>::DescendantsOf(*root_element)) {
-    Color color = Color::kTransparent;
+    Color color;
     if (DeprecatedEqualIgnoringCase(meta_element.GetName(), "theme-color") &&
         CSSParser::ParseColor(
             color, meta_element.Content().GetString().StripWhiteSpace(), true))
       return color;
   }
-  return Color();
+  return base::nullopt;
 }
 
 static HTMLLinkElement* GetLinkElement(const Document* doc,
@@ -6538,7 +6535,8 @@
 void Document::InitContentSecurityPolicy(
     ContentSecurityPolicy* csp,
     const ContentSecurityPolicy* last_origin_document_csp) {
-  SetContentSecurityPolicy(csp ? csp : ContentSecurityPolicy::Create());
+  SetContentSecurityPolicy(csp ? csp
+                               : MakeGarbageCollected<ContentSecurityPolicy>());
 
   GetContentSecurityPolicy()->BindToDelegate(
       GetContentSecurityPolicyDelegate());
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 9d30949..443523f 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1034,7 +1034,7 @@
 
   Vector<IconURL> IconURLs(int icon_types_mask);
 
-  Color ThemeColor() const;
+  base::Optional<Color> ThemeColor() const;
 
   // Returns the HTMLLinkElement currently in use for the Web Manifest.
   // Returns null if there is no such element.
@@ -1936,10 +1936,10 @@
   int64_t ukm_source_id_;
 
 #if DCHECK_IS_ON()
-  unsigned slot_assignment_recalc_forbidden_recursion_depth_;
+  unsigned slot_assignment_recalc_forbidden_recursion_depth_ = 0;
 #endif
   unsigned slot_assignment_recalc_depth_ = 0;
-  unsigned flat_tree_traversal_forbidden_recursion_depth_;
+  unsigned flat_tree_traversal_forbidden_recursion_depth_ = 0;
 
   bool needs_to_record_ukm_outlive_time_;
 
diff --git a/third_party/blink/renderer/core/dom/document_lifecycle.h b/third_party/blink/renderer/core/dom/document_lifecycle.h
index c45fb82..54cda92 100644
--- a/third_party/blink/renderer/core/dom/document_lifecycle.h
+++ b/third_party/blink/renderer/core/dom/document_lifecycle.h
@@ -289,7 +289,7 @@
          state_ == kInPreLayout || state_ == kLayoutClean ||
          state_ == kCompositingInputsClean || state_ == kCompositingClean ||
          state_ == kPrePaintClean || state_ == kPaintClean ||
-         state_ == kStopping;
+         state_ == kStopping || state_ == kInactive;
 }
 
 inline bool DocumentLifecycle::StateAllowsLayoutInvalidation() const {
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc
index 2a6c8f61..923eb54 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.cc
+++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -159,7 +159,7 @@
 
 PublicURLManager& ExecutionContext::GetPublicURLManager() {
   if (!public_url_manager_)
-    public_url_manager_ = PublicURLManager::Create(this);
+    public_url_manager_ = MakeGarbageCollected<PublicURLManager>(this);
   return *public_url_manager_;
 }
 
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h
index 22228ba..8045819 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -85,7 +85,7 @@
 class SecurityOrigin;
 class ScriptState;
 
-enum class TaskType : unsigned;
+enum class TaskType : unsigned char;
 
 enum ReasonForCallingCanExecuteScripts {
   kAboutToExecuteScript,
diff --git a/third_party/blink/renderer/core/execution_context/remote_security_context.cc b/third_party/blink/renderer/core/execution_context/remote_security_context.cc
index aa163af..6f210cbf 100644
--- a/third_party/blink/renderer/core/execution_context/remote_security_context.cc
+++ b/third_party/blink/renderer/core/execution_context/remote_security_context.cc
@@ -16,7 +16,7 @@
   DCHECK(!GetSecurityOrigin());
 
   // Start with a clean slate.
-  SetContentSecurityPolicy(ContentSecurityPolicy::Create());
+  SetContentSecurityPolicy(MakeGarbageCollected<ContentSecurityPolicy>());
 
   // FIXME: Document::initSecurityContext has a few other things we may
   // eventually want here, such as enforcing a setting to
@@ -36,7 +36,7 @@
 
 void RemoteSecurityContext::ResetReplicatedContentSecurityPolicy() {
   DCHECK(GetSecurityOrigin());
-  SetContentSecurityPolicy(ContentSecurityPolicy::Create());
+  SetContentSecurityPolicy(MakeGarbageCollected<ContentSecurityPolicy>());
   GetContentSecurityPolicy()->SetupSelf(*GetSecurityOrigin());
 }
 
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index 825d2bb..4d008c79 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -443,7 +443,7 @@
 void LocalFrameClientImpl::DispatchDidCommitLoad(
     HistoryItem* item,
     WebHistoryCommitType commit_type,
-    WebGlobalObjectReusePolicy global_object_reuse_policy) {
+    GlobalObjectReusePolicy global_object_reuse_policy) {
   if (!web_frame_->Parent()) {
     web_frame_->ViewImpl()->DidCommitLoad(commit_type == kWebStandardCommit,
                                           false);
@@ -452,8 +452,7 @@
   if (web_frame_->Client()) {
     mojom::blink::DocumentInterfaceBrokerRequest
         document_interface_broker_request;
-    if (global_object_reuse_policy !=
-        WebGlobalObjectReusePolicy::kUseExisting) {
+    if (global_object_reuse_policy != GlobalObjectReusePolicy::kUseExisting) {
       document_interface_broker_request =
           mojo::MakeRequest(&document_interface_broker_);
     }
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
index 910c7bd..099d8d7 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -48,6 +48,7 @@
 class WebDevToolsAgentImpl;
 class WebLocalFrameImpl;
 class WebSpellCheckPanelHostClient;
+enum class GlobalObjectReusePolicy;
 struct WebScrollIntoViewParams;
 
 class LocalFrameClientImpl final : public LocalFrameClient {
@@ -100,7 +101,7 @@
   void DispatchDidChangeIcons(IconType) override;
   void DispatchDidCommitLoad(HistoryItem*,
                              WebHistoryCommitType,
-                             WebGlobalObjectReusePolicy) override;
+                             GlobalObjectReusePolicy) override;
   void DispatchDidFailProvisionalLoad(const ResourceError&,
                                       WebHistoryCommitType) override;
   void DispatchDidFailLoad(const ResourceError&, WebHistoryCommitType) override;
diff --git a/third_party/blink/renderer/core/exported/web_document.cc b/third_party/blink/renderer/core/exported/web_document.cc
index ee6e92a..640e200 100644
--- a/third_party/blink/renderer/core/exported/web_document.cc
+++ b/third_party/blink/renderer/core/exported/web_document.cc
@@ -105,8 +105,11 @@
   return ConstUnwrap<Document>()->referrer();
 }
 
-SkColor WebDocument::ThemeColor() const {
-  return ConstUnwrap<Document>()->ThemeColor().Rgb();
+base::Optional<SkColor> WebDocument::ThemeColor() const {
+  base::Optional<Color> color = ConstUnwrap<Document>()->ThemeColor();
+  if (color)
+    return color->Rgb();
+  return base::nullopt;
 }
 
 WebURL WebDocument::OpenSearchDescriptionURL() const {
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
index 64297dd..3b18cad7 100644
--- a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -386,13 +386,6 @@
                                       WebWidget::LifecycleUpdateReason::kOther);
 }
 
-void WebPagePopupImpl::UpdateAllLifecyclePhasesAndCompositeForTesting(
-    bool do_raster) {
-  if (layer_tree_view_) {
-    layer_tree_view_->UpdateAllLifecyclePhasesAndCompositeForTesting(do_raster);
-  }
-}
-
 void WebPagePopupImpl::PaintContent(cc::PaintCanvas* canvas,
                                     const WebRect& rect) {
   if (!closing_)
@@ -597,6 +590,10 @@
                   window_rect.y - root_window_rect.y);
 }
 
+WebPagePopupClient* WebPagePopupImpl::GetClientForTesting() const {
+  return web_page_popup_client_;
+}
+
 void WebPagePopupImpl::Cancel() {
   if (popup_client_)
     popup_client_->CancelPopup();
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.h b/third_party/blink/renderer/core/exported/web_page_popup_impl.h
index 7a6e979..8dffef2 100644
--- a/third_party/blink/renderer/core/exported/web_page_popup_impl.h
+++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.h
@@ -99,6 +99,7 @@
 
   // WebPagePopup implementation.
   WebPoint PositionRelativeToOwner() override;
+  WebPagePopupClient* GetClientForTesting() const override;
 
   // PagePopup implementation.
   void PostMessageToPopup(const String& message) override;
@@ -114,7 +115,6 @@
                   bool record_main_frame_metrics) override;
   void UpdateLifecycle(LifecycleUpdate requested_update,
                        LifecycleUpdateReason reason) override;
-  void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) override;
   void PaintContent(cc::PaintCanvas*, const WebRect&) override;
   void Resize(const WebSize&) override;
   void Close() override;
diff --git a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
index 49fee9b0..d16ac271 100644
--- a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
@@ -154,7 +154,7 @@
       scope, client, interface_registry,
       std::move(document_interface_broker_handle), opener);
   InsertAfter(child, previous_sibling);
-  RemoteFrameOwner* owner = RemoteFrameOwner::Create(
+  auto* owner = MakeGarbageCollected<RemoteFrameOwner>(
       static_cast<SandboxFlags>(sandbox_flags), container_policy,
       frame_owner_properties, frame_owner_element_type);
   child->InitializeCoreFrame(*GetFrame()->GetPage(), owner, name);
@@ -181,7 +181,7 @@
   WebRemoteFrameImpl* child = WebRemoteFrameImpl::Create(scope, client);
   child->SetOpener(opener);
   AppendChild(child);
-  RemoteFrameOwner* owner = RemoteFrameOwner::Create(
+  auto* owner = MakeGarbageCollected<RemoteFrameOwner>(
       static_cast<SandboxFlags>(sandbox_flags), container_policy,
       WebFrameOwnerProperties(), frame_owner_element_type);
   child->InitializeCoreFrame(*GetFrame()->GetPage(), owner, name);
@@ -474,7 +474,7 @@
                                        WebRemoteFrameClient* client)
     : WebRemoteFrame(scope),
       client_(client),
-      frame_client_(RemoteFrameClientImpl::Create(this)),
+      frame_client_(MakeGarbageCollected<RemoteFrameClientImpl>(this)),
       self_keep_alive_(this) {
   DCHECK(client);
 }
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 451e650..c4a8a36 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1592,13 +1592,6 @@
   }
 }
 
-void WebViewImpl::UpdateAllLifecyclePhasesAndCompositeForTesting(
-    bool do_raster) {
-  if (layer_tree_view_) {
-    layer_tree_view_->UpdateAllLifecyclePhasesAndCompositeForTesting(do_raster);
-  }
-}
-
 void WebViewImpl::RequestPresentationCallbackForTesting(
     base::OnceClosure callback) {
   layer_tree_view_->RequestPresentationCallback(std::move(callback));
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index d161ab3..9f6fbeb0 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -443,7 +443,6 @@
   void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override;
   void UpdateLifecycle(LifecycleUpdate requested_update,
                        LifecycleUpdateReason reason) override;
-  void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) override;
   void RequestPresentationCallbackForTesting(
       base::OnceClosure callback) override;
   void PaintContent(cc::PaintCanvas*, const WebRect&) override;
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5 b/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
index d1acc7f..875c012 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
@@ -107,11 +107,6 @@
       depends_on: ["ExperimentalProductivityFeatures"],
     },
     {
-      name: "LegacyImageFormats",
-      feature_policy_name: "legacy-image-formats",
-      depends_on: ["ExperimentalProductivityFeatures"],
-    },
-    {
       name: "Magnetometer",
       feature_policy_name: "magnetometer",
       depends_on: ["Sensor"],
@@ -224,4 +219,4 @@
     //   depends_on: ["WebVR", "WebXR"],
     // },
   ],
-}
\ No newline at end of file
+}
diff --git a/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc b/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
index 3ced572..9f529d16 100644
--- a/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
+++ b/third_party/blink/renderer/core/fetch/body_stream_buffer_test.cc
@@ -95,8 +95,8 @@
   V8TestingScope scope;
   NonThrowableExceptionState exception_state;
   Checkpoint checkpoint;
-  MockFetchDataLoaderClient* client1 = MockFetchDataLoaderClient::Create();
-  MockFetchDataLoaderClient* client2 = MockFetchDataLoaderClient::Create();
+  auto* client1 = MakeGarbageCollected<MockFetchDataLoaderClient>();
+  auto* client2 = MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(0));
@@ -161,8 +161,8 @@
   underlying_source->Close();
 
   Checkpoint checkpoint;
-  MockFetchDataLoaderClient* client1 = MockFetchDataLoaderClient::Create();
-  MockFetchDataLoaderClient* client2 = MockFetchDataLoaderClient::Create();
+  auto* client1 = MakeGarbageCollected<MockFetchDataLoaderClient>();
+  auto* client2 = MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -350,7 +350,7 @@
 TEST_F(BodyStreamBufferTest, LoadBodyStreamBufferAsArrayBuffer) {
   V8TestingScope scope;
   Checkpoint checkpoint;
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
   DOMArrayBuffer* array_buffer = nullptr;
 
   InSequence s;
@@ -388,7 +388,7 @@
 TEST_F(BodyStreamBufferTest, LoadBodyStreamBufferAsBlob) {
   V8TestingScope scope;
   Checkpoint checkpoint;
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
   scoped_refptr<BlobDataHandle> blob_data_handle;
 
   InSequence s;
@@ -424,7 +424,7 @@
 TEST_F(BodyStreamBufferTest, LoadBodyStreamBufferAsString) {
   V8TestingScope scope;
   Checkpoint checkpoint;
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -457,7 +457,7 @@
 TEST_F(BodyStreamBufferTest, LoadClosedHandle) {
   V8TestingScope scope;
   Checkpoint checkpoint;
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -486,7 +486,7 @@
 TEST_F(BodyStreamBufferTest, LoadErroredHandle) {
   V8TestingScope scope;
   Checkpoint checkpoint;
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -516,7 +516,7 @@
 TEST_F(BodyStreamBufferTest, LoaderShouldBeKeptAliveByBodyStreamBuffer) {
   V8TestingScope scope;
   Checkpoint checkpoint;
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -614,8 +614,8 @@
   V8TestingScope scope;
   Checkpoint checkpoint;
   MockFetchDataLoader* loader = MockFetchDataLoader::Create();
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
-  auto* src = BytesConsumerTestUtil::MockBytesConsumer::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
+  auto* src = MakeGarbageCollected<BytesConsumerTestUtil::MockBytesConsumer>();
 
   EXPECT_CALL(*loader, Start(_, _)).Times(0);
 
@@ -649,8 +649,8 @@
   V8TestingScope scope;
   Checkpoint checkpoint;
   MockFetchDataLoader* loader = MockFetchDataLoader::Create();
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
-  auto* src = BytesConsumerTestUtil::MockBytesConsumer::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
+  auto* src = MakeGarbageCollected<BytesConsumerTestUtil::MockBytesConsumer>();
 
   InSequence s;
   EXPECT_CALL(*src, SetClient(_));
@@ -684,8 +684,8 @@
   V8TestingScope scope;
   Checkpoint checkpoint;
   MockFetchDataLoader* loader = MockFetchDataLoader::Create();
-  MockFetchDataLoaderClient* client = MockFetchDataLoaderClient::Create();
-  auto* src = BytesConsumerTestUtil::MockBytesConsumer::Create();
+  auto* client = MakeGarbageCollected<MockFetchDataLoaderClient>();
+  auto* src = MakeGarbageCollected<BytesConsumerTestUtil::MockBytesConsumer>();
 
   InSequence s;
   EXPECT_CALL(*src, SetClient(_));
diff --git a/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h b/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h
index 447e3f3..38d7ce1 100644
--- a/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h
+++ b/third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h
@@ -20,10 +20,6 @@
  public:
   class MockBytesConsumer : public BytesConsumer {
    public:
-    static MockBytesConsumer* Create() {
-      return MakeGarbageCollected<testing::StrictMock<MockBytesConsumer>>();
-    }
-
     MOCK_METHOD2(BeginRead, Result(const char**, size_t*));
     MOCK_METHOD1(EndRead, Result(size_t));
     MOCK_METHOD1(DrainAsBlobDataHandle,
@@ -35,10 +31,9 @@
     MOCK_CONST_METHOD0(GetPublicState, PublicState());
     MOCK_CONST_METHOD0(GetError, Error());
 
-    String DebugName() const override { return "MockBytesConsumer"; }
-
-   protected:
     MockBytesConsumer();
+
+    String DebugName() const override { return "MockBytesConsumer"; }
   };
 
   class MockFetchDataLoaderClient
@@ -47,11 +42,6 @@
     USING_GARBAGE_COLLECTED_MIXIN(MockFetchDataLoaderClient);
 
    public:
-    static testing::StrictMock<MockFetchDataLoaderClient>* Create() {
-      return MakeGarbageCollected<
-          testing::StrictMock<MockFetchDataLoaderClient>>();
-    }
-
     void Trace(blink::Visitor* visitor) override {
       FetchDataLoader::Client::Trace(visitor);
     }
diff --git a/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc b/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
index f82ac7b..80899ea5 100644
--- a/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_data_loader_test.cc
@@ -61,12 +61,12 @@
 TEST(FetchDataLoaderTest, LoadAsBlob) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsBlobHandle("text/test");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
   scoped_refptr<BlobDataHandle> blob_data_handle;
 
   InSequence s;
@@ -110,12 +110,12 @@
 TEST(FetchDataLoaderTest, LoadAsBlobFailed) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsBlobHandle("text/test");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -153,12 +153,12 @@
 TEST(FetchDataLoaderTest, LoadAsBlobCancel) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsBlobHandle("text/test");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -191,12 +191,12 @@
       std::move(blob_data), kQuickBrownFoxLengthWithTerminatingNull);
 
   Checkpoint checkpoint;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsBlobHandle("text/test");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
   scoped_refptr<BlobDataHandle> blob_data_handle;
 
   InSequence s;
@@ -233,12 +233,12 @@
       std::move(blob_data), kQuickBrownFoxLengthWithTerminatingNull);
 
   Checkpoint checkpoint;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsBlobHandle("text/test");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
   scoped_refptr<BlobDataHandle> blob_data_handle;
 
   InSequence s;
@@ -268,12 +268,12 @@
 TEST(FetchDataLoaderTest, LoadAsArrayBuffer) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsArrayBuffer();
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
   DOMArrayBuffer* array_buffer = nullptr;
 
   InSequence s;
@@ -314,12 +314,12 @@
 TEST(FetchDataLoaderTest, LoadAsArrayBufferFailed) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsArrayBuffer();
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -353,12 +353,12 @@
 TEST(FetchDataLoaderTest, LoadAsArrayBufferCancel) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsArrayBuffer();
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -380,12 +380,12 @@
 TEST(FetchDataLoaderTest, LoadAsFormData) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsFormData("boundary");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
   FormData* form_data = nullptr;
 
   InSequence s;
@@ -449,12 +449,12 @@
 TEST(FetchDataLoaderTest, LoadAsFormDataPartialInput) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsFormData("boundary");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -488,12 +488,12 @@
 TEST(FetchDataLoaderTest, LoadAsFormDataFailed) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsFormData("boundary");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -527,12 +527,12 @@
 TEST(FetchDataLoaderTest, LoadAsFormDataCancel) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader =
       FetchDataLoader::CreateLoaderAsFormData("boundary");
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -554,11 +554,11 @@
 TEST(FetchDataLoaderTest, LoadAsString) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader = FetchDataLoader::CreateLoaderAsString();
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -593,11 +593,11 @@
 TEST(FetchDataLoaderTest, LoadAsStringWithNullBytes) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader = FetchDataLoader::CreateLoaderAsString();
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   constexpr char kPattern[] = "Quick\0brown\0fox";
   constexpr size_t kLength = sizeof(kPattern);
@@ -633,11 +633,11 @@
 TEST(FetchDataLoaderTest, LoadAsStringError) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader = FetchDataLoader::CreateLoaderAsString();
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
@@ -671,11 +671,11 @@
 TEST(FetchDataLoaderTest, LoadAsStringCancel) {
   Checkpoint checkpoint;
   BytesConsumer::Client* client = nullptr;
-  MockBytesConsumer* consumer = MockBytesConsumer::Create();
+  auto* consumer = MakeGarbageCollected<MockBytesConsumer>();
 
   FetchDataLoader* fetch_data_loader = FetchDataLoader::CreateLoaderAsString();
-  MockFetchDataLoaderClient* fetch_data_loader_client =
-      MockFetchDataLoaderClient::Create();
+  auto* fetch_data_loader_client =
+      MakeGarbageCollected<MockFetchDataLoaderClient>();
 
   InSequence s;
   EXPECT_CALL(checkpoint, Call(1));
diff --git a/third_party/blink/renderer/core/fetch/fetch_header_list.cc b/third_party/blink/renderer/core/fetch/fetch_header_list.cc
index 496df60..3304b74 100644
--- a/third_party/blink/renderer/core/fetch/fetch_header_list.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_header_list.cc
@@ -12,12 +12,8 @@
 
 namespace blink {
 
-FetchHeaderList* FetchHeaderList::Create() {
-  return MakeGarbageCollected<FetchHeaderList>();
-}
-
 FetchHeaderList* FetchHeaderList::Clone() const {
-  FetchHeaderList* list = Create();
+  auto* list = MakeGarbageCollected<FetchHeaderList>();
   for (const auto& header : header_list_)
     list->Append(header.first, header.second);
   return list;
diff --git a/third_party/blink/renderer/core/fetch/fetch_header_list.h b/third_party/blink/renderer/core/fetch/fetch_header_list.h
index 28178044..7f2db8933 100644
--- a/third_party/blink/renderer/core/fetch/fetch_header_list.h
+++ b/third_party/blink/renderer/core/fetch/fetch_header_list.h
@@ -25,7 +25,6 @@
   };
 
   typedef std::pair<String, String> Header;
-  static FetchHeaderList* Create();
   FetchHeaderList* Clone() const;
 
   FetchHeaderList();
diff --git a/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc b/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
index 4adad47..200e8fc 100644
--- a/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
@@ -15,7 +15,7 @@
 namespace {
 
 TEST(FetchHeaderListTest, Append) {
-  FetchHeaderList* headerList = FetchHeaderList::Create();
+  auto* headerList = MakeGarbageCollected<FetchHeaderList>();
   headerList->Append("ConTenT-TyPe", "text/plain");
   headerList->Append("content-type", "application/xml");
   headerList->Append("CONTENT-type", "foo");
@@ -35,7 +35,7 @@
 }
 
 TEST(FetchHeaderListTest, Set) {
-  FetchHeaderList* headerList = FetchHeaderList::Create();
+  auto* headerList = MakeGarbageCollected<FetchHeaderList>();
   headerList->Append("ConTenT-TyPe", "text/plain");
   headerList->Append("content-type", "application/xml");
   headerList->Append("CONTENT-type", "foo");
@@ -58,7 +58,7 @@
 }
 
 TEST(FetchHeaderListTest, Erase) {
-  FetchHeaderList* headerList = FetchHeaderList::Create();
+  auto* headerList = MakeGarbageCollected<FetchHeaderList>();
   headerList->Remove("foo");
   EXPECT_EQ(0U, headerList->size());
   headerList->Append("ConTenT-TyPe", "text/plain");
@@ -80,7 +80,7 @@
 }
 
 TEST(FetchHeaderListTest, Combine) {
-  FetchHeaderList* headerList = FetchHeaderList::Create();
+  auto* headerList = MakeGarbageCollected<FetchHeaderList>();
   headerList->Append("ConTenT-TyPe", "text/plain");
   headerList->Append("content-type", "application/xml");
   headerList->Append("CONTENT-type", "foo");
@@ -93,7 +93,7 @@
 }
 
 TEST(FetchHeaderListTest, Contains) {
-  FetchHeaderList* headerList = FetchHeaderList::Create();
+  auto* headerList = MakeGarbageCollected<FetchHeaderList>();
   headerList->Append("ConTenT-TyPe", "text/plain");
   headerList->Append("content-type", "application/xml");
   headerList->Append("X-Foo", "bar");
@@ -103,7 +103,7 @@
 }
 
 TEST(FetchHeaderListTest, SortAndCombine) {
-  FetchHeaderList* headerList = FetchHeaderList::Create();
+  auto* headerList = MakeGarbageCollected<FetchHeaderList>();
   EXPECT_TRUE(headerList->SortAndCombine().IsEmpty());
   headerList->Append("content-type", "multipart/form-data");
   headerList->Append("ConTenT-TyPe", "application/xml");
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index ce5876e..6c25a9c 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -81,17 +81,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(Loader);
 
  public:
-  static Loader* Create(ExecutionContext* execution_context,
-                        FetchManager* fetch_manager,
-                        ScriptPromiseResolver* resolver,
-                        FetchRequestData* request,
-                        bool is_isolated_world,
-                        AbortSignal* signal) {
-    return MakeGarbageCollected<Loader>(execution_context, fetch_manager,
-                                        resolver, request, is_isolated_world,
-                                        signal);
-  }
-
   Loader(ExecutionContext*,
          FetchManager*,
          ScriptPromiseResolver*,
@@ -858,9 +847,9 @@
 
   request->SetContext(mojom::RequestContextType::FETCH);
 
-  Loader* loader =
-      Loader::Create(GetExecutionContext(), this, resolver, request,
-                     script_state->World().IsIsolatedWorld(), signal);
+  auto* loader = MakeGarbageCollected<Loader>(
+      GetExecutionContext(), this, resolver, request,
+      script_state->World().IsIsolatedWorld(), signal);
   loaders_.insert(loader);
   signal->AddAlgorithm(WTF::Bind(&Loader::Abort, WrapWeakPersistent(loader)));
   // TODO(ricea): Reject the Response body with AbortError, not TypeError.
diff --git a/third_party/blink/renderer/core/fetch/fetch_request_data.cc b/third_party/blink/renderer/core/fetch/fetch_request_data.cc
index 964c50d..637e405 100644
--- a/third_party/blink/renderer/core/fetch/fetch_request_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_request_data.cc
@@ -158,7 +158,7 @@
 
 FetchRequestData::FetchRequestData()
     : method_(http_names::kGET),
-      header_list_(FetchHeaderList::Create()),
+      header_list_(MakeGarbageCollected<FetchHeaderList>()),
       context_(mojom::RequestContextType::UNSPECIFIED),
       same_origin_data_url_flag_(false),
       referrer_string_(Referrer::ClientReferrerString()),
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index ba66d01..6b8f63f 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -299,7 +299,7 @@
       response_source_(source),
       status_(status),
       status_message_(status_message),
-      header_list_(FetchHeaderList::Create()),
+      header_list_(MakeGarbageCollected<FetchHeaderList>()),
       response_time_(base::Time::Now()) {}
 
 void FetchResponseData::ReplaceBodyStreamBuffer(BodyStreamBuffer* buffer) {
diff --git a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc
index 48c99d97..105b5fe1 100644
--- a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc
+++ b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc
@@ -193,7 +193,7 @@
 
 TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromComplexFormData) {
   scoped_refptr<EncodedFormData> data = ComplexFormData();
-  MockBytesConsumer* underlying = MockBytesConsumer::Create();
+  auto* underlying = MakeGarbageCollected<MockBytesConsumer>();
   BytesConsumer* consumer =
       FormDataBytesConsumer::CreateForTesting(&GetDocument(), data, underlying);
   Checkpoint checkpoint;
@@ -376,7 +376,7 @@
 }
 
 TEST_F(FormDataBytesConsumerTest, BeginReadAffectsDrainingWithComplexFormData) {
-  MockBytesConsumer* underlying = MockBytesConsumer::Create();
+  auto* underlying = MakeGarbageCollected<MockBytesConsumer>();
   BytesConsumer* consumer = FormDataBytesConsumer::CreateForTesting(
       &GetDocument(), ComplexFormData(), underlying);
 
@@ -415,7 +415,7 @@
 TEST_F(FormDataBytesConsumerTest, SetClientWithComplexFormData) {
   scoped_refptr<EncodedFormData> input_form_data = ComplexFormData();
 
-  MockBytesConsumer* underlying = MockBytesConsumer::Create();
+  auto* underlying = MakeGarbageCollected<MockBytesConsumer>();
   BytesConsumer* consumer = FormDataBytesConsumer::CreateForTesting(
       &GetDocument(), input_form_data, underlying);
   Checkpoint checkpoint;
@@ -437,7 +437,7 @@
 TEST_F(FormDataBytesConsumerTest, CancelWithComplexFormData) {
   scoped_refptr<EncodedFormData> input_form_data = ComplexFormData();
 
-  MockBytesConsumer* underlying = MockBytesConsumer::Create();
+  auto* underlying = MakeGarbageCollected<MockBytesConsumer>();
   BytesConsumer* consumer = FormDataBytesConsumer::CreateForTesting(
       &GetDocument(), input_form_data, underlying);
   Checkpoint checkpoint;
diff --git a/third_party/blink/renderer/core/fetch/headers.cc b/third_party/blink/renderer/core/fetch/headers.cc
index 63a499a9..45764179 100644
--- a/third_party/blink/renderer/core/fetch/headers.cc
+++ b/third_party/blink/renderer/core/fetch/headers.cc
@@ -286,7 +286,8 @@
 }
 
 Headers::Headers()
-    : header_list_(FetchHeaderList::Create()), guard_(kNoneGuard) {}
+    : header_list_(MakeGarbageCollected<FetchHeaderList>()),
+      guard_(kNoneGuard) {}
 
 Headers::Headers(FetchHeaderList* header_list)
     : header_list_(header_list), guard_(kNoneGuard) {}
diff --git a/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc b/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
index 645a11b8..e25410fc 100644
--- a/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
+++ b/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer_test.cc
@@ -34,10 +34,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(MockClient);
 
  public:
-  static MockClient* Create() {
-    return MakeGarbageCollected<StrictMock<MockClient>>();
-  }
-
   MockClient() = default;
 
   MOCK_METHOD0(OnStateChange, void());
@@ -76,7 +72,7 @@
       MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
                                                         ASSERT_NO_EXCEPTION);
 
-  Persistent<MockClient> client = MockClient::Create();
+  Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
   consumer->SetClient(client);
 
   Checkpoint checkpoint;
@@ -115,7 +111,7 @@
   Persistent<BytesConsumer> consumer =
       MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
                                                         ASSERT_NO_EXCEPTION);
-  Persistent<MockClient> client = MockClient::Create();
+  Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
   consumer->SetClient(client);
   Checkpoint checkpoint;
 
@@ -172,7 +168,7 @@
   Persistent<BytesConsumer> consumer =
       MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
                                                         ASSERT_NO_EXCEPTION);
-  Persistent<MockClient> client = MockClient::Create();
+  Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
   consumer->SetClient(client);
   Checkpoint checkpoint;
 
@@ -264,7 +260,7 @@
   Persistent<BytesConsumer> consumer =
       MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
                                                         ASSERT_NO_EXCEPTION);
-  Persistent<MockClient> client = MockClient::Create();
+  Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
   consumer->SetClient(client);
   Checkpoint checkpoint;
 
@@ -304,7 +300,7 @@
   Persistent<BytesConsumer> consumer =
       MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
                                                         ASSERT_NO_EXCEPTION);
-  Persistent<MockClient> client = MockClient::Create();
+  Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
   consumer->SetClient(client);
   Checkpoint checkpoint;
 
@@ -344,7 +340,7 @@
   Persistent<BytesConsumer> consumer =
       MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
                                                         ASSERT_NO_EXCEPTION);
-  Persistent<MockClient> client = MockClient::Create();
+  Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
   consumer->SetClient(client);
   Checkpoint checkpoint;
 
diff --git a/third_party/blink/renderer/core/fileapi/file_list.h b/third_party/blink/renderer/core/fileapi/file_list.h
index 0eeec3d..934bf5d 100644
--- a/third_party/blink/renderer/core/fileapi/file_list.h
+++ b/third_party/blink/renderer/core/fileapi/file_list.h
@@ -38,8 +38,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static FileList* Create() { return MakeGarbageCollected<FileList>(); }
-
   FileList();
 
   unsigned length() const { return files_.size(); }
diff --git a/third_party/blink/renderer/core/fileapi/file_list_test.cc b/third_party/blink/renderer/core/fileapi/file_list_test.cc
index 00b6b4c..f3156f7 100644
--- a/third_party/blink/renderer/core/fileapi/file_list_test.cc
+++ b/third_party/blink/renderer/core/fileapi/file_list_test.cc
@@ -10,7 +10,7 @@
 namespace blink {
 
 TEST(FileListTest, pathsForUserVisibleFiles) {
-  FileList* const file_list = FileList::Create();
+  auto* const file_list = MakeGarbageCollected<FileList>();
 
   // Native file.
   file_list->Append(File::Create("/native/path"));
diff --git a/third_party/blink/renderer/core/fileapi/public_url_manager.cc b/third_party/blink/renderer/core/fileapi/public_url_manager.cc
index 9794137d..f6c5ae86 100644
--- a/third_party/blink/renderer/core/fileapi/public_url_manager.cc
+++ b/third_party/blink/renderer/core/fileapi/public_url_manager.cc
@@ -99,10 +99,6 @@
 
 }  // namespace
 
-PublicURLManager* PublicURLManager::Create(ExecutionContext* context) {
-  return MakeGarbageCollected<PublicURLManager>(context);
-}
-
 PublicURLManager::PublicURLManager(ExecutionContext* context)
     : ContextLifecycleObserver(context), is_stopped_(false) {}
 
diff --git a/third_party/blink/renderer/core/fileapi/public_url_manager.h b/third_party/blink/renderer/core/fileapi/public_url_manager.h
index a08d61aa..7b027de 100644
--- a/third_party/blink/renderer/core/fileapi/public_url_manager.h
+++ b/third_party/blink/renderer/core/fileapi/public_url_manager.h
@@ -48,8 +48,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(PublicURLManager);
 
  public:
-  static PublicURLManager* Create(ExecutionContext*);
-
   explicit PublicURLManager(ExecutionContext*);
 
   // Generates a new Blob URL and registers the URLRegistrable to the
diff --git a/third_party/blink/renderer/core/frame/bar_prop.h b/third_party/blink/renderer/core/frame/bar_prop.h
index d4b28a4..668e75a 100644
--- a/third_party/blink/renderer/core/frame/bar_prop.h
+++ b/third_party/blink/renderer/core/frame/bar_prop.h
@@ -51,10 +51,6 @@
     kToolbar
   };
 
-  static BarProp* Create(LocalFrame* frame, Type type) {
-    return MakeGarbageCollected<BarProp>(frame, type);
-  }
-
   BarProp(LocalFrame*, Type);
 
   bool visible() const;
diff --git a/third_party/blink/renderer/core/frame/browser_controls.h b/third_party/blink/renderer/core/frame/browser_controls.h
index 5545e44..c494bcf4 100644
--- a/third_party/blink/renderer/core/frame/browser_controls.h
+++ b/third_party/blink/renderer/core/frame/browser_controls.h
@@ -24,10 +24,6 @@
 class CORE_EXPORT BrowserControls final
     : public GarbageCollected<BrowserControls> {
  public:
-  static BrowserControls* Create(const Page& page) {
-    return MakeGarbageCollected<BrowserControls>(page);
-  }
-
   explicit BrowserControls(const Page&);
 
   void Trace(blink::Visitor*);
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index fc31b52f..ada062c 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -1582,7 +1582,7 @@
   if (attr.Contains('\n') || attr.Contains('\r'))
     return false;
 
-  ContentSecurityPolicy* attr_policy = ContentSecurityPolicy::Create();
+  auto* attr_policy = MakeGarbageCollected<ContentSecurityPolicy>();
   attr_policy->AddPolicyFromHeaderValue(attr,
                                         kContentSecurityPolicyHeaderTypeEnforce,
                                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1601,7 +1601,7 @@
     return true;
   }
 
-  ContentSecurityPolicy* context_policy = ContentSecurityPolicy::Create();
+  auto* context_policy = MakeGarbageCollected<ContentSecurityPolicy>();
   context_policy->AddPolicyFromHeaderValue(
       context_required_csp, kContentSecurityPolicyHeaderTypeEnforce,
       kContentSecurityPolicyHeaderSourceHTTP);
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index e6149dd8..fd052b2 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -207,10 +207,6 @@
 
   static const size_t kMaxSampleLength = 40;
 
-  static ContentSecurityPolicy* Create() {
-    return MakeGarbageCollected<ContentSecurityPolicy>();
-  }
-
   ContentSecurityPolicy();
   ~ContentSecurityPolicy();
   void Trace(blink::Visitor*);
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
index 33ddd35..727cc79 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_fuzzer.cc
@@ -45,7 +45,7 @@
   }
 
   // Construct and initialize a policy from the string.
-  ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+  auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
   csp->DidReceiveHeader(header, header_type, header_source);
   g_page_holder->GetDocument().InitContentSecurityPolicy(csp);
 
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 d121579..3ec5854 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
@@ -26,7 +26,7 @@
 class ContentSecurityPolicyTest : public testing::Test {
  public:
   ContentSecurityPolicyTest()
-      : csp(ContentSecurityPolicy::Create()),
+      : csp(MakeGarbageCollected<ContentSecurityPolicy>()),
         secure_url("https://example.test/image.png"),
         secure_origin(SecurityOrigin::Create(secure_url)) {}
 
@@ -63,7 +63,7 @@
   for (const auto& test : cases) {
     SCOPED_TRACE(testing::Message()
                  << "[Enforce] Header: `" << test.header << "`");
-    csp = ContentSecurityPolicy::Create();
+    csp = MakeGarbageCollected<ContentSecurityPolicy>();
     csp->DidReceiveHeader(test.header, kContentSecurityPolicyHeaderTypeEnforce,
                           kContentSecurityPolicyHeaderSourceHTTP);
     EXPECT_EQ(test.expected_policy, csp->GetInsecureRequestPolicy());
@@ -83,7 +83,7 @@
   for (const auto& test : cases) {
     SCOPED_TRACE(testing::Message()
                  << "[Report-Only] Header: `" << test.header << "`");
-    csp = ContentSecurityPolicy::Create();
+    csp = MakeGarbageCollected<ContentSecurityPolicy>();
     csp->DidReceiveHeader(test.header, kContentSecurityPolicyHeaderTypeReport,
                           kContentSecurityPolicyHeaderSourceHTTP);
     EXPECT_EQ(kLeaveInsecureRequestsAlone, csp->GetInsecureRequestPolicy());
@@ -133,7 +133,7 @@
   const KURL example_url("http://example.com");
   const KURL not_example_url("http://not-example.com");
 
-  ContentSecurityPolicy* csp2 = ContentSecurityPolicy::Create();
+  auto* csp2 = MakeGarbageCollected<ContentSecurityPolicy>();
   csp2->CopyStateFrom(csp.Get());
   EXPECT_FALSE(csp2->AllowScriptFromSource(
       example_url, String(), IntegrityMetadataSet(), kParserInserted,
@@ -167,7 +167,7 @@
   const KURL example_url("http://example.com");
   const KURL not_example_url("http://not-example.com");
 
-  ContentSecurityPolicy* csp2 = ContentSecurityPolicy::Create();
+  auto* csp2 = MakeGarbageCollected<ContentSecurityPolicy>();
   csp2->CopyPluginTypesFrom(csp.Get());
   EXPECT_TRUE(csp2->AllowScriptFromSource(
       example_url, String(), IntegrityMetadataSet(), kParserInserted,
@@ -321,7 +321,8 @@
 TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderMissingIntegrity) {
   const KURL url("https://example.test");
   // Enforce
-  Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
+  Persistent<ContentSecurityPolicy> policy =
+      MakeGarbageCollected<ContentSecurityPolicy>();
   policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeEnforce,
@@ -357,7 +358,7 @@
       kParserInserted, ResourceRequest::RedirectStatus::kNoRedirect,
       SecurityViolationReportingPolicy::kSuppressReporting));
   // Report
-  policy = ContentSecurityPolicy::Create();
+  policy = MakeGarbageCollected<ContentSecurityPolicy>();
   policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeReport,
@@ -403,7 +404,8 @@
       IntegrityMetadata("1234", IntegrityAlgorithm::kSha384).ToPair());
   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   // Enforce
-  Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
+  Persistent<ContentSecurityPolicy> policy =
+      MakeGarbageCollected<ContentSecurityPolicy>();
   policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeEnforce,
@@ -440,7 +442,7 @@
       SecurityViolationReportingPolicy::kSuppressReporting));
   // Content-Security-Policy-Report-Only is not supported in meta element,
   // so nothing should be blocked
-  policy = ContentSecurityPolicy::Create();
+  policy = MakeGarbageCollected<ContentSecurityPolicy>();
   policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeReport,
@@ -482,7 +484,8 @@
 TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaMissingIntegrity) {
   const KURL url("https://example.test");
   // Enforce
-  Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
+  Persistent<ContentSecurityPolicy> policy =
+      MakeGarbageCollected<ContentSecurityPolicy>();
   policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeEnforce,
@@ -519,7 +522,7 @@
       SecurityViolationReportingPolicy::kSuppressReporting));
   // Content-Security-Policy-Report-Only is not supported in meta element,
   // so nothing should be blocked
-  policy = ContentSecurityPolicy::Create();
+  policy = MakeGarbageCollected<ContentSecurityPolicy>();
   policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeReport,
@@ -565,7 +568,8 @@
       IntegrityMetadata("1234", IntegrityAlgorithm::kSha384).ToPair());
   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   // Enforce
-  Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
+  Persistent<ContentSecurityPolicy> policy =
+      MakeGarbageCollected<ContentSecurityPolicy>();
   policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeEnforce,
@@ -602,7 +606,7 @@
       SecurityViolationReportingPolicy::kSuppressReporting));
   // Content-Security-Policy-Report-Only is not supported in meta element,
   // so nothing should be blocked
-  policy = ContentSecurityPolicy::Create();
+  policy = MakeGarbageCollected<ContentSecurityPolicy>();
   policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeReport,
@@ -665,7 +669,8 @@
     unsigned expected_reports = test.allowed ? 0u : 1u;
 
     // Single enforce-mode policy should match `test.expected`:
-    Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
+    Persistent<ContentSecurityPolicy> policy =
+        MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(
         execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy,
@@ -679,7 +684,7 @@
     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
 
     // Single report-mode policy should always be `true`:
-    policy = ContentSecurityPolicy::Create();
+    policy = MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(
         execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy,
@@ -727,7 +732,8 @@
         HTMLScriptElement::Create(*document, CreateElementFlags::ByParser());
 
     // Enforce 'script-src'
-    Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
+    Persistent<ContentSecurityPolicy> policy =
+        MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(String("script-src ") + test.policy,
                              kContentSecurityPolicyHeaderTypeEnforce,
@@ -739,7 +745,7 @@
     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
 
     // Enforce 'style-src'
-    policy = ContentSecurityPolicy::Create();
+    policy = MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(String("style-src ") + test.policy,
                              kContentSecurityPolicyHeaderTypeEnforce,
@@ -751,7 +757,7 @@
     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
 
     // Report 'script-src'
-    policy = ContentSecurityPolicy::Create();
+    policy = MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(String("script-src ") + test.policy,
                              kContentSecurityPolicyHeaderTypeReport,
@@ -762,7 +768,7 @@
     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
 
     // Report 'style-src'
-    policy = ContentSecurityPolicy::Create();
+    policy = MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(String("style-src ") + test.policy,
                              kContentSecurityPolicyHeaderTypeReport,
@@ -832,7 +838,8 @@
         test.allowed1 != test.allowed2 ? 1u : (test.allowed1 ? 0u : 2u);
 
     // Enforce / Report
-    Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
+    Persistent<ContentSecurityPolicy> policy =
+        MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(
         execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy1,
@@ -855,7 +862,7 @@
     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
 
     // Report / Enforce
-    policy = ContentSecurityPolicy::Create();
+    policy = MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(
         execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy1,
@@ -878,7 +885,7 @@
     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
 
     // Enforce / Enforce
-    policy = ContentSecurityPolicy::Create();
+    policy = MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(
         execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy1,
@@ -896,7 +903,7 @@
     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
 
     // Report / Report
-    policy = ContentSecurityPolicy::Create();
+    policy = MakeGarbageCollected<ContentSecurityPolicy>();
     policy->BindToDelegate(
         execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy1,
@@ -1021,7 +1028,7 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, Subsumes) {
-  ContentSecurityPolicy* other = ContentSecurityPolicy::Create();
+  auto* other = MakeGarbageCollected<ContentSecurityPolicy>();
   EXPECT_TRUE(csp->Subsumes(*other));
   EXPECT_TRUE(other->Subsumes(*csp));
 
@@ -1478,7 +1485,7 @@
   KURL not_example_url("http://not-example.com");
 
   // Directive name is case insensitive.
-  csp = ContentSecurityPolicy::Create();
+  csp = MakeGarbageCollected<ContentSecurityPolicy>();
   csp->DidReceiveHeader("sCrIpt-sRc http://example.com",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1491,7 +1498,7 @@
 
   // Duplicate directive that is in a different case pattern is
   // correctly treated as a duplicate directive and ignored.
-  csp = ContentSecurityPolicy::Create();
+  csp = MakeGarbageCollected<ContentSecurityPolicy>();
   csp->DidReceiveHeader(
       "SCRipt-SRC http://example.com; script-src http://not-example.com;",
       kContentSecurityPolicyHeaderTypeEnforce,
@@ -1507,7 +1514,7 @@
 // Tests that using an empty CSP works and doesn't impose any policy
 // restrictions.
 TEST_F(ContentSecurityPolicyTest, EmptyCSPIsNoOp) {
-  csp = ContentSecurityPolicy::Create();
+  csp = MakeGarbageCollected<ContentSecurityPolicy>();
   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
 
   const KURL example_url("http://example.com");
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc
index 3414b2e7..019d3ce3 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list_test.cc
@@ -24,7 +24,7 @@
 
 class CSPDirectiveListTest : public testing::Test {
  public:
-  CSPDirectiveListTest() : csp(ContentSecurityPolicy::Create()) {}
+  CSPDirectiveListTest() : csp(MakeGarbageCollected<ContentSecurityPolicy>()) {}
   void SetUp() override {
     scoped_feature_list_.InitWithFeatures({network::features::kReporting}, {});
     csp->SetupSelf(
diff --git a/third_party/blink/renderer/core/frame/csp/csp_source_test.cc b/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
index 8e3f0b1..ca48da0 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_source_test.cc
@@ -15,7 +15,7 @@
 
 class CSPSourceTest : public testing::Test {
  public:
-  CSPSourceTest() : csp(ContentSecurityPolicy::Create()) {}
+  CSPSourceTest() : csp(MakeGarbageCollected<ContentSecurityPolicy>()) {}
 
  protected:
   Persistent<ContentSecurityPolicy> csp;
@@ -144,7 +144,8 @@
 
   // Self scheme is http.
   {
-    Persistent<ContentSecurityPolicy> csp(ContentSecurityPolicy::Create());
+    Persistent<ContentSecurityPolicy> csp(
+        MakeGarbageCollected<ContentSecurityPolicy>());
     csp->SetupSelf(*SecurityOrigin::CreateFromString("http://a.com/"));
     CSPSource source(csp.Get(), "", "a.com", 0, "/", CSPSource::kNoWildcard,
                      CSPSource::kNoWildcard);
@@ -155,7 +156,8 @@
 
   // Self scheme is https.
   {
-    Persistent<ContentSecurityPolicy> csp(ContentSecurityPolicy::Create());
+    Persistent<ContentSecurityPolicy> csp(
+        MakeGarbageCollected<ContentSecurityPolicy>());
     csp->SetupSelf(*SecurityOrigin::CreateFromString("https://a.com/"));
     CSPSource source(csp.Get(), "", "a.com", 0, "/", CSPSource::kNoWildcard,
                      CSPSource::kNoWildcard);
@@ -166,7 +168,8 @@
 
   // Self scheme is not in the http familly.
   {
-    Persistent<ContentSecurityPolicy> csp(ContentSecurityPolicy::Create());
+    Persistent<ContentSecurityPolicy> csp(
+        MakeGarbageCollected<ContentSecurityPolicy>());
     csp->SetupSelf(*SecurityOrigin::CreateFromString("ftp://a.com/"));
     CSPSource source(csp.Get(), "", "a.com", 0, "/", CSPSource::kNoWildcard,
                      CSPSource::kNoWildcard);
@@ -176,7 +179,8 @@
 
   // Self scheme is unique
   {
-    Persistent<ContentSecurityPolicy> csp(ContentSecurityPolicy::Create());
+    Persistent<ContentSecurityPolicy> csp(
+        MakeGarbageCollected<ContentSecurityPolicy>());
     csp->SetupSelf(
         *SecurityOrigin::CreateFromString("non-standard-scheme://a.com/"));
     CSPSource source(csp.Get(), "", "a.com", 0, "/", CSPSource::kNoWildcard,
@@ -222,7 +226,8 @@
 
   // source scheme is empty
   {
-    Persistent<ContentSecurityPolicy> csp(ContentSecurityPolicy::Create());
+    Persistent<ContentSecurityPolicy> csp(
+        MakeGarbageCollected<ContentSecurityPolicy>());
     csp->SetupSelf(*SecurityOrigin::CreateFromString("http://example.com"));
     CSPSource source(csp.Get(), "", "example.com", 80, "/",
                      CSPSource::kNoWildcard, CSPSource::kNoWildcard);
@@ -248,7 +253,8 @@
 
 TEST_F(CSPSourceTest, HostMatches) {
   KURL base;
-  Persistent<ContentSecurityPolicy> csp(ContentSecurityPolicy::Create());
+  Persistent<ContentSecurityPolicy> csp(
+      MakeGarbageCollected<ContentSecurityPolicy>());
   csp->SetupSelf(*SecurityOrigin::CreateFromString("http://a.com"));
 
   // Host is * (source-expression = "http://*")
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 5f4384f1..8ffdb2b0 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
@@ -155,7 +155,7 @@
 
   // Construct and route the report to the ReportingContext, to be observed
   // by any ReportingObservers.
-  CSPViolationReportBody* body = CSPViolationReportBody::Create(violation_data);
+  auto* body = MakeGarbageCollected<CSPViolationReportBody>(violation_data);
   Report* observed_report =
       MakeGarbageCollected<Report>("csp-violation", Url().GetString(), body);
   auto* reporting_context = ReportingContext::From(document);
diff --git a/third_party/blink/renderer/core/frame/csp/media_list_directive_test.cc b/third_party/blink/renderer/core/frame/csp/media_list_directive_test.cc
index f86ae3e..1176f045c 100644
--- a/third_party/blink/renderer/core/frame/csp/media_list_directive_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/media_list_directive_test.cc
@@ -11,7 +11,8 @@
 
 class MediaListDirectiveTest : public testing::Test {
  public:
-  MediaListDirectiveTest() : csp(ContentSecurityPolicy::Create()) {}
+  MediaListDirectiveTest()
+      : csp(MakeGarbageCollected<ContentSecurityPolicy>()) {}
 
  protected:
   Persistent<ContentSecurityPolicy> csp;
diff --git a/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc b/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
index 28b4331..4620a31 100644
--- a/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
@@ -18,7 +18,8 @@
 
 class SourceListDirectiveTest : public testing::Test {
  public:
-  SourceListDirectiveTest() : csp(ContentSecurityPolicy::Create()) {}
+  SourceListDirectiveTest()
+      : csp(MakeGarbageCollected<ContentSecurityPolicy>()) {}
 
  protected:
   struct Source {
@@ -45,7 +46,7 @@
         SecurityOrigin::Create(secure_url));
     Document* document = Document::CreateForTest();
     document->SetSecurityOrigin(secure_origin);
-    ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+    auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
     csp->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     return csp;
   }
diff --git a/third_party/blink/renderer/core/frame/dom_timer.h b/third_party/blink/renderer/core/frame/dom_timer.h
index 8d433eb7..d6d2adcb 100644
--- a/third_party/blink/renderer/core/frame/dom_timer.h
+++ b/third_party/blink/renderer/core/frame/dom_timer.h
@@ -79,15 +79,6 @@
  private:
   friend class DOMTimerCoordinator;  // For Create().
 
-  static DOMTimer* Create(ExecutionContext* context,
-                          ScheduledAction* action,
-                          TimeDelta timeout,
-                          bool single_shot,
-                          int timeout_id) {
-    return MakeGarbageCollected<DOMTimer>(context, action, timeout, single_shot,
-                                          timeout_id);
-  }
-
   void Fired() override;
 
   scoped_refptr<base::SingleThreadTaskRunner> TimerTaskRunner() const override;
diff --git a/third_party/blink/renderer/core/frame/dom_timer_coordinator.cc b/third_party/blink/renderer/core/frame/dom_timer_coordinator.cc
index 5e0bd33..5d10ef3 100644
--- a/third_party/blink/renderer/core/frame/dom_timer_coordinator.cc
+++ b/third_party/blink/renderer/core/frame/dom_timer_coordinator.cc
@@ -24,8 +24,9 @@
   // FIXME: DOMTimers depends heavily on ExecutionContext. Decouple them.
   DCHECK_EQ(context->Timers(), this);
   int timeout_id = NextID();
-  timers_.insert(timeout_id, DOMTimer::Create(context, action, timeout,
-                                              single_shot, timeout_id));
+  timers_.insert(timeout_id,
+                 MakeGarbageCollected<DOMTimer>(context, action, timeout,
+                                                single_shot, timeout_id));
   return timeout_id;
 }
 
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc
index bd2a9a1..791af2f 100644
--- a/third_party/blink/renderer/core/frame/dom_window.cc
+++ b/third_party/blink/renderer/core/frame/dom_window.cc
@@ -72,7 +72,7 @@
 
 Location* DOMWindow::location() const {
   if (!location_)
-    location_ = Location::Create(const_cast<DOMWindow*>(this));
+    location_ = MakeGarbageCollected<Location>(const_cast<DOMWindow*>(this));
   return location_.Get();
 }
 
diff --git a/third_party/blink/renderer/core/frame/find_in_page.h b/third_party/blink/renderer/core/frame/find_in_page.h
index 9203f56..5ed7226 100644
--- a/third_party/blink/renderer/core/frame/find_in_page.h
+++ b/third_party/blink/renderer/core/frame/find_in_page.h
@@ -28,11 +28,6 @@
       public mojom::blink::FindInPage {
 
  public:
-  static FindInPage* Create(WebLocalFrameImpl& frame,
-                            InterfaceRegistry* interface_registry) {
-    return MakeGarbageCollected<FindInPage>(frame, interface_registry);
-  }
-
   FindInPage(WebLocalFrameImpl& frame, InterfaceRegistry* interface_registry);
 
   bool FindInternal(int identifier,
diff --git a/third_party/blink/renderer/core/frame/frame_owner.h b/third_party/blink/renderer/core/frame/frame_owner.h
index 6e9974d..810b82e 100644
--- a/third_party/blink/renderer/core/frame/frame_owner.h
+++ b/third_party/blink/renderer/core/frame/frame_owner.h
@@ -86,10 +86,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(DummyFrameOwner);
 
  public:
-  static DummyFrameOwner* Create() {
-    return MakeGarbageCollected<DummyFrameOwner>();
-  }
-
   void Trace(blink::Visitor* visitor) override { FrameOwner::Trace(visitor); }
 
   // FrameOwner overrides:
diff --git a/third_party/blink/renderer/core/frame/link_highlights.h b/third_party/blink/renderer/core/frame/link_highlights.h
index 7dd6fc9..83dcc7d 100644
--- a/third_party/blink/renderer/core/frame/link_highlights.h
+++ b/third_party/blink/renderer/core/frame/link_highlights.h
@@ -33,10 +33,6 @@
 class CORE_EXPORT LinkHighlights final
     : public GarbageCollectedFinalized<LinkHighlights> {
  public:
-  static LinkHighlights* Create(Page& page) {
-    return MakeGarbageCollected<LinkHighlights>(page);
-  }
-
   explicit LinkHighlights(Page&);
   virtual ~LinkHighlights();
 
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 1541c0cf..b8d9d274 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -200,7 +200,7 @@
 
 LocalDOMWindow::LocalDOMWindow(LocalFrame& frame)
     : DOMWindow(frame),
-      visualViewport_(DOMVisualViewport::Create(this)),
+      visualViewport_(MakeGarbageCollected<DOMVisualViewport>(this)),
       unused_preloads_timer_(frame.GetTaskRunner(TaskType::kInternalDefault),
                              this,
                              &LocalDOMWindow::WarnUnusedPreloads),
@@ -462,49 +462,55 @@
 
 Screen* LocalDOMWindow::screen() const {
   if (!screen_)
-    screen_ = Screen::Create(GetFrame());
+    screen_ = MakeGarbageCollected<Screen>(GetFrame());
   return screen_.Get();
 }
 
 History* LocalDOMWindow::history() const {
   if (!history_)
-    history_ = History::Create(GetFrame());
+    history_ = MakeGarbageCollected<History>(GetFrame());
   return history_.Get();
 }
 
 BarProp* LocalDOMWindow::locationbar() const {
-  if (!locationbar_)
-    locationbar_ = BarProp::Create(GetFrame(), BarProp::kLocationbar);
+  if (!locationbar_) {
+    locationbar_ =
+        MakeGarbageCollected<BarProp>(GetFrame(), BarProp::kLocationbar);
+  }
   return locationbar_.Get();
 }
 
 BarProp* LocalDOMWindow::menubar() const {
   if (!menubar_)
-    menubar_ = BarProp::Create(GetFrame(), BarProp::kMenubar);
+    menubar_ = MakeGarbageCollected<BarProp>(GetFrame(), BarProp::kMenubar);
   return menubar_.Get();
 }
 
 BarProp* LocalDOMWindow::personalbar() const {
-  if (!personalbar_)
-    personalbar_ = BarProp::Create(GetFrame(), BarProp::kPersonalbar);
+  if (!personalbar_) {
+    personalbar_ =
+        MakeGarbageCollected<BarProp>(GetFrame(), BarProp::kPersonalbar);
+  }
   return personalbar_.Get();
 }
 
 BarProp* LocalDOMWindow::scrollbars() const {
-  if (!scrollbars_)
-    scrollbars_ = BarProp::Create(GetFrame(), BarProp::kScrollbars);
+  if (!scrollbars_) {
+    scrollbars_ =
+        MakeGarbageCollected<BarProp>(GetFrame(), BarProp::kScrollbars);
+  }
   return scrollbars_.Get();
 }
 
 BarProp* LocalDOMWindow::statusbar() const {
   if (!statusbar_)
-    statusbar_ = BarProp::Create(GetFrame(), BarProp::kStatusbar);
+    statusbar_ = MakeGarbageCollected<BarProp>(GetFrame(), BarProp::kStatusbar);
   return statusbar_.Get();
 }
 
 BarProp* LocalDOMWindow::toolbar() const {
   if (!toolbar_)
-    toolbar_ = BarProp::Create(GetFrame(), BarProp::kToolbar);
+    toolbar_ = MakeGarbageCollected<BarProp>(GetFrame(), BarProp::kToolbar);
   return toolbar_.Get();
 }
 
@@ -528,7 +534,7 @@
 
 Navigator* LocalDOMWindow::navigator() const {
   if (!navigator_)
-    navigator_ = Navigator::Create(GetFrame());
+    navigator_ = MakeGarbageCollected<Navigator>(GetFrame());
   return navigator_.Get();
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index 26c60d8..43cf474 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -100,9 +100,6 @@
   static Document* CreateDocument(const String& mime_type,
                                   const DocumentInit&,
                                   bool force_xhtml);
-  static LocalDOMWindow* Create(LocalFrame& frame) {
-    return MakeGarbageCollected<LocalDOMWindow>(frame);
-  }
 
   static LocalDOMWindow* From(const ScriptState*);
 
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 92958e7..d81513f 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -969,7 +969,7 @@
       spell_checker_(MakeGarbageCollected<SpellChecker>(*this)),
       selection_(MakeGarbageCollected<FrameSelection>(*this)),
       event_handler_(MakeGarbageCollected<EventHandler>(*this)),
-      console_(FrameConsole::Create(*this)),
+      console_(MakeGarbageCollected<FrameConsole>(*this)),
       input_method_controller_(
           MakeGarbageCollected<InputMethodController>(*this)),
       text_suggestion_controller_(
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index f73641c..764bcda5 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -47,7 +47,6 @@
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/platform/web_worker_fetch_context.h"
 #include "third_party/blink/public/web/web_frame_load_type.h"
-#include "third_party/blink/public/web/web_global_object_reuse_policy.h"
 #include "third_party/blink/public/web/web_history_commit_type.h"
 #include "third_party/blink/public/web/web_navigation_params.h"
 #include "third_party/blink/public/web/web_triggering_event_info.h"
@@ -59,6 +58,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/remote_frame.h"
 #include "third_party/blink/renderer/core/html/link_resource.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
 #include "third_party/blink/renderer/core/loader/frame_loader_types.h"
 #include "third_party/blink/renderer/core/loader/navigation_policy.h"
@@ -149,7 +149,7 @@
   virtual void DispatchDidChangeIcons(IconType) = 0;
   virtual void DispatchDidCommitLoad(HistoryItem*,
                                      WebHistoryCommitType,
-                                     WebGlobalObjectReusePolicy) = 0;
+                                     GlobalObjectReusePolicy) = 0;
   virtual void DispatchDidFailProvisionalLoad(const ResourceError&,
                                               WebHistoryCommitType) = 0;
   virtual void DispatchDidFailLoad(const ResourceError&,
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index b2df7a14..f3652120 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -1927,8 +1927,8 @@
     ScrollableArea* layout_viewport = LayoutViewport();
     DCHECK(layout_viewport);
 
-    RootFrameViewport* root_frame_viewport =
-        RootFrameViewport::Create(visual_viewport, *layout_viewport);
+    auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
+        visual_viewport, *layout_viewport);
     viewport_scrollable_area_ = root_frame_viewport;
 
     page->GlobalRootScrollerController().InitializeViewportScrollCallback(
@@ -2911,7 +2911,7 @@
 void LocalFrameView::EnableAutoSizeMode(const IntSize& min_size,
                                         const IntSize& max_size) {
   if (!auto_size_info_)
-    auto_size_info_ = FrameViewAutoSizeInfo::Create(this);
+    auto_size_info_ = MakeGarbageCollected<FrameViewAutoSizeInfo>(this);
 
   auto_size_info_->ConfigureAutoSizeMode(min_size, max_size);
   SetLayoutSizeFixedToFrameSize(true);
diff --git a/third_party/blink/renderer/core/frame/location.h b/third_party/blink/renderer/core/frame/location.h
index 67c5578..29a92b3 100644
--- a/third_party/blink/renderer/core/frame/location.h
+++ b/third_party/blink/renderer/core/frame/location.h
@@ -53,10 +53,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static Location* Create(DOMWindow* dom_window) {
-    return MakeGarbageCollected<Location>(dom_window);
-  }
-
   explicit Location(DOMWindow*);
 
   DOMWindow* DomWindow() const { return dom_window_.Get(); }
diff --git a/third_party/blink/renderer/core/frame/navigator.h b/third_party/blink/renderer/core/frame/navigator.h
index 16ed6e3..4572df0 100644
--- a/third_party/blink/renderer/core/frame/navigator.h
+++ b/third_party/blink/renderer/core/frame/navigator.h
@@ -51,10 +51,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(Navigator);
 
  public:
-  static Navigator* Create(LocalFrame* frame) {
-    return MakeGarbageCollected<Navigator>(frame);
-  }
-
   explicit Navigator(LocalFrame*);
 
   // NavigatorCookies
diff --git a/third_party/blink/renderer/core/frame/page_scale_constraints_set.h b/third_party/blink/renderer/core/frame/page_scale_constraints_set.h
index 6144ae4..d6ceb96 100644
--- a/third_party/blink/renderer/core/frame/page_scale_constraints_set.h
+++ b/third_party/blink/renderer/core/frame/page_scale_constraints_set.h
@@ -51,11 +51,7 @@
 class CORE_EXPORT PageScaleConstraintsSet
     : public GarbageCollected<PageScaleConstraintsSet> {
  public:
-  static PageScaleConstraintsSet* Create(Page* page) {
-    return MakeGarbageCollected<PageScaleConstraintsSet>(page);
-  }
-
-  PageScaleConstraintsSet(Page* page);
+  explicit PageScaleConstraintsSet(Page* page);
 
   void Trace(blink::Visitor*);
 
diff --git a/third_party/blink/renderer/core/frame/remote_dom_window.h b/third_party/blink/renderer/core/frame/remote_dom_window.h
index 52f1eb4..e2fd60c8 100644
--- a/third_party/blink/renderer/core/frame/remote_dom_window.h
+++ b/third_party/blink/renderer/core/frame/remote_dom_window.h
@@ -13,10 +13,6 @@
 
 class RemoteDOMWindow final : public DOMWindow {
  public:
-  static RemoteDOMWindow* Create(RemoteFrame& frame) {
-    return MakeGarbageCollected<RemoteDOMWindow>(frame);
-  }
-
   explicit RemoteDOMWindow(RemoteFrame&);
 
   RemoteFrame* GetFrame() const {
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index 4410ff0..abf81467 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -35,7 +35,7 @@
             owner,
             MakeGarbageCollected<RemoteWindowProxyManager>(*this)),
       security_context_(MakeGarbageCollected<RemoteSecurityContext>()) {
-  dom_window_ = RemoteDOMWindow::Create(*this);
+  dom_window_ = MakeGarbageCollected<RemoteDOMWindow>(*this);
   UpdateInertIfPossible();
   UpdateInheritedEffectiveTouchActionIfPossible();
 }
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc b/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
index 2adb7d4..14a665e0 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
@@ -39,11 +39,6 @@
 RemoteFrameClientImpl::RemoteFrameClientImpl(WebRemoteFrameImpl* web_frame)
     : web_frame_(web_frame) {}
 
-RemoteFrameClientImpl* RemoteFrameClientImpl::Create(
-    WebRemoteFrameImpl* web_frame) {
-  return MakeGarbageCollected<RemoteFrameClientImpl>(web_frame);
-}
-
 void RemoteFrameClientImpl::Trace(blink::Visitor* visitor) {
   visitor->Trace(web_frame_);
   RemoteFrameClient::Trace(visitor);
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client_impl.h b/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
index 1a3f706..a9bb305 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
@@ -16,8 +16,6 @@
 
 class RemoteFrameClientImpl final : public RemoteFrameClient {
  public:
-  static RemoteFrameClientImpl* Create(WebRemoteFrameImpl*);
-
   explicit RemoteFrameClientImpl(WebRemoteFrameImpl*);
 
   void Trace(blink::Visitor*) override;
diff --git a/third_party/blink/renderer/core/frame/remote_frame_owner.h b/third_party/blink/renderer/core/frame/remote_frame_owner.h
index 040cbe3d3..550622c 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_owner.h
+++ b/third_party/blink/renderer/core/frame/remote_frame_owner.h
@@ -25,16 +25,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(RemoteFrameOwner);
 
  public:
-  static RemoteFrameOwner* Create(
-      SandboxFlags flags,
-      const ParsedFeaturePolicy& container_policy,
-      const WebFrameOwnerProperties& frame_owner_properties,
-      FrameOwnerElementType frame_owner_element_type) {
-    return MakeGarbageCollected<RemoteFrameOwner>(flags, container_policy,
-                                                  frame_owner_properties,
-                                                  frame_owner_element_type);
-  }
-
   RemoteFrameOwner(SandboxFlags,
                    const ParsedFeaturePolicy&,
                    const WebFrameOwnerProperties&,
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport.h b/third_party/blink/renderer/core/frame/root_frame_viewport.h
index 372f4360d..ca4c8067 100644
--- a/third_party/blink/renderer/core/frame/root_frame_viewport.h
+++ b/third_party/blink/renderer/core/frame/root_frame_viewport.h
@@ -32,12 +32,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(RootFrameViewport);
 
  public:
-  static RootFrameViewport* Create(ScrollableArea& visual_viewport,
-                                   ScrollableArea& layout_viewport) {
-    return MakeGarbageCollected<RootFrameViewport>(visual_viewport,
-                                                   layout_viewport);
-  }
-
   RootFrameViewport(ScrollableArea& visual_viewport,
                     ScrollableArea& layout_viewport);
 
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc b/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
index f33f50e..1dc4b023 100644
--- a/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
+++ b/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
@@ -29,12 +29,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(ScrollableAreaStub);
 
  public:
-  static ScrollableAreaStub* Create(const IntSize& viewport_size,
-                                    const IntSize& contents_size) {
-    return MakeGarbageCollected<ScrollableAreaStub>(viewport_size,
-                                                    contents_size);
-  }
-
   ScrollableAreaStub(const IntSize& viewport_size, const IntSize& contents_size)
       : user_input_scrollable_x_(true),
         user_input_scrollable_y_(true),
@@ -142,12 +136,6 @@
 
 class RootLayoutViewportStub : public ScrollableAreaStub {
  public:
-  static RootLayoutViewportStub* Create(const IntSize& viewport_size,
-                                        const IntSize& contents_size) {
-    return MakeGarbageCollected<RootLayoutViewportStub>(viewport_size,
-                                                        contents_size);
-  }
-
   RootLayoutViewportStub(const IntSize& viewport_size,
                          const IntSize& contents_size)
       : ScrollableAreaStub(viewport_size, contents_size) {}
@@ -169,12 +157,6 @@
 
 class VisualViewportStub : public ScrollableAreaStub {
  public:
-  static VisualViewportStub* Create(const IntSize& viewport_size,
-                                    const IntSize& contents_size) {
-    return MakeGarbageCollected<VisualViewportStub>(viewport_size,
-                                                    contents_size);
-  }
-
   VisualViewportStub(const IntSize& viewport_size, const IntSize& contents_size)
       : ScrollableAreaStub(viewport_size, contents_size), scale_(1) {}
 
@@ -216,13 +198,13 @@
 // correctly, that is, the visual viewport can scroll, but not the layout.
 TEST_F(RootFrameViewportTest, UserInputScrollable) {
   IntSize viewport_size(100, 150);
-  RootLayoutViewportStub* layout_viewport =
-      RootLayoutViewportStub::Create(viewport_size, IntSize(200, 300));
-  VisualViewportStub* visual_viewport =
-      VisualViewportStub::Create(viewport_size, viewport_size);
+  auto* layout_viewport = MakeGarbageCollected<RootLayoutViewportStub>(
+      viewport_size, IntSize(200, 300));
+  auto* visual_viewport =
+      MakeGarbageCollected<VisualViewportStub>(viewport_size, viewport_size);
 
-  ScrollableArea* root_frame_viewport =
-      RootFrameViewport::Create(*visual_viewport, *layout_viewport);
+  auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
+      *visual_viewport, *layout_viewport);
 
   visual_viewport->SetScale(2);
 
@@ -279,13 +261,13 @@
 // using the // RootFrameViewport interface.
 TEST_F(RootFrameViewportTest, TestScrollAnimatorUpdatedBeforeScroll) {
   IntSize viewport_size(100, 150);
-  RootLayoutViewportStub* layout_viewport =
-      RootLayoutViewportStub::Create(viewport_size, IntSize(200, 300));
-  VisualViewportStub* visual_viewport =
-      VisualViewportStub::Create(viewport_size, viewport_size);
+  auto* layout_viewport = MakeGarbageCollected<RootLayoutViewportStub>(
+      viewport_size, IntSize(200, 300));
+  auto* visual_viewport =
+      MakeGarbageCollected<VisualViewportStub>(viewport_size, viewport_size);
 
-  ScrollableArea* root_frame_viewport =
-      RootFrameViewport::Create(*visual_viewport, *layout_viewport);
+  auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
+      *visual_viewport, *layout_viewport);
 
   visual_viewport->SetScale(2);
 
@@ -320,13 +302,13 @@
 // and visual viewport such that the given rect is centered in the viewport.
 TEST_F(RootFrameViewportTest, ScrollIntoView) {
   IntSize viewport_size(100, 150);
-  RootLayoutViewportStub* layout_viewport =
-      RootLayoutViewportStub::Create(viewport_size, IntSize(200, 300));
-  VisualViewportStub* visual_viewport =
-      VisualViewportStub::Create(viewport_size, viewport_size);
+  auto* layout_viewport = MakeGarbageCollected<RootLayoutViewportStub>(
+      viewport_size, IntSize(200, 300));
+  auto* visual_viewport =
+      MakeGarbageCollected<VisualViewportStub>(viewport_size, viewport_size);
 
-  ScrollableArea* root_frame_viewport =
-      RootFrameViewport::Create(*visual_viewport, *layout_viewport);
+  auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
+      *visual_viewport, *layout_viewport);
 
   // Test that the visual viewport is scrolled if the viewport has been
   // resized (as is the case when the ChromeOS keyboard comes up) but not
@@ -414,13 +396,13 @@
 // Tests that the setScrollOffset method works correctly with both viewports.
 TEST_F(RootFrameViewportTest, SetScrollOffset) {
   IntSize viewport_size(500, 500);
-  RootLayoutViewportStub* layout_viewport =
-      RootLayoutViewportStub::Create(viewport_size, IntSize(1000, 2000));
-  VisualViewportStub* visual_viewport =
-      VisualViewportStub::Create(viewport_size, viewport_size);
+  auto* layout_viewport = MakeGarbageCollected<RootLayoutViewportStub>(
+      viewport_size, IntSize(1000, 2000));
+  auto* visual_viewport =
+      MakeGarbageCollected<VisualViewportStub>(viewport_size, viewport_size);
 
-  ScrollableArea* root_frame_viewport =
-      RootFrameViewport::Create(*visual_viewport, *layout_viewport);
+  auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
+      *visual_viewport, *layout_viewport);
 
   visual_viewport->SetScale(2);
 
@@ -454,13 +436,13 @@
 // calculated, taking into account both viewports and page scale.
 TEST_F(RootFrameViewportTest, VisibleContentRect) {
   IntSize viewport_size(500, 401);
-  RootLayoutViewportStub* layout_viewport =
-      RootLayoutViewportStub::Create(viewport_size, IntSize(1000, 2000));
-  VisualViewportStub* visual_viewport =
-      VisualViewportStub::Create(viewport_size, viewport_size);
+  auto* layout_viewport = MakeGarbageCollected<RootLayoutViewportStub>(
+      viewport_size, IntSize(1000, 2000));
+  auto* visual_viewport =
+      MakeGarbageCollected<VisualViewportStub>(viewport_size, viewport_size);
 
-  ScrollableArea* root_frame_viewport =
-      RootFrameViewport::Create(*visual_viewport, *layout_viewport);
+  auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
+      *visual_viewport, *layout_viewport);
 
   root_frame_viewport->SetScrollOffset(ScrollOffset(100, 75),
                                        kProgrammaticScroll);
@@ -482,13 +464,13 @@
 // trying to scroll the layout viewport.
 TEST_F(RootFrameViewportTest, ViewportScrollOrder) {
   IntSize viewport_size(100, 100);
-  RootLayoutViewportStub* layout_viewport =
-      RootLayoutViewportStub::Create(viewport_size, IntSize(200, 300));
-  VisualViewportStub* visual_viewport =
-      VisualViewportStub::Create(viewport_size, viewport_size);
+  auto* layout_viewport = MakeGarbageCollected<RootLayoutViewportStub>(
+      viewport_size, IntSize(200, 300));
+  auto* visual_viewport =
+      MakeGarbageCollected<VisualViewportStub>(viewport_size, viewport_size);
 
-  ScrollableArea* root_frame_viewport =
-      RootFrameViewport::Create(*visual_viewport, *layout_viewport);
+  auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
+      *visual_viewport, *layout_viewport);
 
   visual_viewport->SetScale(2);
 
@@ -506,16 +488,16 @@
 // instead of the original.
 TEST_F(RootFrameViewportTest, SetAlternateLayoutViewport) {
   IntSize viewport_size(100, 100);
-  RootLayoutViewportStub* layout_viewport =
-      RootLayoutViewportStub::Create(viewport_size, IntSize(200, 300));
-  VisualViewportStub* visual_viewport =
-      VisualViewportStub::Create(viewport_size, viewport_size);
+  auto* layout_viewport = MakeGarbageCollected<RootLayoutViewportStub>(
+      viewport_size, IntSize(200, 300));
+  auto* visual_viewport =
+      MakeGarbageCollected<VisualViewportStub>(viewport_size, viewport_size);
 
-  RootLayoutViewportStub* alternate_scroller =
-      RootLayoutViewportStub::Create(viewport_size, IntSize(600, 500));
+  auto* alternate_scroller = MakeGarbageCollected<RootLayoutViewportStub>(
+      viewport_size, IntSize(600, 500));
 
-  RootFrameViewport* root_frame_viewport =
-      RootFrameViewport::Create(*visual_viewport, *layout_viewport);
+  auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
+      *visual_viewport, *layout_viewport);
 
   visual_viewport->SetScale(2);
 
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.h b/third_party/blink/renderer/core/frame/visual_viewport.h
index 5c08f473..55a0802 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.h
+++ b/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -95,10 +95,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(VisualViewport);
 
  public:
-  static VisualViewport* Create(Page& host) {
-    return MakeGarbageCollected<VisualViewport>(host);
-  }
-
   explicit VisualViewport(Page&);
   ~VisualViewport() override;
 
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
index 4f1805f..d165254 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -106,13 +106,6 @@
   return WebRect();
 }
 
-void WebFrameWidgetBase::UpdateAllLifecyclePhasesAndCompositeForTesting(
-    bool do_raster) {
-  if (WebLayerTreeView* layer_tree_view = GetLayerTreeView()) {
-    layer_tree_view->UpdateAllLifecyclePhasesAndCompositeForTesting(do_raster);
-  }
-}
-
 WebDragOperation WebFrameWidgetBase::DragTargetDragEnter(
     const WebDragData& web_drag_data,
     const WebFloatPoint& point_in_viewport,
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.h b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
index a389e8da..3cfbd1c 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.h
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
@@ -84,7 +84,6 @@
   // WebFrameWidget implementation.
   void Close() override;
   WebLocalFrame* LocalRoot() const override;
-  void UpdateAllLifecyclePhasesAndCompositeForTesting(bool do_raster) override;
   WebDragOperation DragTargetDragEnter(const WebDragData&,
                                        const WebFloatPoint& point_in_viewport,
                                        const WebFloatPoint& screen_point,
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index 83ee15a5..f82902b 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -138,17 +138,11 @@
 
   // Note: this isn't a leak, as the object has a self-reference that the
   // caller needs to release by calling Close().
-  WebFrameWidgetBase* widget = WebFrameWidgetImpl::Create(*client);
+  auto* widget = MakeGarbageCollected<WebFrameWidgetImpl>(*client);
   widget->BindLocalRoot(*local_root);
   return widget;
 }
 
-WebFrameWidgetImpl* WebFrameWidgetImpl::Create(WebWidgetClient& client) {
-  // Pass the WebFrameWidgetImpl's self-reference from SelfKeepAlive to the
-  // caller.
-  return MakeGarbageCollected<WebFrameWidgetImpl>(client);
-}
-
 WebFrameWidgetImpl::WebFrameWidgetImpl(WebWidgetClient& client)
     : WebFrameWidgetBase(client),
       self_keep_alive_(this) {}
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
index 23ddac1..86fa54f 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -69,8 +69,6 @@
 class WebFrameWidgetImpl final : public WebFrameWidgetBase,
                                  public PageWidgetEventHandler {
  public:
-  static WebFrameWidgetImpl* Create(WebWidgetClient&);
-
   explicit WebFrameWidgetImpl(WebWidgetClient&);
   ~WebFrameWidgetImpl() override;
 
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 0f463bf..67e67d91b 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
@@ -1685,7 +1685,7 @@
   // observable, it will have the real FrameOwner, and any subsequent real
   // documents will correctly inherit sandbox flags from the owner.
   web_frame->InitializeCoreFrame(*previous_frame->GetPage(),
-                                 DummyFrameOwner::Create(),
+                                 MakeGarbageCollected<DummyFrameOwner>(),
                                  previous_frame->Tree().GetName());
 
   LocalFrame* new_frame = web_frame->GetFrame();
@@ -1730,7 +1730,8 @@
           this,
           std::move(document_interface_broker_handle))),
       autofill_client_(nullptr),
-      find_in_page_(FindInPage::Create(*this, interface_registry)),
+      find_in_page_(
+          MakeGarbageCollected<FindInPage>(*this, interface_registry)),
       interface_registry_(interface_registry),
       input_method_controller_(*this),
       spell_check_panel_host_client_(nullptr),
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.cc b/third_party/blink/renderer/core/html/forms/file_input_type.cc
index 9e2cc4f..50f8f66 100644
--- a/third_party/blink/renderer/core/html/forms/file_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -70,7 +70,7 @@
 inline FileInputType::FileInputType(HTMLInputElement& element)
     : InputType(element),
       KeyboardClickableInputTypeView(element),
-      file_list_(FileList::Create()) {}
+      file_list_(MakeGarbageCollected<FileList>()) {}
 
 InputType* FileInputType::Create(HTMLInputElement& element) {
   return MakeGarbageCollected<FileInputType>(element);
@@ -124,7 +124,7 @@
   HeapVector<Member<File>> file_vector =
       CreateFilesFrom<File*, HeapVector<Member<File>>>(
           state, &File::CreateFromControlState);
-  FileList* file_list = FileList::Create();
+  auto* file_list = MakeGarbageCollected<FileList>();
   for (const auto& file : file_vector)
     file_list->Append(file);
   SetFilesAndDispatchEvents(file_list);
@@ -252,7 +252,7 @@
 
 FileList* FileInputType::CreateFileList(const FileChooserFileInfoList& files,
                                         const base::FilePath& base_dir) {
-  FileList* file_list(FileList::Create());
+  auto* file_list(MakeGarbageCollected<FileList>());
   wtf_size_t size = files.size();
 
   // If a directory is being selected, the UI allows a directory to be chosen
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index 7d6723a1..682b5a5f2 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -76,6 +76,47 @@
   return containing_frame_owner->ShouldLazyLoadChildren();
 }
 
+bool IsFrameLazyLoadable(Document& document,
+                         const KURL& url,
+                         bool is_load_attr_lazy,
+                         bool should_lazy_load_children) {
+  if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled() &&
+      !RuntimeEnabledFeatures::LazyFrameVisibleLoadTimeMetricsEnabled()) {
+    return false;
+  }
+
+  // Only http:// or https:// URLs are eligible for lazy loading, excluding
+  // URLs like invalid or empty URLs, "about:blank", local file URLs, etc.
+  // that it doesn't make sense to lazily load.
+  if (!url.ProtocolIsInHTTPFamily())
+    return false;
+
+  if (is_load_attr_lazy)
+    return true;
+
+  if (!should_lazy_load_children ||
+      // Disallow lazy loading by default if javascript in the embedding
+      // document would be able to access the contents of the frame, since in
+      // those cases deferring the frame could break the page. Note that this
+      // check does not take any possible redirects of |url| into account.
+      document.GetSecurityOrigin()->CanAccess(
+          SecurityOrigin::Create(url).get())) {
+    return false;
+  }
+
+  // If lazy loading is restricted to only Data Saver users, then avoid
+  // lazy loading unless Data Saver is enabled, taking the Data Saver
+  // holdback into consideration.
+  if (RuntimeEnabledFeatures::RestrictLazyFrameLoadingToDataSaverEnabled() &&
+      ((document.GetSettings() &&
+        document.GetSettings()->GetDataSaverHoldbackWebApi()) ||
+       !GetNetworkStateNotifier().SaveDataEnabled())) {
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace
 
 SubframeLoadingDisabler::SubtreeRootSet&
@@ -409,29 +450,11 @@
   if (IsPlugin())
     request.SetSkipServiceWorker(true);
 
-  if ((RuntimeEnabledFeatures::LazyFrameLoadingEnabled() ||
-       RuntimeEnabledFeatures::LazyFrameVisibleLoadTimeMetricsEnabled()) &&
-      !lazy_load_frame_observer_ &&
-      // Only http:// or https:// URLs are eligible for lazy loading, excluding
-      // URLs like invalid or empty URLs, "about:blank", local file URLs, etc.
-      // that it doesn't make sense to lazily load.
-      url.ProtocolIsInHTTPFamily() &&
-      (EqualIgnoringASCIICase(FastGetAttribute(html_names::kLoadAttr),
-                              "lazy") ||
-       (should_lazy_load_children_ &&
-        // Disallow lazy loading by default if javascript in the embedding
-        // document would be able to access the contents of the frame, since in
-        // those cases deferring the frame could break the page. Note that this
-        // check does not take any possible redirects of |url| into account.
-        !GetDocument().GetSecurityOrigin()->CanAccess(
-            SecurityOrigin::Create(url).get()))) &&
-      // If lazy loading is restricted to only Data Saver users, then avoid
-      // lazy loading unless Data Saver is enabled, taking the Data Saver
-      // holdback into consideration.
-      (!RuntimeEnabledFeatures::RestrictLazyFrameLoadingToDataSaverEnabled() ||
-       (!(GetDocument().GetSettings() &&
-          GetDocument().GetSettings()->GetDataSaverHoldbackWebApi()) &&
-        GetNetworkStateNotifier().SaveDataEnabled()))) {
+  if (!lazy_load_frame_observer_ &&
+      IsFrameLazyLoadable(GetDocument(), url,
+                          EqualIgnoringASCIICase(
+                              FastGetAttribute(html_names::kLoadAttr), "lazy"),
+                          should_lazy_load_children_)) {
     // By default, avoid deferring subresources inside a lazily loaded frame.
     // This will make it possible for subresources in hidden frames to load that
     // will never be visible, as well as make it so that deferred frames that
diff --git a/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc b/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
index 41dba9f..ebff844 100644
--- a/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
+++ b/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
@@ -1231,6 +1231,7 @@
 
   GetNetworkStateNotifier().SetSaveDataEnabled(true);
   WebView().GetPage()->GetSettings().SetDataSaverHoldbackWebApi(true);
+  TestCrossOriginFrameIsLazilyLoaded("load='lazy'");
   TestCrossOriginFrameIsImmediatelyLoaded("");
 }
 
@@ -1251,7 +1252,10 @@
 
   GetNetworkStateNotifier().SetSaveDataEnabled(false);
   WebView().GetPage()->GetSettings().SetDataSaverHoldbackWebApi(false);
-  TestCrossOriginFrameIsImmediatelyLoaded("load='lazy'");
+
+  // Even when restricted to data saver, the attribute should be respected.
+  TestCrossOriginFrameIsLazilyLoaded("load='lazy'");
+  TestCrossOriginFrameIsImmediatelyLoaded("");
 }
 
 }  // namespace
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 b5f726c..c9b55ed 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
@@ -150,7 +150,7 @@
         referrer_policy_(network::mojom::ReferrerPolicy::kDefault),
         integrity_attr_set_(false),
         integrity_features_(features),
-        lazyload_attr_set_to_off_(false),
+        load_attr_value_(LoadAttrValue::kAuto),
         width_attr_small_absolute_(false),
         height_attr_small_absolute_(false),
         inline_style_dimensions_small_(false),
@@ -288,12 +288,13 @@
     request->SetCharset(Charset());
     request->SetDefer(defer_);
 
-    // If the 'lazyload' feature policy is enforced, the attribute value "off"
-    // for the 'lazyload' attribute is considered as 'auto'.
-    if ((lazyload_attr_set_to_off_ &&
-         !document_parameters.lazyload_policy_enforced) ||
-        (width_attr_small_absolute_ && height_attr_small_absolute_) ||
-        inline_style_dimensions_small_) {
+    // If the 'lazyload' feature policy is enforced, the attribute value "lazy"
+    // for the 'load' attribute is considered as 'auto'.
+    if (load_attr_value_ != LoadAttrValue::kLazy &&
+        ((load_attr_value_ == LoadAttrValue::kEager &&
+          !document_parameters.lazyload_policy_enforced) ||
+         (width_attr_small_absolute_ && height_attr_small_absolute_) ||
+         inline_style_dimensions_small_)) {
       request->SetIsLazyloadImageDisabled(true);
     }
 
@@ -309,6 +310,8 @@
   }
 
  private:
+  enum class LoadAttrValue { kAuto, kLazy, kEager };
+
   template <typename NameType>
   void ProcessScriptAttribute(const NameType& attribute_name,
                               const String& attribute_value) {
@@ -365,10 +368,14 @@
                Match(attribute_name, kImportanceAttr) &&
                priority_hints_origin_trial_enabled_) {
       SetImportance(attribute_value);
-    } else if (!lazyload_attr_set_to_off_ && Match(attribute_name, kLoadAttr) &&
-               RuntimeEnabledFeatures::LazyImageLoadingEnabled() &&
-               EqualIgnoringASCIICase(attribute_value, "eager")) {
-      lazyload_attr_set_to_off_ = true;
+    } else if (load_attr_value_ == LoadAttrValue::kAuto &&
+               Match(attribute_name, kLoadAttr) &&
+               RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
+      load_attr_value_ = EqualIgnoringASCIICase(attribute_value, "eager")
+                             ? LoadAttrValue::kEager
+                             : EqualIgnoringASCIICase(attribute_value, "lazy")
+                                   ? LoadAttrValue::kLazy
+                                   : LoadAttrValue::kAuto;
     } else if (!width_attr_small_absolute_ &&
                Match(attribute_name, kWidthAttr) &&
                RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
@@ -690,7 +697,7 @@
   bool integrity_attr_set_;
   IntegrityMetadataSet integrity_metadata_;
   SubresourceIntegrity::IntegrityFeatures integrity_features_;
-  bool lazyload_attr_set_to_off_;
+  LoadAttrValue load_attr_value_;
   bool width_attr_small_absolute_;
   bool height_attr_small_absolute_;
   bool inline_style_dimensions_small_;
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
index 929efa6..6131a3f 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
@@ -1228,4 +1228,19 @@
     Test(test_case);
 }
 
+TEST_F(HTMLPreloadScannerTest, LazyImageLoadAttributePassed) {
+  ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test(true);
+  LazyImageLoadTestCase test_cases[] = {
+      {"<img src='foo.jpg' load='auto'>", false},
+      {"<img src='foo.jpg' load='lazy'>", false},
+      {"<img src='foo.jpg' load='eager'>", true},
+      // load=lazy should override other conditions.
+      {"<img src='foo.jpg' style='height: 1px;' load='lazy'>", false},
+      {"<img src='foo.jpg' style='height: 1px; width: 1px' load='lazy'>",
+       false},
+  };
+  for (const auto& test_case : test_cases)
+    Test(test_case);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc b/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc
index e32b7d8..32cd93c 100644
--- a/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_application_cache_agent.cc
@@ -169,7 +169,7 @@
     const ApplicationCacheHost::CacheInfo& application_cache_info) {
   return protocol::ApplicationCache::ApplicationCache::create()
       .setManifestURL(application_cache_info.manifest_.GetString())
-      .setSize(application_cache_info.size_)
+      .setSize(application_cache_info.response_sizes_)
       .setCreationTime(application_cache_info.creation_time_)
       .setUpdateTime(application_cache_info.update_time_)
       .setResources(
@@ -218,7 +218,7 @@
   std::unique_ptr<protocol::ApplicationCache::ApplicationCacheResource> value =
       protocol::ApplicationCache::ApplicationCacheResource::create()
           .setUrl(resource_info.resource_.GetString())
-          .setSize(static_cast<int>(resource_info.size_))
+          .setSize(static_cast<int>(resource_info.response_size_))
           .setType(builder.ToString())
           .build();
   return value;
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index 4935335..de9b41aa 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -648,21 +648,24 @@
     // is outside the spanner but inside the multicol container.
     return;
   }
-  // FIXME: Technically percentage height objects only need a relayout if their
-  // percentage isn't going to be turned into an auto value. Add a method to
-  // determine this, so that we can avoid the relayout.
-  bool has_relative_logical_height =
-      child.HasRelativeLogicalHeight() ||
-      (child.IsAnonymous() && HasRelativeLogicalHeight()) ||
-      child.StretchesToViewport();
-  if (relayout_children || (has_relative_logical_height && !IsLayoutView()) ||
-      (height_available_to_children_changed_ &&
-       ChangeInAvailableLogicalHeightAffectsChild(this, child)) ||
-      (child.IsListMarker() && IsListItem() &&
-       ToLayoutBlockFlow(this)->ContainsFloats())) {
-    // TODO(cbiesinger): Should be child.SetSelfNeedsLayoutForAvailableSpace,
-    // but that makes tests fail.
+
+  if (relayout_children) {
     child.SetChildNeedsLayout(kMarkOnlyThis);
+  } else {
+    // FIXME: Technically percentage height objects only need a relayout if
+    // their percentage isn't going to be turned into an auto value. Add a
+    // method to determine this, so that we can avoid the relayout.
+    bool has_relative_logical_height =
+        child.HasRelativeLogicalHeight() ||
+        (child.IsAnonymous() && HasRelativeLogicalHeight()) ||
+        child.StretchesToViewport();
+    if ((has_relative_logical_height && !IsLayoutView()) ||
+        (height_available_to_children_changed_ &&
+         ChangeInAvailableLogicalHeightAffectsChild(this, child)) ||
+        (child.IsListMarker() && IsListItem() &&
+         ToLayoutBlockFlow(this)->ContainsFloats())) {
+      child.SetSelfNeedsLayoutForAvailableSpace(true);
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.cc b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
index f7476abf..0997851 100644
--- a/third_party/blink/renderer/core/layout/line/inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
@@ -519,10 +519,6 @@
     const Font& font) const {
   InlineTextBoxPainter(*this).PaintTextMatchMarkerForeground(
       paint_info, box_origin, marker, style, font);
-  if (GetLineLayoutItem().ContainsOnlyWhitespaceOrNbsp() !=
-      OnlyWhitespaceOrNbsp::kYes) {
-    paint_info.context.GetPaintController().SetTextPainted();
-  }
 }
 
 void InlineTextBox::PaintTextMatchMarkerBackground(
diff --git a/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc b/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
index f6b9fcce..3b5e8e0 100644
--- a/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
+++ b/third_party/blink/renderer/core/loader/appcache/application_cache_host.cc
@@ -211,12 +211,13 @@
 
 ApplicationCacheHost::CacheInfo ApplicationCacheHost::ApplicationCacheInfo() {
   if (!host_)
-    return CacheInfo(NullURL(), 0, 0, 0);
+    return CacheInfo(NullURL(), 0, 0, 0, 0);
 
   WebApplicationCacheHost::CacheInfo web_info;
   host_->GetAssociatedCacheInfo(&web_info);
   return CacheInfo(web_info.manifest_url, web_info.creation_time,
-                   web_info.update_time, web_info.total_size);
+                   web_info.update_time, web_info.response_sizes,
+                   web_info.padding_sizes);
 }
 
 int ApplicationCacheHost::GetHostID() const {
@@ -232,11 +233,11 @@
   WebVector<WebApplicationCacheHost::ResourceInfo> web_resources;
   host_->GetResourceList(&web_resources);
   for (size_t i = 0; i < web_resources.size(); ++i) {
-    resources->push_back(
-        ResourceInfo(web_resources[i].url, web_resources[i].is_master,
-                     web_resources[i].is_manifest, web_resources[i].is_fallback,
-                     web_resources[i].is_foreign, web_resources[i].is_explicit,
-                     web_resources[i].size));
+    resources->push_back(ResourceInfo(
+        web_resources[i].url, web_resources[i].is_master,
+        web_resources[i].is_manifest, web_resources[i].is_fallback,
+        web_resources[i].is_foreign, web_resources[i].is_explicit,
+        web_resources[i].response_size, web_resources[i].padding_size));
   }
 }
 
diff --git a/third_party/blink/renderer/core/loader/appcache/application_cache_host.h b/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
index f806dcba..d6bf721 100644
--- a/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
+++ b/third_party/blink/renderer/core/loader/appcache/application_cache_host.h
@@ -68,15 +68,18 @@
     CacheInfo(const KURL& manifest,
               double creation_time,
               double update_time,
-              int64_t size)
+              int64_t response_sizes,
+              int64_t padding_sizes)
         : manifest_(manifest),
           creation_time_(creation_time),
           update_time_(update_time),
-          size_(size) {}
+          response_sizes_(response_sizes),
+          padding_sizes_(padding_sizes) {}
     KURL manifest_;
     double creation_time_;
     double update_time_;
-    int64_t size_;
+    int64_t response_sizes_;
+    int64_t padding_sizes_;
   };
 
   struct ResourceInfo {
@@ -87,21 +90,24 @@
                  bool is_fallback,
                  bool is_foreign,
                  bool is_explicit,
-                 int64_t size)
+                 int64_t response_size,
+                 int64_t padding_size)
         : resource_(resource),
           is_master_(is_master),
           is_manifest_(is_manifest),
           is_fallback_(is_fallback),
           is_foreign_(is_foreign),
           is_explicit_(is_explicit),
-          size_(size) {}
+          response_size_(response_size),
+          padding_size_(padding_size) {}
     KURL resource_;
     bool is_master_;
     bool is_manifest_;
     bool is_fallback_;
     bool is_foreign_;
     bool is_explicit_;
-    int64_t size_;
+    int64_t response_size_;
+    int64_t padding_size_;
   };
 
   typedef Vector<ResourceInfo> ResourceInfoList;
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index bc64b12..c6a68ec 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -585,6 +585,8 @@
   WebHistoryCommitType history_commit_type = LoadTypeToCommitType(load_type_);
   switch (state_) {
     case kNotStarted:
+      FALLTHROUGH;
+    case kProvisional:
       state_ = kSentDidFinishLoad;
       GetLocalFrameClient().DispatchDidFailProvisionalLoad(error,
                                                            history_commit_type);
@@ -600,8 +602,6 @@
       GetFrameLoader().DidFinishNavigation();
       break;
     case kSentDidFinishLoad:
-      FALLTHROUGH;
-    case kProvisional:
       NOTREACHED();
       break;
   }
@@ -738,7 +738,7 @@
 ContentSecurityPolicy* DocumentLoader::CreateCSP(
     const ResourceResponse& response,
     const String& origin_policy_string) {
-  ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+  auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
   csp->SetOverrideURLForSelf(response.CurrentRequestUrl());
 
   if (!frame_->GetSettings()->BypassCSP()) {
@@ -775,7 +775,7 @@
                                     kContentSecurityPolicyHeaderTypeEnforce,
                                     kContentSecurityPolicyHeaderSourceHTTP);
     } else {
-      ContentSecurityPolicy* required_csp = ContentSecurityPolicy::Create();
+      auto* required_csp = MakeGarbageCollected<ContentSecurityPolicy>();
       required_csp->AddPolicyFromHeaderValue(
           GetFrameLoader().RequiredCSP(),
           kContentSecurityPolicyHeaderTypeEnforce,
@@ -870,8 +870,8 @@
   InstallNewDocument(Url(), initiator_origin, owner_document,
                      GetFrameLoader().ShouldReuseDefaultView(
                          Url(), content_security_policy_.Get())
-                         ? WebGlobalObjectReusePolicy::kUseExisting
-                         : WebGlobalObjectReusePolicy::kCreateNew,
+                         ? GlobalObjectReusePolicy::kUseExisting
+                         : GlobalObjectReusePolicy::kCreateNew,
                      mime_type, encoding, InstallNewDocumentReason::kNavigation,
                      parsing_policy, overriding_url);
   parser_->SetDocumentWasLoadedAsPartOfNavigation();
@@ -1300,7 +1300,7 @@
 }
 
 void DocumentLoader::DidCommitNavigation(
-    WebGlobalObjectReusePolicy global_object_reuse_policy) {
+    GlobalObjectReusePolicy global_object_reuse_policy) {
   if (GetFrameLoader().StateMachine()->CreatingInitialEmptyDocument())
     return;
 
@@ -1400,7 +1400,7 @@
     const KURL& url,
     const scoped_refptr<const SecurityOrigin> initiator_origin,
     Document* owner_document,
-    WebGlobalObjectReusePolicy global_object_reuse_policy,
+    GlobalObjectReusePolicy global_object_reuse_policy,
     const AtomicString& mime_type,
     const AtomicString& encoding,
     InstallNewDocumentReason reason,
@@ -1426,8 +1426,8 @@
   // commits. To make that happen, we "securely transition" the existing
   // LocalDOMWindow to the Document that results from the network load. See also
   // Document::IsSecureTransitionTo.
-  if (global_object_reuse_policy != WebGlobalObjectReusePolicy::kUseExisting)
-    frame_->SetDOMWindow(LocalDOMWindow::Create(*frame_));
+  if (global_object_reuse_policy != GlobalObjectReusePolicy::kUseExisting)
+    frame_->SetDOMWindow(MakeGarbageCollected<LocalDOMWindow>(*frame_));
 
   if (reason == InstallNewDocumentReason::kNavigation)
     WillCommitNavigation();
@@ -1570,7 +1570,7 @@
 void DocumentLoader::ReplaceDocumentWhileExecutingJavaScriptURL(
     const KURL& url,
     Document* owner_document,
-    WebGlobalObjectReusePolicy global_object_reuse_policy,
+    GlobalObjectReusePolicy global_object_reuse_policy,
     const String& source) {
   InstallNewDocument(url, nullptr, owner_document, global_object_reuse_policy,
                      MimeType(), response_.TextEncodingName(),
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index b61c18b..3dafeb4 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -38,7 +38,6 @@
 #include "third_party/blink/public/platform/web_navigation_body_loader.h"
 #include "third_party/blink/public/platform/web_scoped_virtual_time_pauser.h"
 #include "third_party/blink/public/web/web_frame_load_type.h"
-#include "third_party/blink/public/web/web_global_object_reuse_policy.h"
 #include "third_party/blink/public/web/web_navigation_params.h"
 #include "third_party/blink/public/web/web_navigation_type.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
@@ -82,6 +81,12 @@
 class WebServiceWorkerNetworkProvider;
 struct ViewportDescriptionWrapper;
 
+// Indicates whether the global object (i.e. Window instance) associated with
+// the previous document in a browsing context was replaced or reused for the
+// new Document corresponding to the just-committed navigation; effective in the
+// main world and all isolated worlds. WindowProxies are not affected.
+enum class GlobalObjectReusePolicy { kCreateNew, kUseExisting };
+
 // The DocumentLoader fetches a main resource and handles the result.
 class CORE_EXPORT DocumentLoader
     : public GarbageCollectedFinalized<DocumentLoader>,
@@ -104,7 +109,7 @@
 
   void ReplaceDocumentWhileExecutingJavaScriptURL(const KURL&,
                                                   Document* owner_document,
-                                                  WebGlobalObjectReusePolicy,
+                                                  GlobalObjectReusePolicy,
                                                   const String& source);
 
   const AtomicString& MimeType() const;
@@ -281,7 +286,7 @@
       const KURL&,
       const scoped_refptr<const SecurityOrigin> initiator_origin,
       Document* owner_document,
-      WebGlobalObjectReusePolicy,
+      GlobalObjectReusePolicy,
       const AtomicString& mime_type,
       const AtomicString& encoding,
       InstallNewDocumentReason,
@@ -289,7 +294,7 @@
       const KURL& overriding_url);
   void DidInstallNewDocument(Document*);
   void WillCommitNavigation();
-  void DidCommitNavigation(WebGlobalObjectReusePolicy);
+  void DidCommitNavigation(GlobalObjectReusePolicy);
 
   void CommitNavigation(const AtomicString& mime_type,
                         const KURL& overriding_url = KURL());
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index f13880cf3..0fe23a5 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -74,6 +74,8 @@
 
 namespace blink {
 
+enum class GlobalObjectReusePolicy;
+
 class CORE_EXPORT EmptyChromeClient : public ChromeClient {
  public:
   static EmptyChromeClient* Create() {
@@ -271,7 +273,7 @@
   void DispatchDidChangeIcons(IconType) override {}
   void DispatchDidCommitLoad(HistoryItem*,
                              WebHistoryCommitType,
-                             WebGlobalObjectReusePolicy) override {}
+                             GlobalObjectReusePolicy) override {}
   void DispatchDidFailProvisionalLoad(const ResourceError&,
                                       WebHistoryCommitType) override {}
   void DispatchDidFailLoad(const ResourceError&,
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
index 2dc6d824..d8cc7b6 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -142,7 +142,7 @@
     dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(500, 500));
     dummy_page_holder->GetPage().SetDeviceScaleFactorDeprecated(1.0);
     document = &dummy_page_holder->GetDocument();
-    owner = DummyFrameOwner::Create();
+    owner = MakeGarbageCollected<DummyFrameOwner>();
   }
 
   void TearDown() override {
@@ -295,7 +295,7 @@
     Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
     document = &dummy_page_holder->GetDocument();
     document->SetURL(main_resource_url);
-    owner = DummyFrameOwner::Create();
+    owner = MakeGarbageCollected<DummyFrameOwner>();
   }
 
   KURL url;
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 77c1e0b7..d7fa95b0 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -377,10 +377,10 @@
   // done previously before getting here:
   // HTMLFormElement::ScheduleFormSubmission
   // HTMLFrameElementBase::OpenURL
-  WebGlobalObjectReusePolicy global_object_reuse_policy =
+  GlobalObjectReusePolicy global_object_reuse_policy =
       ShouldReuseDefaultView(url, document->GetContentSecurityPolicy())
-          ? WebGlobalObjectReusePolicy::kUseExisting
-          : WebGlobalObjectReusePolicy::kCreateNew;
+          ? GlobalObjectReusePolicy::kUseExisting
+          : GlobalObjectReusePolicy::kCreateNew;
 
   document_loader_->StopLoading();
 
@@ -890,7 +890,7 @@
   }
 
   if (origin_document && origin_document->GetContentSecurityPolicy()) {
-    last_origin_document_csp_ = ContentSecurityPolicy::Create();
+    last_origin_document_csp_ = MakeGarbageCollected<ContentSecurityPolicy>();
     last_origin_document_csp_->CopyStateFrom(
         origin_document->GetContentSecurityPolicy());
     last_origin_document_csp_->CopyPluginTypesFrom(
@@ -1015,14 +1015,14 @@
       std::move(extra_data));
   if (history_item)
     provisional_document_loader_->SetItemForHistoryNavigation(history_item);
-  if (!provisional_document_loader_->PrepareForLoad())
-    return;
 
   frame_->GetFrameScheduler()->DidStartProvisionalLoad(frame_->IsMainFrame());
   Client()->DispatchDidStartProvisionalLoad(provisional_document_loader_);
   probe::DidStartProvisionalLoad(frame_);
   virtual_time_pauser_.PauseVirtualTime();
-  provisional_document_loader_->StartLoading();
+
+  if (provisional_document_loader_->PrepareForLoad())
+    provisional_document_loader_->StartLoading();
   TakeObjectSnapshot();
 }
 
@@ -1358,13 +1358,7 @@
 void FrameLoader::Detach() {
   frame_->GetDocument()->CancelParsing();
   DetachDocumentLoader(document_loader_);
-  if (provisional_document_loader_) {
-    // Suppress client notification about failed provisional
-    // load - it does not bring any value when the frame is
-    // being detached anyway.
-    provisional_document_loader_->SetSentDidFinishLoad();
-    DetachDocumentLoader(provisional_document_loader_);
-  }
+  DetachDocumentLoader(provisional_document_loader_);
   frame_->GetNavigationScheduler().Cancel();
   DidFinishNavigation();
 
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 78a2c2a..5cfff2c 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -71,11 +71,15 @@
 bool IsLazyLoadableImage(const LocalFrame* frame,
                          HTMLImageElement* html_image,
                          const KURL& url) {
-  // Do not lazyload image elements created from javascript.
-  if (!html_image->ElementCreatedByParser())
+  if (!url.ProtocolIsInHTTPFamily())
     return false;
 
-  if (!url.ProtocolIsInHTTPFamily())
+  if (EqualIgnoringASCIICase(
+          html_image->FastGetAttribute(html_names::kLoadAttr), "lazy"))
+    return true;
+
+  // Do not lazyload image elements created from javascript.
+  if (!html_image->ElementCreatedByParser())
     return false;
 
   if (EqualIgnoringASCIICase(
@@ -98,27 +102,10 @@
   return true;
 }
 
-bool CheckForOptimizedImagePolicy(const Document& document,
-                                  ImageResourceContent* new_image) {
+bool CheckForUnoptimizedImagePolicy(const Document& document,
+                                    ImageResourceContent* new_image) {
   if (!new_image)
     return false;
-  // Render the image as a placeholder image if the document does not have the
-  // 'legacy-image-formats' feature enabled, and the image is not one of the
-  // allowed formats.
-  if (!new_image->IsAcceptableContentType()) {
-    // If the image violates the 'legacy-image-formats' policy, record violation
-    // Blink.UseCounter.FeaturePolicy.PotentialVioation. Note that violation
-    // report is up to once per page load.
-    document.CountPotentialFeaturePolicyViolation(
-        mojom::FeaturePolicyFeature::kLegacyImageFormats);
-    // Check if 'legacy-image-formats' policy is disallowed by feature policy.
-    if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
-        !document.IsFeatureEnabled(
-            mojom::FeaturePolicyFeature::kLegacyImageFormats,
-            ReportOptions::kReportOnFailure)) {
-      return true;
-    }
-  }
 
   // Render the image as a placeholder image if the image is not sufficiently
   // well-compressed, according to the unoptimized image feature policies on
@@ -794,10 +781,10 @@
     }
   }
 
-  // TODO(loonybear): support image policies on  other images in addition to
+  // TODO(loonybear): support image policies on other images in addition to
   // HTMLImageElement.
   // crbug.com/930281
-  if (CheckForOptimizedImagePolicy(element_->GetDocument(), image_content_) &&
+  if (CheckForUnoptimizedImagePolicy(element_->GetDocument(), image_content_) &&
       IsHTMLImageElement(element_))
     ToHTMLImageElement(element_)->SetImagePolicyViolated();
 
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
index f85377c2..43ceb0c 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
@@ -490,18 +490,6 @@
   return UpdateImageResult::kNoDecodeError;
 }
 
-// Return true if the image type is one of the hard-coded 'modern' image
-// formats.
-// TODO(crbug.com/838263): Support site-defined list of acceptable formats
-// through feature policy declarations.
-bool ImageResourceContent::IsAcceptableContentType() {
-  AtomicString mime_type = GetResponse().HttpContentType();
-  // If this was loaded from disk, there is no mime type. Return true for now.
-  if (mime_type.IsNull())
-    return true;
-  return MIMETypeRegistry::IsModernImageMIMEType(mime_type);
-}
-
 // Return true if the image content is well-compressed (and not full of
 // extraneous metadata). "well-compressed" is determined by comparing the
 // image's compression ratio against a specific value that is defined by an
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.h b/third_party/blink/renderer/core/loader/resource/image_resource_content.h
index ea516b2f..b32c43ae 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_content.h
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.h
@@ -175,10 +175,9 @@
     return is_refetchable_data_from_disk_cache_;
   }
 
-  // Optimized image policies: These methods are used to determine whether the
+  // Optimized image policies: This method is used to determine whether the
   // image resource violates any of the image policies in effect on the current
   // page.
-  bool IsAcceptableContentType();
   bool IsAcceptableCompressionRatio(const SecurityContext& context);
 
   void LoadDeferredImage(ResourceFetcher* fetcher);
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index d39c9c05..abaad73 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -165,16 +165,17 @@
       drag_controller_(DragController::Create(this)),
       focus_controller_(FocusController::Create(this)),
       context_menu_controller_(ContextMenuController::Create(this)),
-      page_scale_constraints_set_(PageScaleConstraintsSet::Create(this)),
+      page_scale_constraints_set_(
+          MakeGarbageCollected<PageScaleConstraintsSet>(this)),
       pointer_lock_controller_(PointerLockController::Create(this)),
-      browser_controls_(BrowserControls::Create(*this)),
+      browser_controls_(MakeGarbageCollected<BrowserControls>(*this)),
       console_message_storage_(MakeGarbageCollected<ConsoleMessageStorage>()),
       global_root_scroller_controller_(
           TopDocumentRootScrollerController::Create(*this)),
-      visual_viewport_(VisualViewport::Create(*this)),
+      visual_viewport_(MakeGarbageCollected<VisualViewport>(*this)),
       overscroll_controller_(
           OverscrollController::Create(GetVisualViewport(), GetChromeClient())),
-      link_highlights_(LinkHighlights::Create(*this)),
+      link_highlights_(MakeGarbageCollected<LinkHighlights>(*this)),
       plugin_data_(nullptr),
       // TODO(pdr): Initialize |validation_message_client_| lazily.
       validation_message_client_(ValidationMessageClientImpl::Create(*this)),
diff --git a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
index fb943fe..05b179f 100644
--- a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
+++ b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
@@ -104,7 +104,7 @@
     target->DispatchActivateInvisibleEventIfNeeded();
   }
 
-  if (doc.IsSVGDocument() && !frame.IsMainFrame())
+  if (doc.IsSVGDocument() && (!frame.IsMainFrame() || !target))
     return nullptr;
 
   if (!anchor_node)
diff --git a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor_test.cc b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor_test.cc
index a6135fb..79df5fd 100644
--- a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor_test.cc
@@ -11,11 +11,14 @@
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/html/html_anchor_element.h"
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/html/html_image_element.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 
 namespace blink {
@@ -261,4 +264,46 @@
   // Non-crash is considered a pass.
 }
 
+// Ensure that an SVG document doesn't automatically create a fragment anchor
+// without the URL actually having a fragment.
+TEST_F(ElementFragmentAnchorTest, SVGDocumentDoesntCreateFragment) {
+  SimRequest main_resource("https://example.com/test.html", "text/html");
+  SimRequest svg_resource("https://example.com/file.svg", "image/svg+xml");
+
+  LoadURL("https://example.com/test.html");
+
+  main_resource.Complete(R"HTML(
+      <!DOCTYPE html>
+      <img id="image" src=file.svg>
+    )HTML");
+
+  // Load an SVG that's transformed outside of the container rect. Ensure that
+  // we don't scroll it into view since we didn't specify a hash fragment.
+  svg_resource.Complete(R"SVG(
+      <svg id="svg" width="50" height="50" xmlns="http://www.w3.org/2000/svg">
+         <style>
+          #svg{
+            transform: translateX(200px) translateY(200px);
+          }
+         </style>
+         <circle class="path" cx="50" cy="50" r="20" fill="red"/>
+      </svg>
+    )SVG");
+
+  auto* img = ToHTMLImageElement(GetDocument().getElementById("image"));
+  SVGImage* svg = ToSVGImage(img->CachedImage()->GetImage());
+  auto* view =
+      DynamicTo<LocalFrameView>(svg->GetPageForTesting()->MainFrame()->View());
+
+  // Scroll should remain unchanged and no anchor should be set.
+  ASSERT_EQ(ScrollOffset(), view->GetScrollableArea()->GetScrollOffset());
+  ASSERT_FALSE(view->GetFragmentAnchor());
+
+  // Check after a BeginFrame as well since SVG documents appear to process the
+  // fragment at this time as well.
+  Compositor().BeginFrame();
+  ASSERT_EQ(ScrollOffset(), view->GetScrollableArea()->GetScrollOffset());
+  ASSERT_FALSE(view->GetFragmentAnchor());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/BUILD.gn b/third_party/blink/renderer/core/streams/BUILD.gn
index ba0c7ce..1d8e79c 100644
--- a/third_party/blink/renderer/core/streams/BUILD.gn
+++ b/third_party/blink/renderer/core/streams/BUILD.gn
@@ -18,6 +18,8 @@
     "readable_stream_default_controller_interface.h",
     "readable_stream_default_reader.cc",
     "readable_stream_default_reader.h",
+    "readable_stream_native.cc",
+    "readable_stream_native.h",
     "readable_stream_operations.cc",
     "readable_stream_operations.h",
     "readable_stream_wrapper.cc",
diff --git a/third_party/blink/renderer/core/streams/README.md b/third_party/blink/renderer/core/streams/README.md
index 78e10fc..d8d7c8d8 100644
--- a/third_party/blink/renderer/core/streams/README.md
+++ b/third_party/blink/renderer/core/streams/README.md
@@ -1,8 +1,33 @@
 # core/streams/
 
-This directory contains the Blink implementation of [the WHATWG Streams standard][1].
+This directory contains the Blink implementation of [the WHATWG Streams
+standard][1].
 
 We use [V8 extras][2] to implement it.
 
+There is also a new implementation that is written in C++ rather than
+JavaScript. It is currently off by default, behind the Blink "StreamsNative"
+feature. The following files are part of the new implementation:
+
+    readable_stream_default_controller.idl
+    readable_stream_default_controller_interface.cc
+    readable_stream_default_controller_interface.h
+    readable_stream_default_reader.cc
+    readable_stream_default_reader.h
+    readable_stream_default_reader.idl
+    readable_stream_native.cc
+    readable_stream_native.h
+    writable_stream_default_controller.cc
+    writable_stream_default_controller.h
+    writable_stream_default_controller.idl
+    writable_stream_default_writer.cc
+    writable_stream_default_writer.h
+    writable_stream_default_writer.idl
+    writable_stream_native.cc
+    writable_stream_native.h
+
+See also [Streams C++ port design doc][3].
+
 [1]: https://streams.spec.whatwg.org/
 [2]: https://docs.google.com/document/d/1AT5-T0aHGp7Lt29vPWFr2-qG8r3l9CByyvKwEuA8Ec0
+[3]: https://docs.google.com/document/d/1n0IIRmJb0R-DFc2IhhJfS2-LUwl6iKSBNaR0klr3o40/edit
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations.cc b/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
index d56a1a83..f130b29 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
@@ -270,6 +270,14 @@
   TraceWrapperV8Reference<v8::Value> controller_;
 };
 
+class TrivialStartAlgorithm : public StreamStartAlgorithm {
+ public:
+  v8::MaybeLocal<v8::Promise> Run(ScriptState* script_state,
+                                  ExceptionState&) override {
+    return PromiseResolveWithUndefined(script_state);
+  }
+};
+
 }  // namespace
 
 // TODO(ricea): For optimal performance, method_name should be cached as an
@@ -326,6 +334,10 @@
       controller);
 }
 
+CORE_EXPORT StreamStartAlgorithm* CreateTrivialStartAlgorithm() {
+  return MakeGarbageCollected<TrivialStartAlgorithm>();
+}
+
 CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(
     ScriptState* script_state,
     v8::Local<v8::Object> object,
@@ -424,6 +436,10 @@
       script_state->GetIsolate(), size.As<v8::Function>());
 }
 
+CORE_EXPORT StrategySizeAlgorithm* CreateDefaultSizeAlgorithm() {
+  return MakeGarbageCollected<DefaultSizeAlgorithm>();
+}
+
 // PromiseResolve implements Promise.resolve(_x_) from the ECMASCRIPT standard,
 // https://tc39.github.io/ecma262/#sec-promise.resolve, except that the
 // Get(_x_, "constructor") step is skipped.
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations.h b/third_party/blink/renderer/core/streams/miscellaneous_operations.h
index d396a17..c7cb9837 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations.h
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations.h
@@ -49,6 +49,10 @@
     const char* method_name_for_error,
     v8::Local<v8::Value> controller);
 
+// Returns a startAlgorithm that always returns a promise resolved with
+// undefined.
+CORE_EXPORT StreamStartAlgorithm* CreateTrivialStartAlgorithm();
+
 // Used in place of InvokeOrNoop in spec. Always takes 1 argument.
 // https://streams.spec.whatwg.org/#invoke-or-noop
 CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(ScriptState*,
@@ -81,6 +85,8 @@
     v8::Local<v8::Value> size,
     ExceptionState&);
 
+CORE_EXPORT StrategySizeAlgorithm* CreateDefaultSizeAlgorithm();
+
 // Implements "a promise rejected with" from the INFRA standard.
 // https://www.w3.org/2001/tag/doc/promises-guide/#a-promise-rejected-with
 CORE_EXPORT v8::Local<v8::Promise> PromiseReject(ScriptState*,
diff --git a/third_party/blink/renderer/core/streams/readable_stream.cc b/third_party/blink/renderer/core/streams/readable_stream.cc
index 04c31ce6..8b787d6 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/readable_stream.h"
 
+#include "third_party/blink/renderer/core/streams/readable_stream_native.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_wrapper.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -32,7 +33,11 @@
                                        ScriptValue underlying_source,
                                        ScriptValue strategy,
                                        ExceptionState& exception_state) {
-  // TODO(ricea): Select implementation based on StreamsNative feature here.
+  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
+    return ReadableStreamNative::Create(script_state, underlying_source,
+                                        strategy, exception_state);
+  }
+
   return ReadableStreamWrapper::Create(script_state, underlying_source,
                                        strategy, exception_state);
 }
@@ -41,6 +46,11 @@
     ScriptState* script_state,
     UnderlyingSourceBase* underlying_source,
     size_t high_water_mark) {
+  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
+    return ReadableStreamNative::CreateWithCountQueueingStrategy(
+        script_state, underlying_source, high_water_mark);
+  }
+
   // TODO(ricea): Select implementation based on StreamsNative feature here.
   return ReadableStreamWrapper::CreateWithCountQueueingStrategy(
       script_state, underlying_source, high_water_mark);
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc b/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
index 94de7a4..4371d75c 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
@@ -5,27 +5,659 @@
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
+#include "third_party/blink/renderer/core/streams/queue_with_sizes.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_native.h"
+#include "third_party/blink/renderer/core/streams/stream_algorithms.h"
+#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
+#include "third_party/blink/renderer/core/streams/stream_script_function.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/to_v8.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
 
 namespace blink {
 
-void ReadableStreamDefaultController::close(ScriptState* script_state) {}
+// This constructor is used internally; it is not reachable from JavaScript.
+ReadableStreamDefaultController::ReadableStreamDefaultController()
+    : queue_(MakeGarbageCollected<QueueWithSizes>()) {}
+
+double ReadableStreamDefaultController::desiredSize(bool& is_null) const {
+  // https://streams.spec.whatwg.org/#rs-default-controller-desired-size
+  // 2. Return ! ReadableStreamDefaultControllerGetDesiredSize(this).
+  base::Optional<double> desired_size = GetDesiredSize();
+  is_null = !desired_size.has_value();
+  return is_null ? 0.0 : desired_size.value();
+}
+
+void ReadableStreamDefaultController::close(ScriptState* script_state,
+                                            ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#rs-default-controller-close
+  // 2. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false,
+  //    throw a TypeError exception.
+  if (!CanCloseOrEnqueue(this)) {
+    // The following code is just to provide a nice exception message.
+    const char* errorDescription = nullptr;
+    if (this->is_close_requested_) {
+      errorDescription =
+          "Cannot close a readable stream that has already been requested to "
+          "be closed";
+    } else {
+      const ReadableStreamNative* stream = this->controlled_readable_stream_;
+      switch (stream->state_) {
+        case ReadableStreamNative::kErrored:
+          errorDescription = "Cannot close an errored readable stream";
+          break;
+
+        case ReadableStreamNative::kClosed:
+          errorDescription = "Cannot close an errored readable stream";
+          break;
+
+        default:
+          NOTREACHED();
+          break;
+      }
+    }
+    exception_state.ThrowTypeError(errorDescription);
+    return;
+  }
+
+  // 3. Perform ! ReadableStreamDefaultControllerClose(this).
+  return Close(script_state, this);
+}
 
 void ReadableStreamDefaultController::enqueue(ScriptState* script_state,
                                               ExceptionState& exception_state) {
+  enqueue(script_state,
+          ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())),
+          exception_state);
 }
 
 void ReadableStreamDefaultController::enqueue(ScriptState* script_state,
                                               ScriptValue chunk,
                                               ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#rs-default-controller-enqueue
+  // 2. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false,
+  //    throw a TypeError exception.
+  if (!CanCloseOrEnqueue(this)) {
+    exception_state.ThrowTypeError(EnqueueExceptionMessage(this));
+    return;
+  }
+
+  // 3. Return ? ReadableStreamDefaultControllerEnqueue(this, chunk).
+  return Enqueue(script_state, this, chunk.V8Value(), exception_state);
 }
 
 void ReadableStreamDefaultController::error(ScriptState* script_state) {
-  return;
+  error(script_state,
+        ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())));
 }
 
 void ReadableStreamDefaultController::error(ScriptState* script_state,
                                             ScriptValue e) {
-  return;
+  // https://streams.spec.whatwg.org/#rs-default-controller-error
+  // 2. Perform ! ReadableStreamDefaultControllerError(this, e).
+  Error(script_state, this, e.V8Value());
+}
+
+void ReadableStreamDefaultController::Close(
+    ScriptState* script_state,
+    ReadableStreamDefaultController* controller) {
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-close
+  // 1. Let stream be controller.[[controlledReadableStream]].
+  ReadableStreamNative* stream = controller->controlled_readable_stream_;
+
+  // 2. Assert: ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)
+  //    is true.
+  DCHECK(CanCloseOrEnqueue(controller));
+
+  // 3. Set controller.[[closeRequested]] to true.
+  controller->is_close_requested_ = true;
+
+  // 4. If controller.[[queue]] is empty,
+  if (controller->queue_->IsEmpty()) {
+    // a. Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller).
+    ClearAlgorithms(controller);
+
+    // b. Perform ! ReadableStreamClose(stream).
+    ReadableStreamNative::Close(script_state, stream);
+  }
+}
+
+void ReadableStreamDefaultController::Enqueue(
+    ScriptState* script_state,
+    ReadableStreamDefaultController* controller,
+    v8::Local<v8::Value> chunk,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-enqueue
+  // 1. Let stream be controller.[[controlledReadableStream]].
+  const auto stream = controller->controlled_readable_stream_;
+
+  // 2. Assert: ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)
+  //    is true.
+  DCHECK(CanCloseOrEnqueue(controller));
+
+  // 3. If ! IsReadableStreamLocked(stream) is true and !
+  //    ReadableStreamGetNumReadRequests(stream) > 0, perform !
+  //    ReadableStreamFulfillReadRequest(stream, chunk, false).
+  if (ReadableStreamNative::IsLocked(stream) &&
+      ReadableStreamNative::GetNumReadRequests(stream) > 0) {
+    ReadableStreamNative::FulfillReadRequest(script_state, stream, chunk,
+                                             false);
+  } else {
+    // 4. Otherwise,
+    //   a. Let result be the result of performing controller.
+    //      [[strategySizeAlgorithm]], passing in chunk, and interpreting the
+    //      result as an ECMAScript completion value.
+    base::Optional<double> chunk_size =
+        controller->strategy_size_algorithm_->Run(script_state, chunk,
+                                                  exception_state);
+
+    //   b. If result is an abrupt completion,
+    if (exception_state.HadException()) {
+      //    i. Perform ! ReadableStreamDefaultControllerError(controller,
+      //       result.[[Value]]).
+      Error(script_state, controller, exception_state.GetException());
+      //    ii. Return result.
+      return;
+    }
+    DCHECK(chunk_size.has_value());
+
+    //  c. Let chunkSize be result.[[Value]].
+    //  d. Let enqueueResult be EnqueueValueWithSize(controller, chunk,
+    //     chunkSize).
+    controller->queue_->EnqueueValueWithSize(
+        script_state->GetIsolate(), chunk, chunk_size.value(), exception_state);
+
+    //   e. If enqueueResult is an abrupt completion,
+    if (exception_state.HadException()) {
+      //    i. Perform ! ReadableStreamDefaultControllerError(controller,
+      //       enqueueResult.[[Value]]).
+      Error(script_state, controller, exception_state.GetException());
+      //    ii. Return enqueueResult.
+      return;
+    }
+  }
+
+  // 5. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).
+  CallPullIfNeeded(script_state, controller);
+}
+
+void ReadableStreamDefaultController::Error(
+    ScriptState* script_state,
+    ReadableStreamDefaultController* controller,
+    v8::Local<v8::Value> e) {
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-error
+  // 1. Let stream be controller.[[controlledReadableStream]].
+  ReadableStreamNative* stream = controller->controlled_readable_stream_;
+
+  // 2. If stream.[[state]] is not "readable", return.
+  if (stream->state_ != ReadableStreamNative::kReadable) {
+    return;
+  }
+
+  // 3. Perform ! ResetQueue(controller).
+  controller->queue_->ResetQueue();
+
+  // 4. Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller).
+  ClearAlgorithms(controller);
+
+  // 5. Perform ! ReadableStreamError(stream, e).
+  ReadableStreamNative::Error(script_state, stream, e);
+}
+
+// This is an instance method rather than the static function in the standard,
+// so |this| is |controller|.
+base::Optional<double> ReadableStreamDefaultController::GetDesiredSize() const {
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-get-desired-size
+  switch (controlled_readable_stream_->state_) {
+    // 3. If state is "errored", return null.
+    case ReadableStreamNative::kErrored:
+      return base::nullopt;
+
+    // 4. If state is "closed", return 0.
+    case ReadableStreamNative::kClosed:
+      return 0.0;
+
+    case ReadableStreamNative::kReadable:
+      // 5. Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].
+      return strategy_high_water_mark_ - queue_->TotalSize();
+  }
+}
+
+void ReadableStreamDefaultController::Trace(Visitor* visitor) {
+  visitor->Trace(cancel_algorithm_);
+  visitor->Trace(controlled_readable_stream_);
+  visitor->Trace(pull_algorithm_);
+  visitor->Trace(queue_);
+  visitor->Trace(strategy_size_algorithm_);
+  visitor->Trace(lock_notify_target_);
+  ScriptWrappable::Trace(visitor);
+}
+
+//
+// Readable stream default controller internal methods
+//
+
+v8::Local<v8::Promise> ReadableStreamDefaultController::CancelSteps(
+    ScriptState* script_state,
+    v8::Local<v8::Value> reason) {
+  // https://streams.spec.whatwg.org/#rs-default-controller-private-cancel
+  // 1. Perform ! ResetQueue(this).
+  queue_->ResetQueue();
+
+  // 2. Let result be the result of performing this.[[cancelAlgorithm]], passing
+  //    reason.
+  auto result = cancel_algorithm_->Run(script_state, 1, &reason);
+
+  // 3. Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).
+  ClearAlgorithms(this);
+
+  // 4. Return result.
+  return result;
+}
+
+StreamPromiseResolver* ReadableStreamDefaultController::PullSteps(
+    ScriptState* script_state) {
+  // https://streams.spec.whatwg.org/#rs-default-controller-private-pull
+  // 1. Let stream be this.[[controlledReadableStream]].
+  ReadableStreamNative* stream = controlled_readable_stream_;
+
+  // 2. If this.[[queue]] is not empty,
+  if (!queue_->IsEmpty()) {
+    // a. Let chunk be ! DequeueValue(this).
+    const auto chunk = queue_->DequeueValue(script_state->GetIsolate());
+
+    // b. If this.[[closeRequested]] is true and this.[[queue]] is empty,
+    if (is_close_requested_ && queue_->IsEmpty()) {
+      //   i. Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).
+      ClearAlgorithms(this);
+
+      //   ii. Perform ! ReadableStreamClose(stream).
+      ReadableStreamNative::Close(script_state, stream);
+    } else {
+      // c. Otherwise, perform !
+      //    ReadableStreamDefaultControllerCallPullIfNeeded(this).
+      CallPullIfNeeded(script_state, this);
+    }
+
+    // d. Return a promise resolved with !
+    //    ReadableStreamCreateReadResult(chunk, false,
+    //    stream.[[reader]].[[forAuthorCode]]).
+    return StreamPromiseResolver::CreateResolved(
+        script_state,
+        ReadableStreamNative::CreateReadResult(
+            script_state, chunk, false, stream->reader_->for_author_code_));
+  }
+
+  // 3. Let pendingPromise be ! ReadableStreamAddReadRequest(stream).
+  StreamPromiseResolver* pendingPromise =
+      ReadableStreamNative::AddReadRequest(script_state, stream);
+
+  // 4. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).
+  CallPullIfNeeded(script_state, this);
+
+  // 5. Return pendingPromise.
+  return pendingPromise;
+}
+
+//
+// Readable Stream Default Controller Abstract Operations
+//
+
+void ReadableStreamDefaultController::CallPullIfNeeded(
+    ScriptState* script_state,
+    ReadableStreamDefaultController* controller) {
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-call-pull-if-needed
+  // 1. Let shouldPull be ! ReadableStreamDefaultControllerShouldCallPull(
+  //    controller).
+  const bool should_pull = ShouldCallPull(controller);
+
+  // 2. If shouldPull is false, return.
+  if (!should_pull) {
+    return;
+  }
+
+  // 3. If controller.[[pulling]] is true,
+  if (controller->is_pulling_) {
+    // a. Set controller.[[pullAgain]] to true.
+    controller->will_pull_again_ = true;
+
+    // b. Return.
+    return;
+  }
+
+  // 4. Assert: controller.[[pullAgain]] is false.
+  DCHECK(!controller->will_pull_again_);
+
+  // 5. Set controller.[[pulling]] to true.
+  controller->is_pulling_ = true;
+
+  // 6. Let pullPromise be the result of performing
+  //    controller.[[pullAlgorithm]].
+  auto pull_promise =
+      controller->pull_algorithm_->Run(script_state, 0, nullptr);
+
+  class ResolveFunction : public StreamScriptFunction {
+   public:
+    ResolveFunction(ScriptState* script_state,
+                    ReadableStreamDefaultController* controller)
+        : StreamScriptFunction(script_state), controller_(controller) {}
+
+    void CallWithLocal(v8::Local<v8::Value>) override {
+      // 7. Upon fulfillment of pullPromise,
+      //   a. Set controller.[[pulling]] to false.
+      controller_->is_pulling_ = false;
+
+      //   b. If controller.[[pullAgain]] is true,
+      if (controller_->will_pull_again_) {
+        //  i. Set controller.[[pullAgain]] to false.
+        controller_->will_pull_again_ = false;
+
+        //  ii. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(
+        //      controller).
+        CallPullIfNeeded(GetScriptState(), controller_);
+      }
+    }
+
+    void Trace(Visitor* visitor) override {
+      visitor->Trace(controller_);
+      StreamScriptFunction::Trace(visitor);
+    }
+
+   private:
+    const TraceWrapperMember<ReadableStreamDefaultController> controller_;
+  };
+
+  class RejectFunction : public StreamScriptFunction {
+   public:
+    RejectFunction(ScriptState* script_state,
+                   ReadableStreamDefaultController* controller)
+        : StreamScriptFunction(script_state), controller_(controller) {}
+
+    void CallWithLocal(v8::Local<v8::Value> e) override {
+      // 8. Upon rejection of pullPromise with reason e,
+      //   a. Perform ! ReadableStreamDefaultControllerError(controller, e).
+      Error(GetScriptState(), controller_, e);
+    }
+
+    void Trace(Visitor* visitor) override {
+      visitor->Trace(controller_);
+      StreamScriptFunction::Trace(visitor);
+    }
+
+   private:
+    const TraceWrapperMember<ReadableStreamDefaultController> controller_;
+  };
+
+  StreamThenPromise(
+      script_state->GetContext(), pull_promise,
+      MakeGarbageCollected<ResolveFunction>(script_state, controller),
+      MakeGarbageCollected<RejectFunction>(script_state, controller));
+}
+
+bool ReadableStreamDefaultController::ShouldCallPull(
+    const ReadableStreamDefaultController* controller) {
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-should-call-pull
+  // 1. Let stream be controller.[[controlledReadableStream]].
+  const ReadableStreamNative* stream = controller->controlled_readable_stream_;
+
+  // 2. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is
+  //    false, return false.
+  if (!CanCloseOrEnqueue(controller)) {
+    return false;
+  }
+
+  // 3. If controller.[[started]] is false, return false.
+  if (!controller->is_started_) {
+    return false;
+  }
+
+  // 4. If ! IsReadableStreamLocked(stream) is true and !
+  //    ReadableStreamGetNumReadRequests(stream) > 0, return true.
+  if (ReadableStreamNative::IsLocked(stream) &&
+      ReadableStreamNative::GetNumReadRequests(stream) > 0) {
+    return true;
+  }
+
+  // 5. Let desiredSize be ! ReadableStreamDefaultControllerGetDesiredSize
+  //    (controller).
+  base::Optional<double> desired_size = controller->GetDesiredSize();
+
+  // 6. Assert: desiredSize is not null.
+  DCHECK(desired_size.has_value());
+
+  // 7. If desiredSize > 0, return true.
+  // 8. Return false.
+  return desired_size.value() > 0;
+}
+
+void ReadableStreamDefaultController::ClearAlgorithms(
+    ReadableStreamDefaultController* controller) {
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-clear-algorithms
+  // 1. Set controller.[[pullAlgorithm]] to undefined.
+  controller->pull_algorithm_ = nullptr;
+
+  // 2. Set controller.[[cancelAlgorithm]] to undefined.
+  controller->cancel_algorithm_ = nullptr;
+
+  // 3. Set controller.[[strategySizeAlgorithm]] to undefined.
+  controller->strategy_size_algorithm_ = nullptr;
+}
+
+bool ReadableStreamDefaultController::HasBackpressure(
+    const ReadableStreamDefaultController* controller) {
+  // https://streams.spec.whatwg.org/#rs-default-controller-has-backpressure
+  // 1. If ! ReadableStreamDefaultControllerShouldCallPull(controller) is true,
+  //    return false.
+  // 2. Otherwise, return true.
+  return !ShouldCallPull(controller);
+}
+
+bool ReadableStreamDefaultController::CanCloseOrEnqueue(
+    const ReadableStreamDefaultController* controller) {
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-can-close-or-enqueue
+  // 1. Let state be controller.[[controlledReadableStream]].[[state]].
+  const auto state = controller->controlled_readable_stream_->state_;
+
+  // 2. If controller.[[closeRequested]] is false and state is "readable",
+  //    return true.
+  // 3. Otherwise, return false.
+  return !controller->is_close_requested_ &&
+         state == ReadableStreamNative::kReadable;
+}
+
+void ReadableStreamDefaultController::SetUp(
+    ScriptState* script_state,
+    ReadableStreamNative* stream,
+    ReadableStreamDefaultController* controller,
+    StreamStartAlgorithm* start_algorithm,
+    StreamAlgorithm* pull_algorithm,
+    StreamAlgorithm* cancel_algorithm,
+    double high_water_mark,
+    StrategySizeAlgorithm* size_algorithm,
+    bool enable_blink_lock_notifications,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller
+  // 1. Assert: stream.[[readableStreamController]] is undefined.
+  DCHECK(!stream->readable_stream_controller_);
+
+  // 2. Set controller.[[controlledReadableStream]] to stream.
+  controller->controlled_readable_stream_ = stream;
+
+  // 3. Set controller.[[queue]] and controller.[[queueTotalSize]] to undefined,
+  //    then perform ! ResetQueue(controller).
+  // These steps are performed by the constructor, so just check that nothing
+  // interfered.
+  DCHECK(controller->queue_->IsEmpty());
+  DCHECK_EQ(controller->queue_->TotalSize(), 0);
+
+  // Not part of the standard.
+  controller->enable_blink_lock_notifications_ =
+      enable_blink_lock_notifications;
+
+  // 5. Set controller.[[strategySizeAlgorithm]] to sizeAlgorithm and
+  //    controller.[[strategyHWM]] to highWaterMark.
+  controller->strategy_size_algorithm_ = size_algorithm;
+  controller->strategy_high_water_mark_ = high_water_mark;
+
+  // 6. Set controller.[[pullAlgorithm]] to pullAlgorithm.
+  controller->pull_algorithm_ = pull_algorithm;
+
+  // 7. Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
+  controller->cancel_algorithm_ = cancel_algorithm;
+
+  // 8. Set stream.[[readableStreamController]] to controller.
+  stream->readable_stream_controller_ = controller;
+
+  // 9. Let startResult be the result of performing startAlgorithm. (This may
+  //    throw an exception.)
+  // 10. Let startPromise be a promise resolved with startResult.
+  // The conversion of startResult to a promise happens inside start_algorithm
+  // in this implementation.
+  v8::Local<v8::Promise> start_promise;
+  if (!start_algorithm->Run(script_state, exception_state)
+           .ToLocal(&start_promise)) {
+    if (!exception_state.HadException()) {
+      // Is this block really needed? Can we make this a DCHECK?
+      exception_state.ThrowException(
+          static_cast<int>(DOMExceptionCode::kInvalidStateError),
+          "start algorithm failed with no exception thrown");
+    }
+    return;
+  }
+  DCHECK(!exception_state.HadException());
+
+  class ResolveFunction : public StreamScriptFunction {
+   public:
+    ResolveFunction(ScriptState* script_state,
+                    ReadableStreamDefaultController* controller)
+        : StreamScriptFunction(script_state), controller_(controller) {}
+
+    void CallWithLocal(v8::Local<v8::Value>) override {
+      //  11. Upon fulfillment of startPromise,
+      //    a. Set controller.[[started]] to true.
+      controller_->is_started_ = true;
+
+      //    b. Assert: controller.[[pulling]] is false.
+      DCHECK(!controller_->is_pulling_);
+
+      //    c. Assert: controller.[[pullAgain]] is false.
+      DCHECK(!controller_->will_pull_again_);
+
+      //    d. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(
+      //       controller).
+      CallPullIfNeeded(GetScriptState(), controller_);
+    }
+
+    void Trace(Visitor* visitor) override {
+      visitor->Trace(controller_);
+      StreamScriptFunction::Trace(visitor);
+    }
+
+   private:
+    const TraceWrapperMember<ReadableStreamDefaultController> controller_;
+  };
+
+  class RejectFunction : public StreamScriptFunction {
+   public:
+    RejectFunction(ScriptState* script_state,
+                   ReadableStreamDefaultController* controller)
+        : StreamScriptFunction(script_state), controller_(controller) {}
+
+    void CallWithLocal(v8::Local<v8::Value> r) override {
+      //  12. Upon rejection of startPromise with reason r,
+      //    a. Perform ! ReadableStreamDefaultControllerError(controller, r).
+      Error(GetScriptState(), controller_, r);
+    }
+
+    void Trace(Visitor* visitor) override {
+      visitor->Trace(controller_);
+      StreamScriptFunction::Trace(visitor);
+    }
+
+   private:
+    const TraceWrapperMember<ReadableStreamDefaultController> controller_;
+  };
+
+  StreamThenPromise(
+      script_state->GetContext(), start_promise,
+      MakeGarbageCollected<ResolveFunction>(script_state, controller),
+      MakeGarbageCollected<RejectFunction>(script_state, controller));
+}
+
+void ReadableStreamDefaultController::SetUpFromUnderlyingSource(
+    ScriptState* script_state,
+    ReadableStreamNative* stream,
+    v8::Local<v8::Object> underlying_source,
+    double high_water_mark,
+    StrategySizeAlgorithm* size_algorithm,
+    bool enable_blink_lock_notifications,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller-from-underlying-source
+  // 2. Let controller be ObjectCreate(the original value of
+  //    ReadableStreamDefaultController's prototype property).
+  auto* controller = MakeGarbageCollected<ReadableStreamDefaultController>();
+
+  // This method is only called when a WritableStream is being constructed by
+  // JavaScript. So the execution context should be valid and this call should
+  // not crash.
+  auto controller_value = ToV8(controller, script_state);
+
+  // 3. Let startAlgorithm be the following steps:
+  //   a. Return ? InvokeOrNoop(underlyingSource, "start", « controller »).
+  auto* start_algorithm =
+      CreateStartAlgorithm(script_state, underlying_source,
+                           "underlyingSource.start", controller_value);
+
+  // 4. Let pullAlgorithm be ? CreateAlgorithmFromUnderlyingMethod
+  //    (underlyingSource, "pull", 0, « controller »).
+  auto* pull_algorithm = CreateAlgorithmFromUnderlyingMethod(
+      script_state, underlying_source, "pull", "underlyingSource.pull",
+      controller_value, exception_state);
+  if (exception_state.HadException()) {
+    return;
+  }
+
+  // 5. Let cancelAlgorithm be ? CreateAlgorithmFromUnderlyingMethod
+  //    (underlyingSource, "cancel", 1, « »).
+  auto* cancel_algorithm = CreateAlgorithmFromUnderlyingMethod(
+      script_state, underlying_source, "cancel", "underlyingSource.cancel",
+      controller_value, exception_state);
+  if (exception_state.HadException()) {
+    return;
+  }
+
+  // TODO(ricea): Remove this once C++ API has been updated.
+  if (enable_blink_lock_notifications) {
+    controller->lock_notify_target_.Set(script_state->GetIsolate(),
+                                        underlying_source);
+  }
+
+  // 6. Perform ? SetUpReadableStreamDefaultController(stream, controller,
+  //    startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark,
+  //    sizeAlgorithm).
+  SetUp(script_state, stream, controller, start_algorithm, pull_algorithm,
+        cancel_algorithm, high_water_mark, size_algorithm,
+        enable_blink_lock_notifications, exception_state);
+}
+
+// Used internally by enqueue() and also by TransformStream.
+const char* ReadableStreamDefaultController::EnqueueExceptionMessage(
+    const ReadableStreamDefaultController* controller) {
+  if (controller->is_close_requested_) {
+    return "Cannot enqueue a chunk into a readable stream that is closed or "
+           "has been requested to be closed";
+  }
+
+  const ReadableStreamNative* stream = controller->controlled_readable_stream_;
+  const auto state = stream->state_;
+  if (state == ReadableStreamNative::kErrored) {
+    return "Cannot enqueue a chunk into an errored readable stream";
+  }
+  DCHECK(state == ReadableStreamNative::kClosed);
+  return "Cannot enqueue a chunk into a closed readable stream";
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller.h b/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
index 49e4a01..b55101d 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller.h
@@ -5,25 +5,126 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_CONTROLLER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_CONTROLLER_H_
 
+#include "base/optional.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "v8/include/v8.h"
 
 namespace blink {
 
 class ExceptionState;
+class QueueWithSizes;
+class ReadableStreamNative;
 class ScriptState;
 class ScriptValue;
+class StrategySizeAlgorithm;
+class StreamAlgorithm;
+class StreamPromiseResolver;
+class StreamStartAlgorithm;
 
 class ReadableStreamDefaultController : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  void close(ScriptState*);
+  ReadableStreamDefaultController();
+
+  // https://streams.spec.whatwg.org/#rs-default-controller-desired-size
+  double desiredSize(bool& is_null) const;
+
+  // https://streams.spec.whatwg.org/#rs-default-controller-close
+  void close(ScriptState*, ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#rs-default-controller-enqueue
   void enqueue(ScriptState*, ExceptionState&);
   void enqueue(ScriptState*, ScriptValue chunk, ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#rs-default-controller-error
   void error(ScriptState*);
   void error(ScriptState*, ScriptValue e);
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-close
+  static void Close(ScriptState*, ReadableStreamDefaultController*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-enqueue
+  static void Enqueue(ScriptState*,
+                      ReadableStreamDefaultController*,
+                      v8::Local<v8::Value> chunk,
+                      ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-error
+  static void Error(ScriptState*,
+                    ReadableStreamDefaultController*,
+                    v8::Local<v8::Value> e);
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-get-desired-size
+  base::Optional<double> GetDesiredSize() const;
+
+  void Trace(Visitor*) override;
+
+ private:
+  friend class ReadableStreamNative;
+  friend class ReadableStreamDefaultReader;
+
+  // https://streams.spec.whatwg.org/#rs-default-controller-private-cancel
+  v8::Local<v8::Promise> CancelSteps(ScriptState*, v8::Local<v8::Value> reason);
+
+  // https://streams.spec.whatwg.org/#rs-default-controller-private-pull
+  StreamPromiseResolver* PullSteps(ScriptState*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-call-pull-if-needed
+  static void CallPullIfNeeded(ScriptState*, ReadableStreamDefaultController*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-should-call-pull
+  static bool ShouldCallPull(const ReadableStreamDefaultController*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-clear-algorithms
+  static void ClearAlgorithms(ReadableStreamDefaultController*);
+
+  // https://streams.spec.whatwg.org/#rs-default-controller-has-backpressure
+  static bool HasBackpressure(const ReadableStreamDefaultController*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-controller-can-close-or-enqueue
+  static bool CanCloseOrEnqueue(const ReadableStreamDefaultController*);
+
+  // https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller
+  static void SetUp(ScriptState*,
+                    ReadableStreamNative*,
+                    ReadableStreamDefaultController*,
+                    StreamStartAlgorithm* start_algorithm,
+                    StreamAlgorithm* pull_algorithm,
+                    StreamAlgorithm* cancel_algorithm,
+                    double high_water_mark,
+                    StrategySizeAlgorithm* size_algorithm,
+                    bool enable_blink_lock_notifications,
+                    ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller-from-underlying-source
+  static void SetUpFromUnderlyingSource(ScriptState*,
+                                        ReadableStreamNative*,
+                                        v8::Local<v8::Object> underlying_source,
+                                        double high_water_mark,
+                                        StrategySizeAlgorithm* size_algorithm,
+                                        bool enable_blink_lock_notifications,
+                                        ExceptionState&);
+
+  static const char* EnqueueExceptionMessage(
+      const ReadableStreamDefaultController*);
+
+  // Boolean flags are grouped together to reduce object size. Verbs have been
+  // added to the names in the standard to match Blink style.
+  bool is_close_requested_ = false;
+  bool will_pull_again_ = false;
+  bool is_pulling_ = false;
+  bool is_started_ = false;
+  bool enable_blink_lock_notifications_ = false;
+  TraceWrapperMember<StreamAlgorithm> cancel_algorithm_;
+  TraceWrapperMember<ReadableStreamNative> controlled_readable_stream_;
+  TraceWrapperMember<StreamAlgorithm> pull_algorithm_;
+  TraceWrapperMember<QueueWithSizes> queue_;
+  double strategy_high_water_mark_ = 0.0;
+  TraceWrapperMember<StrategySizeAlgorithm> strategy_size_algorithm_;
+  TraceWrapperV8Reference<v8::Object> lock_notify_target_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl b/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
index 9a587c7..ddd4337 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
@@ -10,7 +10,8 @@
     NoInterfaceObject,
     RaisesException=Constructor
 ] interface ReadableStreamDefaultController {
-    [CallWith=ScriptState, NotEnumerable] void close();
+    [NotEnumerable] readonly attribute double? desiredSize;
+    [CallWith=ScriptState, NotEnumerable, RaisesException] void close();
     [CallWith=ScriptState, NotEnumerable, RaisesException] void enqueue(
         optional any chunk);
     [CallWith=ScriptState, NotEnumerable] void error(optional any e);
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc b/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
index 74556d7..4ed6a28 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
@@ -4,8 +4,11 @@
 
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.h"
 
+#include "base/optional.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_default_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
 #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
@@ -110,11 +113,86 @@
   ScopedPersistent<v8::Value> js_controller_;
 };
 
+class ReadableStreamDefaultControllerNative final
+    : public ReadableStreamDefaultControllerInterface {
+ public:
+  explicit ReadableStreamDefaultControllerNative(ScriptValue controller)
+      : ReadableStreamDefaultControllerInterface(controller.GetScriptState()) {
+    DCHECK(RuntimeEnabledFeatures::StreamsNativeEnabled());
+
+    v8::Local<v8::Object> controller_object =
+        controller.V8Value().As<v8::Object>();
+    controller_ = V8ReadableStreamDefaultController::ToImpl(controller_object);
+
+    DCHECK(controller_);
+  }
+
+  void NoteHasBeenCanceled() override { controller_ = nullptr; }
+
+  bool IsActive() const override { return controller_; }
+
+  void Close() override {
+    if (!controller_)
+      return;
+
+    ScriptState::Scope scope(script_state_);
+
+    ReadableStreamDefaultController::Close(script_state_, controller_);
+  }
+
+  double DesiredSize() const override {
+    if (!controller_)
+      return 0.0;
+
+    base::Optional<double> desired_size = controller_->GetDesiredSize();
+    DCHECK(desired_size.has_value());
+    return desired_size.value();
+  }
+
+  void Enqueue(v8::Local<v8::Value> js_chunk) const override {
+    if (!controller_)
+      return;
+
+    ScriptState::Scope scope(script_state_);
+
+    ExceptionState exception_state(script_state_->GetIsolate(),
+                                   ExceptionState::kUnknownContext, "", "");
+    ReadableStreamDefaultController::Enqueue(script_state_, controller_,
+                                             js_chunk, exception_state);
+    if (exception_state.HadException()) {
+      DLOG(WARNING) << "Ignoring exception from Enqueue()";
+      exception_state.ClearException();
+    }
+  }
+
+  void Error(v8::Local<v8::Value> js_error) override {
+    if (!controller_)
+      return;
+
+    ScriptState::Scope scope(script_state_);
+
+    ReadableStreamDefaultController::Error(script_state_, controller_,
+                                           js_error);
+  }
+
+  void Trace(Visitor* visitor) override {
+    visitor->Trace(controller_);
+    ReadableStreamDefaultControllerInterface::Trace(visitor);
+  }
+
+ private:
+  TraceWrapperMember<ReadableStreamDefaultController> controller_;
+};
+
 }  // namespace
 
 ReadableStreamDefaultControllerInterface*
 ReadableStreamDefaultControllerInterface::Create(ScriptValue controller) {
-  // TODO(ricea): Support the StreamsNative implementation.
+  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
+    return MakeGarbageCollected<ReadableStreamDefaultControllerNative>(
+        controller);
+  }
+
   return MakeGarbageCollected<ReadableStreamDefaultControllerWrapper>(
       controller);
 }
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc b/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc
index 87e45d8..039679d 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_reader.cc
@@ -5,7 +5,8 @@
 #include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_native.h"
 #include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -18,58 +19,154 @@
     ScriptState* script_state,
     ReadableStream* stream,
     ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return nullptr;
+  DCHECK(RuntimeEnabledFeatures::StreamsNativeEnabled());
+  auto* stream_native = static_cast<ReadableStreamNative*>(stream);
+  auto* reader = MakeGarbageCollected<ReadableStreamDefaultReader>(
+      script_state, stream_native, exception_state);
+  if (exception_state.HadException()) {
+    return nullptr;
+  }
+  return reader;
 }
 
 ReadableStreamDefaultReader::ReadableStreamDefaultReader(
     ScriptState* script_state,
     ReadableStreamNative* stream,
     ExceptionState& exception_state) {
-  ThrowUnimplemented(exception_state);
-  return;
+  // https://streams.spec.whatwg.org/#default-reader-constructor
+  // 2. If ! IsReadableStreamLocked(stream) is true, throw a TypeError
+  //    exception.
+  if (ReadableStreamNative::IsLocked(stream)) {
+    exception_state.ThrowTypeError(
+        "ReadableStreamReader constructor can only accept readable streams "
+        "that are not yet locked to a reader");
+    return;
+  }
+
+  // 3. Perform ! ReadableStreamReaderGenericInitialize(this, stream).
+  ReadableStreamNative::ReaderGenericInitialize(script_state, this, stream);
+
+  // 4. Set this.[[readRequests]] to a new empty List.
+  DCHECK_EQ(read_requests_.size(), 0u);
 }
 
 ReadableStreamDefaultReader::~ReadableStreamDefaultReader() = default;
 
 ScriptPromise ReadableStreamDefaultReader::closed(
     ScriptState* script_state) const {
-  return RejectUnimplemented(script_state);
+  // https://streams.spec.whatwg.org/#default-reader-closed
+  //  2. Return this.[[closedPromise]].
+  return closed_promise_->GetScriptPromise(script_state);
 }
 
 ScriptPromise ReadableStreamDefaultReader::cancel(ScriptState* script_state) {
-  return RejectUnimplemented(script_state);
+  return cancel(
+      script_state,
+      ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())));
 }
 
 ScriptPromise ReadableStreamDefaultReader::cancel(ScriptState* script_state,
                                                   ScriptValue reason) {
-  return RejectUnimplemented(script_state);
+  // https://streams.spec.whatwg.org/#default-reader-cancel
+  // 2. If this.[[ownerReadableStream]] is undefined, return a promise rejected
+  //    with a TypeError exception.
+  if (!owner_readable_stream_) {
+    return ScriptPromise::Reject(
+        script_state,
+        v8::Exception::TypeError(V8String(
+            script_state->GetIsolate(),
+            "This readable stream reader has been released and cannot be used "
+            "to cancel its previous owner stream")));
+  }
+
+  // 3. Return ! ReadableStreamReaderGenericCancel(this, reason).
+  v8::Local<v8::Promise> result = ReadableStreamNative::ReaderGenericCancel(
+      script_state, this, reason.V8Value());
+  return ScriptPromise(script_state, result);
 }
 
 ScriptPromise ReadableStreamDefaultReader::read(ScriptState* script_state) {
-  return RejectUnimplemented(script_state);
-}
+  // https://streams.spec.whatwg.org/#default-reader-read
+  // 2. If this.[[ownerReadableStream]] is undefined, return a promise rejected
+  //  with a TypeError exception.
+  if (!owner_readable_stream_) {
+    return ScriptPromise::Reject(
+        script_state,
+        v8::Exception::TypeError(V8String(
+            script_state->GetIsolate(),
+            "This readable stream reader has been released and cannot be used "
+            "to read from its previous owner stream")));
+  }
 
-ScriptPromise ReadableStreamDefaultReader::read(ScriptState* script_state,
-                                                ScriptValue chunk) {
-  return RejectUnimplemented(script_state);
-}
-
-void ReadableStreamDefaultReader::releaseLock(ScriptState* script_state) {
-  return;
-}
-
-void ReadableStreamDefaultReader::ThrowUnimplemented(
-    ExceptionState& exception_state) {
-  exception_state.ThrowTypeError("unimplemented");
-}
-
-ScriptPromise ReadableStreamDefaultReader::RejectUnimplemented(
-    ScriptState* script_state) {
-  return StreamPromiseResolver::CreateRejected(
-             script_state, v8::Exception::TypeError(V8String(
-                               script_state->GetIsolate(), "unimplemented")))
+  // 3. Return ! ReadableStreamDefaultReaderRead(this).
+  return ReadableStreamDefaultReader::Read(script_state, this)
       ->GetScriptPromise(script_state);
 }
 
+void ReadableStreamDefaultReader::releaseLock(ScriptState* script_state,
+                                              ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#default-reader-release-lock
+  // 2. If this.[[ownerReadableStream]] is undefined, return.
+  if (!owner_readable_stream_) {
+    return;
+  }
+
+  // 3. If this.[[readRequests]] is not empty, throw a TypeError exception.
+  if (read_requests_.size() > 0) {
+    exception_state.ThrowTypeError(
+        "Cannot release a readable stream reader when it still has outstanding "
+        "read() calls that have not yet settled");
+    return;
+  }
+
+  // 4. Perform ! ReadableStreamReaderGenericRelease(this).
+  ReadableStreamNative::ReaderGenericRelease(script_state, this);
+}
+
+StreamPromiseResolver* ReadableStreamDefaultReader::Read(
+    ScriptState* script_state,
+    ReadableStreamDefaultReader* reader) {
+  auto* isolate = script_state->GetIsolate();
+  // https://streams.spec.whatwg.org/#readable-stream-default-reader-read
+  // 1. Let stream be reader.[[ownerReadableStream]].
+  ReadableStreamNative* stream = reader->owner_readable_stream_;
+
+  // 2. Assert: stream is not undefined.
+  DCHECK(stream);
+
+  // 3. Set stream.[[disturbed]] to true.
+  stream->is_disturbed_ = true;
+
+  switch (stream->state_) {
+    // 4. If stream.[[state]] is "closed", return a promise resolved with !
+    //    ReadableStreamCreateReadResult(undefined, true,
+    //    reader.[[forAuthorCode]]).
+    case ReadableStreamNative::kClosed:
+      return StreamPromiseResolver::CreateResolved(
+          script_state, ReadableStreamNative::CreateReadResult(
+                            script_state, v8::Undefined(isolate), true,
+                            reader->for_author_code_));
+
+    // 5. If stream.[[state]] is "errored", return a promise rejected with
+    //    stream.[[storedError]].
+    case ReadableStreamNative::kErrored:
+      return StreamPromiseResolver::CreateRejected(
+          script_state, stream->GetStoredError(isolate));
+
+    case ReadableStreamNative::kReadable:
+      // 6. Assert: stream.[[state]] is "readable".
+      DCHECK_EQ(stream->state_, ReadableStreamNative::kReadable);
+
+      // 7. Return ! stream.[[readableStreamController]].[[PullSteps]]().
+      return stream->GetController()->PullSteps(script_state);
+  }
+}
+
+void ReadableStreamDefaultReader::Trace(Visitor* visitor) {
+  visitor->Trace(closed_promise_);
+  visitor->Trace(owner_readable_stream_);
+  visitor->Trace(read_requests_);
+  ScriptWrappable::Trace(visitor);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_reader.h b/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
index ad7d9ef..b36d29bd 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_reader.h
@@ -5,8 +5,10 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_READER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_DEFAULT_READER_H_
 
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "v8/include/v8.h"
 
 namespace blink {
@@ -14,9 +16,10 @@
 class ExceptionState;
 class ScriptPromise;
 class ScriptState;
-class ScriptValue;
 class ReadableStream;
 class ReadableStreamNative;
+class StreamPromiseResolver;
+class Visitor;
 
 class ReadableStreamDefaultReader : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
@@ -26,24 +29,45 @@
                                              ReadableStream* stream,
                                              ExceptionState&);
 
+  // https://streams.spec.whatwg.org/#default-reader-constructor
   ReadableStreamDefaultReader(ScriptState*,
                               ReadableStreamNative* stream,
                               ExceptionState&);
   ~ReadableStreamDefaultReader() override;
 
+  // https://streams.spec.whatwg.org/#default-reader-closed
   ScriptPromise closed(ScriptState*) const;
 
+  // https://streams.spec.whatwg.org/#default-reader-cancel
   ScriptPromise cancel(ScriptState*);
   ScriptPromise cancel(ScriptState*, ScriptValue reason);
 
+  // https://streams.spec.whatwg.org/#default-reader-read
   ScriptPromise read(ScriptState*);
-  ScriptPromise read(ScriptState*, ScriptValue chunk);
 
-  void releaseLock(ScriptState*);
+  // https://streams.spec.whatwg.org/#default-reader-release-lock
+  void releaseLock(ScriptState*, ExceptionState&);
+
+  //
+  // Readable stream reader abstract operations
+  //
+
+  // https://streams.spec.whatwg.org/#readable-stream-default-reader-read
+  static StreamPromiseResolver* Read(ScriptState* script_state,
+                                     ReadableStreamDefaultReader* reader);
+
+  StreamPromiseResolver* ClosedPromise() { return closed_promise_; }
+
+  void Trace(Visitor*) override;
 
  private:
-  static void ThrowUnimplemented(ExceptionState&);
-  static ScriptPromise RejectUnimplemented(ScriptState*);
+  friend class ReadableStreamDefaultController;
+  friend class ReadableStreamNative;
+
+  TraceWrapperMember<StreamPromiseResolver> closed_promise_;
+  bool for_author_code_ = true;
+  TraceWrapperMember<ReadableStreamNative> owner_readable_stream_;
+  HeapDeque<TraceWrapperMember<StreamPromiseResolver>> read_requests_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl b/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
index a57b5e4..1a1fee3 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
@@ -18,5 +18,5 @@
     [CallWith=ScriptState, NotEnumerable] Promise<void> cancel(
         optional any reason);
     [CallWith=ScriptState, NotEnumerable] Promise<void> read();
-    [CallWith=ScriptState, NotEnumerable] void releaseLock();
+    [CallWith=ScriptState, NotEnumerable, RaisesException] void releaseLock();
 };
diff --git a/third_party/blink/renderer/core/streams/readable_stream_native.cc b/third_party/blink/renderer/core/streams/readable_stream_native.cc
new file mode 100644
index 0000000..4a3913f
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/readable_stream_native.cc
@@ -0,0 +1,1221 @@
+// 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/streams/readable_stream_native.h"
+
+#include "base/stl_util.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_reader.h"
+#include "third_party/blink/renderer/core/streams/stream_algorithms.h"
+#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
+#include "third_party/blink/renderer/core/streams/stream_script_function.h"
+#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/core/streams/writable_stream_native.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
+#include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
+
+namespace blink {
+
+class ReadableStreamNative::TeeEngine final
+    : public GarbageCollectedFinalized<TeeEngine> {
+ public:
+  TeeEngine() = default;
+
+  // Create the streams and start copying data.
+  void Start(ScriptState*, ReadableStreamNative*, ExceptionState&);
+
+  // Branch1() and Branch2() are null until Start() is called.
+  ReadableStreamNative* Branch1() const { return branch_[0]; }
+  ReadableStreamNative* Branch2() const { return branch_[1]; }
+
+  void Trace(Visitor* visitor) {
+    visitor->Trace(stream_);
+    visitor->Trace(reader_);
+    visitor->Trace(reason_[0]);
+    visitor->Trace(reason_[1]);
+    visitor->Trace(branch_[0]);
+    visitor->Trace(branch_[1]);
+    visitor->Trace(controller_[0]);
+    visitor->Trace(controller_[1]);
+    visitor->Trace(cancel_promise_);
+  }
+
+ private:
+  class PullAlgorithm;
+  class CancelAlgorithm;
+
+  TraceWrapperMember<ReadableStreamNative> stream_;
+  TraceWrapperMember<ReadableStreamDefaultReader> reader_;
+  TraceWrapperMember<StreamPromiseResolver> cancel_promise_;
+  bool closed_ = false;
+
+  // The standard contains a number of pairs of variables with one for each
+  // stream. These are implemented as arrays here. While they are 1-indexed in
+  // the standard, they are 0-indexed here; ie. "canceled_[0]" here corresponds
+  // to "canceled1" in the standard.
+  bool canceled_[2] = {false, false};
+  TraceWrapperV8Reference<v8::Value> reason_[2];
+  TraceWrapperMember<ReadableStreamNative> branch_[2];
+  TraceWrapperMember<ReadableStreamDefaultController> controller_[2];
+
+  DISALLOW_COPY_AND_ASSIGN(TeeEngine);
+};
+
+class ReadableStreamNative::TeeEngine::PullAlgorithm final
+    : public StreamAlgorithm {
+ public:
+  explicit PullAlgorithm(TeeEngine* engine) : engine_(engine) {}
+
+  v8::Local<v8::Promise> Run(ScriptState* script_state,
+                             int,
+                             v8::Local<v8::Value>[]) override {
+    // https://streams.spec.whatwg.org/#readable-stream-tee
+    // 12. Let pullAlgorithm be the following steps:
+    //   a. Return the result of transforming ! ReadableStreamDefaultReaderRead(
+    //      reader) with a fulfillment handler which takes the argument result
+    //      and performs the following steps:
+    return StreamThenPromise(
+        script_state->GetContext(),
+        ReadableStreamDefaultReader::Read(script_state, engine_->reader_)
+            ->V8Promise(script_state->GetIsolate()),
+        MakeGarbageCollected<ResolveFunction>(script_state, engine_));
+  }
+
+  void Trace(Visitor* visitor) override {
+    visitor->Trace(engine_);
+    StreamAlgorithm::Trace(visitor);
+  }
+
+ private:
+  class ResolveFunction final : public StreamScriptFunction {
+   public:
+    ResolveFunction(ScriptState* script_state, TeeEngine* engine)
+        : StreamScriptFunction(script_state), engine_(engine) {}
+
+    void CallWithLocal(v8::Local<v8::Value> result) override {
+      //    i. If closed is true, return.
+      if (engine_->closed_) {
+        return;
+      }
+
+      //   ii. Assert: Type(result) is Object.
+      DCHECK(result->IsObject());
+
+      auto* script_state = GetScriptState();
+      auto* isolate = script_state->GetIsolate();
+
+      //  iii. Let done be ! Get(result, "done").
+      //   vi. Let value be ! Get(result, "value").
+      // The precise order of operations is not important here, because |result|
+      // is guaranteed to have own properties of "value" and "done" and so the
+      // "Get" operations cannot have side-effects.
+      v8::Local<v8::Value> value;
+      bool done = false;
+      bool unpack_succeeded =
+          V8UnpackIteratorResult(script_state, result.As<v8::Object>(), &done)
+              .ToLocal(&value);
+      CHECK(unpack_succeeded);
+
+      //   vi. Assert: Type(done) is Boolean.
+      //    v. If done is true,
+      if (done) {
+        //    1. If canceled1 is false,
+        //        a. Perform ! ReadableStreamDefaultControllerClose(branch1.
+        //           [[readableStreamController]]).
+        //    2. If canceled2 is false,
+        //        b. Perform ! ReadableStreamDefaultControllerClose(branch2.
+        //           [[readableStreamController]]).
+        for (int branch = 0; branch < 2; ++branch) {
+          if (!engine_->canceled_[branch]) {
+            ReadableStreamDefaultController::Close(
+                script_state, engine_->controller_[branch]);
+          }
+        }
+        //    3. Set closed to true.
+        engine_->closed_ = true;
+
+        //    4. Return.
+        return;
+      }
+      ExceptionState exception_state(isolate, ExceptionState::kUnknownContext,
+                                     "", "");
+      //  vii. Let value1 and value2 be value.
+      // viii. If canceled2 is false and cloneForBranch2 is true, set value2 to
+      //       ? StructuredDeserialize(? StructuredSerialize(value2), the
+      //       current Realm Record).
+      // TODO(ricea): Support cloneForBranch2
+
+      //   ix. If canceled1 is false, perform ?
+      //       ReadableStreamDefaultControllerEnqueue(branch1.
+      //       [[readableStreamController]], value1).
+      //    x. If canceled2 is false, perform ?
+      //       ReadableStreamDefaultControllerEnqueue(branch2.
+      //       [[readableStreamController]], value2).
+      for (int branch = 0; branch < 2; ++branch) {
+        if (!engine_->canceled_[branch]) {
+          ReadableStreamDefaultController::Enqueue(script_state,
+                                                   engine_->controller_[branch],
+                                                   value, exception_state);
+          if (exception_state.HadException()) {
+            // Instead of returning a rejection, which is inconvenient here,
+            // call ControllerError(). The only difference this makes is that
+            // it happens synchronously, but that should not be observable.
+            ReadableStreamDefaultController::Error(
+                script_state, engine_->controller_[branch],
+                exception_state.GetException());
+            exception_state.ClearException();
+            return;
+          }
+        }
+      }
+    }
+
+    void Trace(Visitor* visitor) override {
+      visitor->Trace(engine_);
+      StreamScriptFunction::Trace(visitor);
+    }
+
+   private:
+    TraceWrapperMember<TeeEngine> engine_;
+  };
+
+  TraceWrapperMember<TeeEngine> engine_;
+};
+
+class ReadableStreamNative::TeeEngine::CancelAlgorithm final
+    : public StreamAlgorithm {
+ public:
+  CancelAlgorithm(TeeEngine* engine, int branch)
+      : engine_(engine), branch_(branch) {
+    DCHECK(branch == 0 || branch == 1);
+  }
+
+  v8::Local<v8::Promise> Run(ScriptState* script_state,
+                             int argc,
+                             v8::Local<v8::Value> argv[]) override {
+    // https://streams.spec.whatwg.org/#readable-stream-tee
+    // This implements both cancel1Algorithm and cancel2Algorithm as they are
+    // identical except for the index they operate on. Standard comments are
+    // from cancel1Algorithm.
+    // 13. Let cancel1Algorithm be the following steps, taking a reason
+    //     argument:
+    auto* isolate = script_state->GetIsolate();
+
+    // a. Set canceled1 to true.
+    engine_->canceled_[branch_] = true;
+    DCHECK_EQ(argc, 1);
+
+    // b. Set reason1 to reason.
+    engine_->reason_[branch_].Set(isolate, argv[0]);
+
+    const int other_branch = 1 - branch_;
+
+    // c. If canceled2 is true,
+    if (engine_->canceled_[other_branch]) {
+      // i. Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).
+      v8::Local<v8::Value> reason[] = {engine_->reason_[0].NewLocal(isolate),
+                                       engine_->reason_[1].NewLocal(isolate)};
+      v8::Local<v8::Value> composite_reason =
+          v8::Array::New(script_state->GetIsolate(), reason, 2);
+
+      // ii. Let cancelResult be ! ReadableStreamCancel(stream,
+      //    compositeReason).
+      auto cancel_result = ReadableStreamNative::Cancel(
+          script_state, engine_->stream_, composite_reason);
+
+      // iii. Resolve cancelPromise with cancelResult.
+      engine_->cancel_promise_->Resolve(script_state, cancel_result);
+    }
+    return engine_->cancel_promise_->V8Promise(isolate);
+  }
+
+  void Trace(Visitor* visitor) override {
+    visitor->Trace(engine_);
+    StreamAlgorithm::Trace(visitor);
+  }
+
+ private:
+  TraceWrapperMember<TeeEngine> engine_;
+  const int branch_;
+};
+
+void ReadableStreamNative::TeeEngine::Start(ScriptState* script_state,
+                                            ReadableStreamNative* stream,
+                                            ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#readable-stream-tee
+  //  1. Assert: ! IsReadableStream(stream) is true.
+  DCHECK(stream);
+
+  // TODO(ricea):  2. Assert: Type(cloneForBranch2) is Boolean.
+
+  stream_ = stream;
+
+  // 3. Let reader be ? AcquireReadableStreamDefaultReader(stream).
+  reader_ = ReadableStreamNative::AcquireDefaultReader(script_state, stream,
+                                                       false, exception_state);
+  if (exception_state.HadException()) {
+    return;
+  }
+
+  // These steps are performed by the constructor:
+  //  4. Let closed be false.
+  DCHECK(!closed_);
+
+  //  5. Let canceled1 be false.
+  DCHECK(!canceled_[0]);
+
+  //  6. Let canceled2 be false.
+  DCHECK(!canceled_[1]);
+
+  //  7. Let reason1 be undefined.
+  DCHECK(reason_[0].IsEmpty());
+
+  //  8. Let reason2 be undefined.
+  DCHECK(reason_[1].IsEmpty());
+
+  //  9. Let branch1 be undefined.
+  DCHECK(!branch_[0]);
+
+  // 10. Let branch2 be undefined.
+  DCHECK(!branch_[1]);
+
+  // 11. Let cancelPromise be a new promise.
+  cancel_promise_ = MakeGarbageCollected<StreamPromiseResolver>(script_state);
+
+  // 12. Let pullAlgorithm be the following steps:
+  // (steps are defined in PullAlgorithm::Run()).
+  auto* pull_algorithm = MakeGarbageCollected<PullAlgorithm>(this);
+
+  // 13. Let cancel1Algorithm be the following steps, taking a reason argument:
+  // (see CancelAlgorithm::Run()).
+  auto* cancel1_algorithm = MakeGarbageCollected<CancelAlgorithm>(this, 0);
+
+  // 14. Let cancel2Algorithm be the following steps, taking a reason argument:
+  // (both algorithms share a single implementation).
+  auto* cancel2_algorithm = MakeGarbageCollected<CancelAlgorithm>(this, 1);
+
+  // 15. Let startAlgorithm be an algorithm that returns undefined.
+  auto* start_algorithm = CreateTrivialStartAlgorithm();
+
+  auto* size_algorithm = CreateDefaultSizeAlgorithm();
+
+  // 16. Set branch1 to ! CreateReadableStream(startAlgorithm, pullAlgorithm,
+  //   cancel1Algorithm).
+  branch_[0] = ReadableStreamNative::Create(
+      script_state, start_algorithm, pull_algorithm, cancel1_algorithm, 1.0,
+      size_algorithm, exception_state);
+  if (exception_state.HadException()) {
+    return;
+  }
+
+  // 17. Set branch2 to ! CreateReadableStream(startAlgorithm, pullAlgorithm,
+  //   cancel2Algorithm).
+  branch_[1] = ReadableStreamNative::Create(
+      script_state, start_algorithm, pull_algorithm, cancel2_algorithm, 1.0,
+      size_algorithm, exception_state);
+  if (exception_state.HadException()) {
+    return;
+  }
+
+  for (int branch = 0; branch < 2; ++branch) {
+    controller_[branch] = branch_[branch]->readable_stream_controller_;
+  }
+
+  class RejectFunction final : public StreamScriptFunction {
+   public:
+    RejectFunction(ScriptState* script_state, TeeEngine* engine)
+        : StreamScriptFunction(script_state), engine_(engine) {}
+
+    void CallWithLocal(v8::Local<v8::Value> r) override {
+      // 18. Upon rejection of reader.[[closedPromise]] with reason r,
+      //   a. Perform ! ReadableStreamDefaultControllerError(branch1.
+      //      [[readableStreamController]], r).
+      ReadableStreamDefaultController::Error(GetScriptState(),
+                                             engine_->controller_[0], r);
+
+      //   b. Perform ! ReadableStreamDefaultControllerError(branch2.
+      //      [[readableStreamController]], r).
+      ReadableStreamDefaultController::Error(GetScriptState(),
+                                             engine_->controller_[1], r);
+    }
+
+    void Trace(Visitor* visitor) override {
+      visitor->Trace(engine_);
+      StreamScriptFunction::Trace(visitor);
+    }
+
+   private:
+    TraceWrapperMember<TeeEngine> engine_;
+  };
+
+  // 18. Upon rejection of reader.[[closedPromise]] with reason r,
+  StreamThenPromise(
+      script_state->GetContext(),
+      reader_->closed_promise_->V8Promise(script_state->GetIsolate()), nullptr,
+      MakeGarbageCollected<RejectFunction>(script_state, this));
+
+  // Step "19. Return « branch1, branch2 »."
+  // is performed by the caller.
+}
+
+class ReadableStreamNative::ReadHandleImpl final
+    : public ReadableStream::ReadHandle {
+ public:
+  explicit ReadHandleImpl(ReadableStreamDefaultReader* reader)
+      : reader_(reader) {}
+  ~ReadHandleImpl() override = default;
+
+  ScriptPromise Read(ScriptState* script_state) override {
+    return ReadableStreamDefaultReader::Read(script_state, reader_)
+        ->GetScriptPromise(script_state);
+  }
+
+  void Trace(Visitor* visitor) override {
+    visitor->Trace(reader_);
+    ReadHandle::Trace(visitor);
+  }
+
+ private:
+  const TraceWrapperMember<ReadableStreamDefaultReader> reader_;
+};
+
+ReadableStreamNative* ReadableStreamNative::Create(
+    ScriptState* script_state,
+    ScriptValue underlying_source,
+    ScriptValue strategy,
+    ExceptionState& exception_state) {
+  auto* stream = MakeGarbageCollected<ReadableStreamNative>(
+      script_state, underlying_source, strategy, false, exception_state);
+  if (exception_state.HadException()) {
+    return nullptr;
+  }
+
+  return stream;
+}
+
+ReadableStreamNative* ReadableStreamNative::CreateWithCountQueueingStrategy(
+    ScriptState* script_state,
+    UnderlyingSourceBase* underlying_source,
+    size_t high_water_mark) {
+  auto* isolate = script_state->GetIsolate();
+
+  // It's safer to use a workalike rather than a real CountQueuingStrategy
+  // object. We use the default "size" function as it is implemented in C++ and
+  // so much faster than calling into JavaScript. Since the create object has a
+  // null prototype, there is no danger of us finding some other "size" function
+  // via the prototype chain.
+  v8::Local<v8::Name> high_water_mark_string =
+      V8AtomicString(isolate, "highWaterMark");
+  v8::Local<v8::Value> high_water_mark_value =
+      v8::Number::New(isolate, high_water_mark);
+
+  auto strategy_object =
+      v8::Object::New(isolate, v8::Null(isolate), &high_water_mark_string,
+                      &high_water_mark_value, 1);
+
+  ExceptionState exception_state(script_state->GetIsolate(),
+                                 ExceptionState::kConstructionContext,
+                                 "ReadableStream");
+
+  v8::Local<v8::Value> underlying_source_v8 =
+      ToV8(underlying_source, script_state);
+
+  auto* stream = MakeGarbageCollected<ReadableStreamNative>(
+      script_state, ScriptValue(script_state, underlying_source_v8),
+      ScriptValue(script_state, strategy_object), true, exception_state);
+
+  if (exception_state.HadException()) {
+    exception_state.ClearException();
+    DLOG(WARNING)
+        << "Ignoring an exception in CreateWithCountQueuingStrategy().";
+  }
+
+  return stream;
+}
+
+ReadableStreamNative* ReadableStreamNative::Create(
+    ScriptState* script_state,
+    StreamStartAlgorithm* start_algorithm,
+    StreamAlgorithm* pull_algorithm,
+    StreamAlgorithm* cancel_algorithm,
+    double high_water_mark,
+    StrategySizeAlgorithm* size_algorithm,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#create-readable-stream
+  // All arguments are compulsory in this implementation, so the first two steps
+  // are skipped:
+  // 1. If highWaterMark was not passed, set it to 1.
+  // 2. If sizeAlgorithm was not passed, set it to an algorithm that returns 1.
+
+  // 3. Assert: ! IsNonNegativeNumber(highWaterMark) is true.
+  DCHECK_GE(high_water_mark, 0);
+
+  // 4. Let stream be ObjectCreate(the original value of ReadableStream's
+  //    prototype property).
+  auto* stream = MakeGarbageCollected<ReadableStreamNative>();
+
+  // 5. Perform ! InitializeReadableStream(stream).
+  Initialize(stream);
+
+  // 6. Let controller be ObjectCreate(the original value of
+  //    ReadableStreamDefaultController's prototype property).
+  auto* controller = MakeGarbageCollected<ReadableStreamDefaultController>();
+
+  // 7. Perform ? SetUpReadableStreamDefaultController(stream, controller,
+  //    startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark,
+  //    sizeAlgorithm).
+  ReadableStreamDefaultController::SetUp(
+      script_state, stream, controller, start_algorithm, pull_algorithm,
+      cancel_algorithm, high_water_mark, size_algorithm, false,
+      exception_state);
+  if (exception_state.HadException()) {
+    return nullptr;
+  }
+
+  // 8. Return stream.
+  return stream;
+}
+
+ReadableStreamNative::ReadableStreamNative() = default;
+
+// TODO(ricea): Remove |enable_blink_lock_notifications| once
+// blink::ReadableStreamOperations has been updated to use CreateReadableStream.
+ReadableStreamNative::ReadableStreamNative(ScriptState* script_state,
+                                           ScriptValue raw_underlying_source,
+                                           ScriptValue raw_strategy,
+                                           bool enable_blink_lock_notifications,
+                                           ExceptionState& exception_state) {
+  if (!enable_blink_lock_notifications) {
+    // TODO(ricea): Move this to IDL once blink::ReadableStreamOperations is
+    // no longer using the public constructor.
+    UseCounter::Count(ExecutionContext::From(script_state),
+                      WebFeature::kReadableStreamConstructor);
+  }
+
+  // https://streams.spec.whatwg.org/#rs-constructor
+  //  1. Perform ! InitializeReadableStream(this).
+  Initialize(this);
+
+  // The next part of this constructor corresponds to the object conversions
+  // that are implicit in the definition in the standard.
+  DCHECK(!raw_underlying_source.IsEmpty());
+  DCHECK(!raw_strategy.IsEmpty());
+
+  auto context = script_state->GetContext();
+  auto* isolate = script_state->GetIsolate();
+
+  // TODO(ricea): Share some of this code with WritableStreamNative.
+
+  auto underlying_source_value = raw_underlying_source.V8Value();
+  if (underlying_source_value->IsUndefined()) {
+    underlying_source_value = v8::Object::New(isolate);
+  }
+  v8::TryCatch try_catch(isolate);
+  v8::Local<v8::Object> underlying_source;
+  if (!underlying_source_value->ToObject(context).ToLocal(&underlying_source)) {
+    exception_state.RethrowV8Exception(try_catch.Exception());
+    return;
+  }
+
+  auto strategy_value = raw_strategy.V8Value();
+  if (strategy_value->IsUndefined()) {
+    strategy_value = v8::Object::New(isolate);
+  }
+  v8::Local<v8::Object> strategy;
+  v8::MaybeLocal<v8::Object> strategy_maybe = strategy_value->ToObject(context);
+  if (!strategy_maybe.ToLocal(&strategy)) {
+    exception_state.RethrowV8Exception(try_catch.Exception());
+    return;
+  }
+
+  // 2. Let size be ? GetV(strategy, "size").
+  v8::Local<v8::Value> size;
+  if (!strategy->Get(context, V8AtomicString(isolate, "size")).ToLocal(&size)) {
+    exception_state.RethrowV8Exception(try_catch.Exception());
+    return;
+  }
+
+  // 3. Let highWaterMark be ? GetV(strategy, "highWaterMark").
+  v8::Local<v8::Value> high_water_mark_value;
+  if (!strategy->Get(context, V8AtomicString(isolate, "highWaterMark"))
+           .ToLocal(&high_water_mark_value)) {
+    exception_state.RethrowV8Exception(try_catch.Exception());
+    return;
+  }
+
+  // 4. Let type be ? GetV(underlyingSource, "type").
+  v8::Local<v8::Value> type;
+  if (!underlying_source->Get(context, V8AtomicString(isolate, "type"))
+           .ToLocal(&type)) {
+    exception_state.RethrowV8Exception(try_catch.Exception());
+    return;
+  }
+
+  if (!type->IsUndefined()) {
+    // 5. Let typeString be ? ToString(type).
+    v8::Local<v8::String> type_string;
+    if (!type->ToString(context).ToLocal(&type_string)) {
+      exception_state.RethrowV8Exception(try_catch.Exception());
+      return;
+    }
+
+    // 6. If typeString is "bytes",
+    if (type_string == V8AtomicString(isolate, "bytes")) {
+      // TODO(ricea): Implement bytes type.
+      exception_state.ThrowRangeError("bytes type is not yet implemented");
+      return;
+    }
+
+    // 8. Otherwise, throw a RangeError exception.
+    exception_state.ThrowRangeError("Invalid type is specified");
+    return;
+  }
+
+  // 7. Otherwise, if type is undefined,
+  //   a. Let sizeAlgorithm be ? MakeSizeAlgorithmFromSizeFunction(size).
+  auto* size_algorithm =
+      MakeSizeAlgorithmFromSizeFunction(script_state, size, exception_state);
+  if (exception_state.HadException()) {
+    return;
+  }
+  DCHECK(size_algorithm);
+
+  // 2. If highWaterMark is undefined, let highWaterMark be 1.
+  double high_water_mark = 1;
+  if (!high_water_mark_value->IsUndefined()) {
+    // The conversion to Number which happens inside
+    // ValidateAndNormalizeHighWaterMark in the standard is performed beforehand
+    // here.
+    v8::Local<v8::Number> high_water_mark_as_number;
+    if (!high_water_mark_value->ToNumber(context).ToLocal(
+            &high_water_mark_as_number)) {
+      exception_state.RethrowV8Exception(try_catch.Exception());
+      return;
+    }
+    high_water_mark = high_water_mark_as_number->Value();
+  }
+
+  //  3. Set highWaterMark to ? ValidateAndNormalizeHighWaterMark(
+  //     highWaterMark).
+  high_water_mark =
+      ValidateAndNormalizeHighWaterMark(high_water_mark, exception_state);
+  if (exception_state.HadException()) {
+    return;
+  }
+
+  // 4. Perform ? SetUpReadableStreamDefaultControllerFromUnderlyingSource
+  //  (this, underlyingSource, highWaterMark, sizeAlgorithm).
+  ReadableStreamDefaultController::SetUpFromUnderlyingSource(
+      script_state, this, underlying_source, high_water_mark, size_algorithm,
+      enable_blink_lock_notifications, exception_state);
+}
+
+ReadableStreamNative::~ReadableStreamNative() = default;
+
+bool ReadableStreamNative::locked(ScriptState* script_state,
+                                  ExceptionState& exception_state) const {
+  // https://streams.spec.whatwg.org/#rs-locked
+  // 2. Return ! IsReadableStreamLocked(this).
+  return IsLocked(this);
+}
+
+ScriptPromise ReadableStreamNative::cancel(ScriptState* script_state,
+                                           ExceptionState& exception_state) {
+  return cancel(
+      script_state,
+      ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())),
+      exception_state);
+}
+
+ScriptPromise ReadableStreamNative::cancel(ScriptState* script_state,
+                                           ScriptValue reason,
+                                           ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#rs-cancel
+  // 2. If ! IsReadableStreamLocked(this) is true, return a promise rejected
+  //    with a TypeError exception.
+  if (IsLocked(this)) {
+    exception_state.ThrowTypeError("Cannot cancel a locked stream");
+    return ScriptPromise();
+  }
+
+  // 3. Return ! ReadableStreamCancel(this, reason).
+  v8::Local<v8::Promise> result = Cancel(script_state, this, reason.V8Value());
+  return ScriptPromise(script_state, result);
+}
+
+ScriptValue ReadableStreamNative::getReader(ScriptState* script_state,
+                                            ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#rs-get-reader
+  // 2. If mode is undefined, return ? AcquireReadableStreamDefaultReader(this,
+  //    true).
+  auto* reader = ReadableStreamNative::AcquireDefaultReader(
+      script_state, this, true, exception_state);
+  if (!reader) {
+    return ScriptValue();
+  }
+
+  return ScriptValue(script_state, ToV8(reader, script_state));
+}
+
+ScriptValue ReadableStreamNative::getReader(ScriptState* script_state,
+                                            ScriptValue options,
+                                            ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#rs-get-reader
+  // Since we don't support byob readers, the only thing
+  // GetReaderValidateOptions() needs to do is throw an exception if
+  // |options.mode| is invalid.
+  GetReaderValidateOptions(script_state, options, exception_state);
+  if (exception_state.HadException()) {
+    return ScriptValue();
+  }
+
+  return getReader(script_state, exception_state);
+}
+
+ScriptValue ReadableStreamNative::pipeThrough(ScriptState* script_state,
+                                              ScriptValue transform_stream,
+                                              ExceptionState& exception_state) {
+  return pipeThrough(
+      script_state, transform_stream,
+      ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())),
+      exception_state);
+}
+
+// https://streams.spec.whatwg.org/#rs-pipe-through
+ScriptValue ReadableStreamNative::pipeThrough(ScriptState* script_state,
+                                              ScriptValue transform_stream,
+                                              ScriptValue options,
+                                              ExceptionState& exception_state) {
+  exception_state.ThrowTypeError("pipeThrough not yet implemented");
+  return ScriptValue();
+}
+
+ScriptPromise ReadableStreamNative::pipeTo(ScriptState* script_state,
+                                           ScriptValue destination,
+                                           ExceptionState& exception_state) {
+  return pipeTo(
+      script_state, destination,
+      ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())),
+      exception_state);
+}
+
+ScriptPromise ReadableStreamNative::pipeTo(ScriptState* script_state,
+                                           ScriptValue destination_value,
+                                           ScriptValue options,
+                                           ExceptionState& exception_state) {
+  exception_state.ThrowTypeError("pipeTo not yet implemented");
+  return ScriptPromise();
+}
+
+ScriptValue ReadableStreamNative::tee(ScriptState* script_state,
+                                      ExceptionState& exception_state) {
+  return CallTeeAndReturnBranchArray(script_state, this, exception_state);
+}
+
+//
+// Readable stream abstract operations
+//
+ReadableStreamDefaultReader* ReadableStreamNative::AcquireDefaultReader(
+    ScriptState* script_state,
+    ReadableStreamNative* stream,
+    bool for_author_code,
+    ExceptionState& exception_state) {
+  // https://streams.spec.whatwg.org/#acquire-readable-stream-reader
+  // for_author_code is compulsory in this implementation
+  // 1. If forAuthorCode was not passed, set it to false.
+
+  // 2. Let reader be ? Construct(ReadableStreamDefaultReader, « stream »).
+  auto* reader = MakeGarbageCollected<ReadableStreamDefaultReader>(
+      script_state, stream, exception_state);
+  if (exception_state.HadException()) {
+    return nullptr;
+  }
+
+  // 3. Set reader.[[forAuthorCode]] to forAuthorCode.
+  reader->for_author_code_ = for_author_code;
+
+  // 4. Return reader.
+  return reader;
+}
+
+void ReadableStreamNative::Initialize(ReadableStreamNative* stream) {
+  // Fields are initialised by the constructor, so we only check that they were
+  // initialised correctly.
+  // https://streams.spec.whatwg.org/#initialize-readable-stream
+  // 1. Set stream.[[state]] to "readable".
+  DCHECK_EQ(stream->state_, kReadable);
+  // 2. Set stream.[[reader]] and stream.[[storedError]] to undefined.
+  DCHECK(!stream->reader_);
+  DCHECK(stream->stored_error_.IsEmpty());
+  // 3. Set stream.[[disturbed]] to false.
+  DCHECK(!stream->is_disturbed_);
+}
+
+// TODO(domenic): cloneForBranch2 argument from spec not supported yet
+void ReadableStreamNative::Tee(ScriptState* script_state,
+                               ReadableStream** branch1,
+                               ReadableStream** branch2,
+                               ExceptionState& exception_state) {
+  auto* engine = MakeGarbageCollected<TeeEngine>();
+  engine->Start(script_state, this, exception_state);
+  if (exception_state.HadException()) {
+    return;
+  }
+
+  // Instead of returning a List like ReadableStreamTee in the standard, the
+  // branches are returned via output parameters.
+  *branch1 = engine->Branch1();
+  *branch2 = engine->Branch2();
+}
+
+ReadableStream::ReadHandle* ReadableStreamNative::GetReadHandle(
+    ScriptState* script_state,
+    ExceptionState& exception_state) {
+  auto* reader = ReadableStreamNative::AcquireDefaultReader(
+      script_state, this, false, exception_state);
+  if (exception_state.HadException()) {
+    return nullptr;
+  }
+  return MakeGarbageCollected<ReadHandleImpl>(reader);
+}
+
+void ReadableStreamNative::LockAndDisturb(ScriptState* script_state,
+                                          ExceptionState& exception_state) {
+  ScriptState::Scope scope(script_state);
+
+  if (reader_) {
+    return;
+  }
+
+  ReadableStreamDefaultReader* reader =
+      AcquireDefaultReader(script_state, this, false, exception_state);
+  if (!reader) {
+    return;
+  }
+
+  is_disturbed_ = true;
+}
+
+void ReadableStreamNative::Serialize(ScriptState* script_state,
+                                     MessagePort* port,
+                                     ExceptionState& exception_state) {
+  // TODO(ricea): Implement this.
+}
+
+v8::Local<v8::Value> ReadableStreamNative::GetStoredError(
+    v8::Isolate* isolate) const {
+  return stored_error_.NewLocal(isolate);
+}
+
+void ReadableStreamNative::Trace(Visitor* visitor) {
+  visitor->Trace(readable_stream_controller_);
+  visitor->Trace(reader_);
+  visitor->Trace(stored_error_);
+  ReadableStream::Trace(visitor);
+}
+
+//
+// Abstract Operations Used By Controllers
+//
+
+StreamPromiseResolver* ReadableStreamNative::AddReadRequest(
+    ScriptState* script_state,
+    ReadableStreamNative* stream) {
+  // https://streams.spec.whatwg.org/#readable-stream-add-read-request
+  // 1. Assert: ! IsReadableStreamDefaultReader(stream.[[reader]]) is true.
+  DCHECK(stream->reader_);
+
+  // 2. Assert: stream.[[state]] is "readable".
+  DCHECK_EQ(stream->state_, kReadable);
+
+  // 3. Let promise be a new promise.
+  auto* promise = MakeGarbageCollected<StreamPromiseResolver>(script_state);
+
+  // This implementation stores promises directly in |read_requests_| rather
+  // than wrapping them in a Record.
+  // 4. Let readRequest be Record {[[promise]]: promise}.
+  // 5. Append readRequest as the last element of stream.[[reader]].
+  //  [[readRequests]].
+  stream->reader_->read_requests_.push_back(promise);
+
+  // 6. Return promise.
+  return promise;
+}
+
+v8::Local<v8::Promise> ReadableStreamNative::Cancel(
+    ScriptState* script_state,
+    ReadableStreamNative* stream,
+    v8::Local<v8::Value> reason) {
+  // https://streams.spec.whatwg.org/#readable-stream-cancel
+  // 1. Set stream.[[disturbed]] to true.
+  stream->is_disturbed_ = true;
+
+  // 2. If stream.[[state]] is "closed", return a promise resolved with
+  //    undefined.
+  const auto state = stream->state_;
+  if (state == kClosed) {
+    return PromiseResolveWithUndefined(script_state);
+  }
+
+  // 3. If stream.[[state]] is "errored", return a promise rejected with stream.
+  //    [[storedError]].
+  if (state == kErrored) {
+    return PromiseReject(script_state,
+                         stream->GetStoredError(script_state->GetIsolate()));
+  }
+
+  // 4. Perform ! ReadableStreamClose(stream).
+  Close(script_state, stream);
+
+  // 5. Let sourceCancelPromise be ! stream.[[readableStreamController]].
+  //    [[CancelSteps]](reason).
+  v8::Local<v8::Promise> source_cancel_promise =
+      stream->readable_stream_controller_->CancelSteps(script_state, reason);
+
+  class ReturnUndefinedFunction : public StreamScriptFunction {
+   public:
+    explicit ReturnUndefinedFunction(ScriptState* script_state)
+        : StreamScriptFunction(script_state) {}
+
+    // The method does nothing; the default value of undefined is returned to
+    // JavaScript.
+    void CallWithLocal(v8::Local<v8::Value>) override {}
+  };
+
+  // 6. Return the result of transforming sourceCancelPromise with a
+  //    fulfillment handler that returns undefined.
+  return StreamThenPromise(
+      script_state->GetContext(), source_cancel_promise,
+      MakeGarbageCollected<ReturnUndefinedFunction>(script_state));
+}
+
+void ReadableStreamNative::Close(ScriptState* script_state,
+                                 ReadableStreamNative* stream) {
+  // https://streams.spec.whatwg.org/#readable-stream-close
+  // 1. Assert: stream.[[state]] is "readable".
+  DCHECK_EQ(stream->state_, kReadable);
+
+  // 2. Set stream.[[state]] to "closed".
+  stream->state_ = kClosed;
+
+  // 3. Let reader be stream.[[reader]].
+  ReadableStreamDefaultReader* reader = stream->reader_;
+
+  // 4. If reader is undefined, return.
+  if (!reader) {
+    return;
+  }
+
+  // TODO(ricea): Support BYOB readers.
+  // 5. If ! IsReadableStreamDefaultReader(reader) is true,
+  //   a. Repeat for each readRequest that is an element of reader.
+  //      [[readRequests]],
+  for (StreamPromiseResolver* promise : reader->read_requests_) {
+    //   i. Resolve readRequest.[[promise]] with !
+    //      ReadableStreamCreateReadResult(undefined, true, reader.
+    //      [[forAuthorCode]]).
+    promise->Resolve(script_state,
+                     CreateReadResult(script_state,
+                                      v8::Undefined(script_state->GetIsolate()),
+                                      true, reader->for_author_code_));
+  }
+
+  //   b. Set reader.[[readRequests]] to an empty List.
+  reader->read_requests_.clear();
+
+  // 6. Resolve reader.[[closedPromise]] with undefined.
+  reader->closed_promise_->ResolveWithUndefined(script_state);
+}
+
+v8::Local<v8::Value> ReadableStreamNative::CreateReadResult(
+    ScriptState* script_state,
+    v8::Local<v8::Value> value,
+    bool done,
+    bool for_author_code) {
+  // https://streams.spec.whatwg.org/#readable-stream-create-read-result
+  auto* isolate = script_state->GetIsolate();
+  auto context = script_state->GetContext();
+  auto value_string = V8AtomicString(isolate, "value");
+  auto done_string = V8AtomicString(isolate, "done");
+  auto done_value = v8::Boolean::New(isolate, done);
+  // 1. Let prototype be null.
+  // 2. If forAuthorCode is true, set prototype to %ObjectPrototype%.
+  // This implementation doesn't use a |prototype| variable, instead using
+  // different code paths depending on the value of |for_author_code|.
+  if (for_author_code) {
+    // 4. Let obj be ObjectCreate(prototype).
+    auto obj = v8::Object::New(isolate);
+
+    // 5. Perform CreateDataProperty(obj, "value", value).
+    obj->CreateDataProperty(context, value_string, value).Check();
+
+    // 6. Perform CreateDataProperty(obj, "done", done).
+    obj->CreateDataProperty(context, done_string, done_value).Check();
+
+    // 7. Return obj.
+    return obj;
+  }
+
+  // When |for_author_code| is false, we can perform all the steps in a single
+  // call to V8.
+
+  // 4. Let obj be ObjectCreate(prototype).
+  // 5. Perform CreateDataProperty(obj, "value", value).
+  // 6. Perform CreateDataProperty(obj, "done", done).
+  // 7. Return obj.
+  // TODO(ricea): Is it possible to use this optimised API in both cases?
+  v8::Local<v8::Name> names[2] = {value_string, done_string};
+  v8::Local<v8::Value> values[2] = {value, done_value};
+
+  static_assert(base::size(names) == base::size(values),
+                "names and values arrays must be the same size");
+  return v8::Object::New(isolate, v8::Null(isolate), names, values,
+                         base::size(names));
+}
+
+void ReadableStreamNative::Error(ScriptState* script_state,
+                                 ReadableStreamNative* stream,
+                                 v8::Local<v8::Value> e) {
+  // https://streams.spec.whatwg.org/#readable-stream-error
+  // 2. Assert: stream.[[state]] is "readable".
+  DCHECK_EQ(stream->state_, kReadable);
+  auto* isolate = script_state->GetIsolate();
+
+  // 3. Set stream.[[state]] to "errored".
+  stream->state_ = kErrored;
+
+  // 4. Set stream.[[storedError]] to e.
+  stream->stored_error_.Set(isolate, e);
+
+  // 5. Let reader be stream.[[reader]].
+  ReadableStreamDefaultReader* reader = stream->reader_;
+
+  // 6. If reader is undefined, return.
+  if (!reader) {
+    return;
+  }
+
+  // 7. If ! IsReadableStreamDefaultReader(reader) is true,
+  // TODO(ricea): Support BYOB readers.
+  //   a. Repeat for each readRequest that is an element of reader.
+  //      [[readRequests]],
+  for (StreamPromiseResolver* promise : reader->read_requests_) {
+    //   i. Reject readRequest.[[promise]] with e.
+    promise->Reject(script_state, e);
+  }
+
+  //   b. Set reader.[[readRequests]] to a new empty List.
+  reader->read_requests_.clear();
+
+  // 9. Reject reader.[[closedPromise]] with e.
+  reader->closed_promise_->Reject(script_state, e);
+
+  // 10. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
+  reader->closed_promise_->MarkAsHandled(isolate);
+}
+
+void ReadableStreamNative::FulfillReadRequest(ScriptState* script_state,
+                                              ReadableStreamNative* stream,
+                                              v8::Local<v8::Value> chunk,
+                                              bool done) {
+  // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-request
+  // 1. Let reader be stream.[[reader]].
+  ReadableStreamDefaultReader* reader = stream->reader_;
+
+  // 2. Let readRequest be the first element of reader.[[readRequests]].
+  StreamPromiseResolver* read_request = reader->read_requests_.front();
+
+  // 3. Remove readIntoRequest from reader.[[readIntoRequests]], shifting all
+  //    other elements downward (so that the second becomes the first, and so
+  //    on).
+  reader->read_requests_.pop_front();
+
+  // 4. Resolve readIntoRequest.[[promise]] with !
+  //    ReadableStreamCreateReadResult(chunk, done, reader.[[forAuthorCode]]).
+  read_request->Resolve(
+      script_state, ReadableStreamNative::CreateReadResult(
+                        script_state, chunk, done, reader->for_author_code_));
+}
+
+int ReadableStreamNative::GetNumReadRequests(
+    const ReadableStreamNative* stream) {
+  // https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests
+  // 1. Return the number of elements in stream.[[reader]].[[readRequests]].
+  return stream->reader_->read_requests_.size();
+}
+
+//
+//  Readable Stream Reader Generic Abstract Operations
+//
+
+v8::Local<v8::Promise> ReadableStreamNative::ReaderGenericCancel(
+    ScriptState* script_state,
+    ReadableStreamDefaultReader* reader,
+    v8::Local<v8::Value> reason) {
+  // https://streams.spec.whatwg.org/#readable-stream-reader-generic-cancel
+  // 1. Let stream be reader.[[ownerReadableStream]].
+  ReadableStreamNative* stream = reader->owner_readable_stream_;
+
+  // 2. Assert: stream is not undefined.
+  DCHECK(stream);
+
+  // 3. Return ! ReadableStreamCancel(stream, reason).
+  return ReadableStreamNative::Cancel(script_state, stream, reason);
+}
+
+void ReadableStreamNative::ReaderGenericInitialize(
+    ScriptState* script_state,
+    ReadableStreamDefaultReader* reader,
+    ReadableStreamNative* stream) {
+  auto* isolate = script_state->GetIsolate();
+  // TODO(yhirano): Remove this when we don't need hasPendingActivity in
+  // blink::UnderlyingSourceBase.
+  ReadableStreamDefaultController* controller =
+      stream->readable_stream_controller_;
+  if (controller->enable_blink_lock_notifications_) {
+    // The stream is created with an external controller (i.e. made in
+    // Blink).
+    v8::Local<v8::Object> lock_notify_target =
+        controller->lock_notify_target_.NewLocal(isolate);
+    CallNullaryMethod(script_state, lock_notify_target, "notifyLockAcquired");
+  }
+
+  // https://streams.spec.whatwg.org/#readable-stream-reader-generic-initialize
+  // 1. Set reader.[[forAuthorCode]] to true.
+  DCHECK(reader->for_author_code_);
+
+  // 2. Set reader.[[ownerReadableStream]] to stream.
+  reader->owner_readable_stream_ = stream;
+
+  // 3. Set stream.[[reader]] to reader.
+  stream->reader_ = reader;
+
+  switch (stream->state_) {
+    // 4. If stream.[[state]] is "readable",
+    case kReadable:
+      // a. Set reader.[[closedPromise]] to a new promise.
+      reader->closed_promise_ =
+          MakeGarbageCollected<StreamPromiseResolver>(script_state);
+      break;
+
+    // 5. Otherwise, if stream.[[state]] is "closed",
+    case kClosed:
+      // a. Set reader.[[closedPromise]] to a promise resolved with undefined.
+      reader->closed_promise_ =
+          StreamPromiseResolver::CreateResolvedWithUndefined(script_state);
+      break;
+
+    // 6. Otherwise,
+    case kErrored:
+      // a. Assert: stream.[[state]] is "errored".
+      DCHECK_EQ(stream->state_, kErrored);
+
+      // b. Set reader.[[closedPromise]] to a promise rejected with stream.
+      //    [[storedError]].
+      reader->closed_promise_ = StreamPromiseResolver::CreateRejected(
+          script_state, stream->GetStoredError(isolate));
+
+      // c. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
+      reader->closed_promise_->MarkAsHandled(isolate);
+      break;
+  }
+}
+
+void ReadableStreamNative::ReaderGenericRelease(
+    ScriptState* script_state,
+    ReadableStreamDefaultReader* reader) {
+  // https://streams.spec.whatwg.org/#readable-stream-reader-generic-release
+  // 1. Assert: reader.[[ownerReadableStream]] is not undefined.
+  DCHECK(reader->owner_readable_stream_);
+
+  // 2. Assert: reader.[[ownerReadableStream]].[[reader]] is reader.
+  DCHECK_EQ(reader->owner_readable_stream_->reader_, reader);
+
+  auto* isolate = script_state->GetIsolate();
+  // TODO(yhirano): Remove this when we don"t need hasPendingActivity in
+  // blink::UnderlyingSourceBase.
+  ReadableStreamDefaultController* controller =
+      reader->owner_readable_stream_->readable_stream_controller_;
+  if (controller->enable_blink_lock_notifications_) {
+    // The stream is created with an external controller (i.e. made in
+    // Blink).
+    auto lock_notify_target = controller->lock_notify_target_.NewLocal(isolate);
+    CallNullaryMethod(script_state, lock_notify_target, "notifyLockReleased");
+  }
+
+  // 3. If reader.[[ownerReadableStream]].[[state]] is "readable", reject
+  //    reader.[[closedPromise]] with a TypeError exception.
+  if (reader->owner_readable_stream_->state_ == kReadable) {
+    reader->closed_promise_->Reject(
+        script_state,
+        v8::Exception::TypeError(V8String(
+            isolate,
+            "This readable stream reader has been released and cannot be used "
+            "to monitor the stream's state")));
+  } else {
+    // 4. Otherwise, set reader.[[closedPromise]] to a promise rejected with a
+    //    TypeError exception.
+    reader->closed_promise_ = StreamPromiseResolver::CreateRejected(
+        script_state, v8::Exception::TypeError(V8String(
+                          isolate,
+                          "This readable stream reader has been released and "
+                          "cannot be used to monitor the stream's state")));
+  }
+
+  // 5. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
+  reader->closed_promise_->MarkAsHandled(isolate);
+
+  // 6. Set reader.[[ownerReadableStream]].[[reader]] to undefined.
+  reader->owner_readable_stream_->reader_ = nullptr;
+
+  // 7. Set reader.[[ownerReadableStream]] to undefined.
+  reader->owner_readable_stream_ = nullptr;
+}
+
+//
+// TODO(ricea): Functions for transferable streams.
+//
+
+void ReadableStreamNative::CallNullaryMethod(ScriptState* script_state,
+                                             v8::Local<v8::Object> object,
+                                             const char* method_name) {
+  auto* isolate = script_state->GetIsolate();
+  auto context = script_state->GetContext();
+  v8::TryCatch try_catch(isolate);
+  v8::Local<v8::Value> method;
+  if (!object->Get(context, V8AtomicString(isolate, method_name))
+           .ToLocal(&method)) {
+    DLOG(WARNING) << "Ignored failed lookup of '" << method_name
+                  << "' in CallNullaryMethod";
+    return;
+  }
+
+  if (!method->IsFunction()) {
+    DLOG(WARNING) << "Didn't call '" << method_name
+                  << "' in CallNullaryMethod because it was the wrong type";
+    return;
+  }
+
+  v8::MaybeLocal<v8::Value> result =
+      method.As<v8::Function>()->Call(context, object, 0, nullptr);
+  if (result.IsEmpty()) {
+    DLOG(WARNING) << "Ignored failure of '" << method_name
+                  << "' in CallNullaryMethod";
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_native.h b/third_party/blink/renderer/core/streams/readable_stream_native.h
new file mode 100644
index 0000000..0ef478ff
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/readable_stream_native.h
@@ -0,0 +1,272 @@
+// 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_STREAMS_READABLE_STREAM_NATIVE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_NATIVE_H_
+
+#include <stdint.h>
+
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class ExceptionState;
+class ReadableStreamDefaultController;
+class ReadableStreamDefaultReader;
+class ScriptState;
+class StrategySizeAlgorithm;
+class StreamAlgorithm;
+class StreamPromiseResolver;
+class StreamStartAlgorithm;
+class UnderlyingSourceBase;
+class Visitor;
+
+// C++ implementation of ReadableStream.
+// See https://streams.spec.whatwg.org/#rs-model for background.
+class ReadableStreamNative : public ReadableStream {
+ public:
+  enum State : uint8_t { kReadable, kClosed, kErrored };
+
+  // Implements ReadableStream::Create() when this implementation is enabled.
+  static ReadableStreamNative* Create(ScriptState* script_state,
+                                      ScriptValue underlying_source,
+                                      ScriptValue strategy,
+                                      ExceptionState& exception_state);
+
+  // Implements ReadableStream::CreateWithCountQueueingStrategy() when this
+  // implementation is enabled.
+  //
+  // TODO(ricea): Replace this API with something more efficient when the old
+  // implementation is gone.
+  static ReadableStreamNative* CreateWithCountQueueingStrategy(
+      ScriptState* script_state,
+      UnderlyingSourceBase* underlying_source,
+      size_t high_water_mark);
+
+  // CreateReadableStream():
+  // https://streams.spec.whatwg.org/#create-readable-stream
+  static ReadableStreamNative* Create(ScriptState*,
+                                      StreamStartAlgorithm* start_algorithm,
+                                      StreamAlgorithm* pull_algorithm,
+                                      StreamAlgorithm* cancel_algorithm,
+                                      double high_water_mark,
+                                      StrategySizeAlgorithm* size_algorithm,
+                                      ExceptionState&);
+
+  ReadableStreamNative();
+
+  // TODO(ricea): Remove |enable_blink_lock_notifications| once
+  // blink::ReadableStreamOperations has been updated to use
+  // CreateReadableStream.
+  // https://streams.spec.whatwg.org/#rs-constructor
+  ReadableStreamNative(ScriptState*,
+                       ScriptValue raw_underlying_source,
+                       ScriptValue raw_strategy,
+                       bool enable_blink_lock_notifications,
+                       ExceptionState&);
+
+  ~ReadableStreamNative() override;
+
+  // https://streams.spec.whatwg.org/#rs-constructor
+  bool locked(ScriptState*, ExceptionState&) const override;
+
+  ScriptPromise cancel(ScriptState*, ExceptionState&) override;
+
+  // https://streams.spec.whatwg.org/#rs-cancel
+  ScriptPromise cancel(ScriptState*,
+                       ScriptValue reason,
+                       ExceptionState&) override;
+
+  ScriptValue getReader(ScriptState*, ExceptionState&) override;
+
+  // https://streams.spec.whatwg.org/#rs-get-reader
+  ScriptValue getReader(ScriptState*,
+                        ScriptValue options,
+                        ExceptionState&) override;
+
+  ScriptValue pipeThrough(ScriptState*,
+                          ScriptValue transform_stream,
+                          ExceptionState&) override;
+
+  // https://streams.spec.whatwg.org/#rs-pipe-through
+  ScriptValue pipeThrough(ScriptState*,
+                          ScriptValue transform_stream,
+                          ScriptValue options,
+                          ExceptionState&) override;
+
+  ScriptPromise pipeTo(ScriptState*,
+                       ScriptValue destination,
+                       ExceptionState&) override;
+
+  // https://streams.spec.whatwg.org/#rs-pipe-to
+  ScriptPromise pipeTo(ScriptState*,
+                       ScriptValue destination_value,
+                       ScriptValue options,
+                       ExceptionState&) override;
+
+  // https://streams.spec.whatwg.org/#rs-tee
+  ScriptValue tee(ScriptState*, ExceptionState&) override;
+
+  // TODO(domenic): cloneForBranch2 argument from spec not supported yet
+  void Tee(ScriptState*,
+           ReadableStream** branch1,
+           ReadableStream** branch2,
+           ExceptionState&) override;
+
+  ReadHandle* GetReadHandle(ScriptState*, ExceptionState&) override;
+
+  base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const override {
+    return IsLocked(this);
+  }
+
+  base::Optional<bool> IsDisturbed(ScriptState*,
+                                   ExceptionState&) const override {
+    return IsDisturbed(this);
+  }
+
+  base::Optional<bool> IsReadable(ScriptState*,
+                                  ExceptionState&) const override {
+    return IsReadable(this);
+  }
+
+  base::Optional<bool> IsClosed(ScriptState*, ExceptionState&) const override {
+    return IsClosed(this);
+  }
+
+  base::Optional<bool> IsErrored(ScriptState*, ExceptionState&) const override {
+    return IsErrored(this);
+  }
+
+  void LockAndDisturb(ScriptState*, ExceptionState&) override;
+
+  void Serialize(ScriptState*, MessagePort* port, ExceptionState&) override;
+
+  bool IsBroken() const override { return false; }
+
+  //
+  // Readable stream abstract operations
+  //
+
+  // https://streams.spec.whatwg.org/#is-readable-stream-disturbed
+  static bool IsDisturbed(const ReadableStreamNative* stream) {
+    return stream->is_disturbed_;
+  }
+
+  // https://streams.spec.whatwg.org/#is-readable-stream-locked
+  static bool IsLocked(const ReadableStreamNative* stream) {
+    return stream->reader_;
+  }
+
+  //
+  // Functions exported for use by TransformStream. Not part of the standard.
+  //
+
+  static bool IsReadable(const ReadableStreamNative* stream) {
+    return stream->state_ == kReadable;
+  }
+
+  static bool IsClosed(const ReadableStreamNative* stream) {
+    return stream->state_ == kClosed;
+  }
+
+  static bool IsErrored(const ReadableStreamNative* stream) {
+    return stream->state_ == kErrored;
+  }
+
+  ReadableStreamDefaultController* GetController() {
+    return readable_stream_controller_;
+  }
+
+  v8::Local<v8::Value> GetStoredError(v8::Isolate*) const;
+
+  void Trace(Visitor*) override;
+
+ private:
+  friend class ReadableStreamDefaultController;
+  friend class ReadableStreamDefaultReader;
+
+  class ReadHandleImpl;
+  class TeeEngine;
+
+  // https://streams.spec.whatwg.org/#initialize-readable-stream
+  static void Initialize(ReadableStreamNative*);
+
+  // https://streams.spec.whatwg.org/#acquire-readable-stream-reader
+  static ReadableStreamDefaultReader* AcquireDefaultReader(
+      ScriptState*,
+      ReadableStreamNative*,
+      bool for_author_code,
+      ExceptionState&);
+
+  // https://streams.spec.whatwg.org/#readable-stream-add-read-request
+  static StreamPromiseResolver* AddReadRequest(ScriptState*,
+                                               ReadableStreamNative*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-cancel
+  static v8::Local<v8::Promise> Cancel(ScriptState*,
+                                       ReadableStreamNative*,
+                                       v8::Local<v8::Value> reason);
+
+  // https://streams.spec.whatwg.org/#readable-stream-close
+  static void Close(ScriptState*, ReadableStreamNative*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-create-read-result
+  static v8::Local<v8::Value> CreateReadResult(ScriptState*,
+                                               v8::Local<v8::Value> value,
+                                               bool done,
+                                               bool for_author_code);
+
+  // https://streams.spec.whatwg.org/#readable-stream-error
+  static void Error(ScriptState*,
+                    ReadableStreamNative*,
+                    v8::Local<v8::Value> e);
+
+  // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-request
+  static void FulfillReadRequest(ScriptState*,
+                                 ReadableStreamNative*,
+                                 v8::Local<v8::Value> chunk,
+                                 bool done);
+
+  // https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests
+  static int GetNumReadRequests(const ReadableStreamNative*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-reader-generic-cancel
+  static v8::Local<v8::Promise> ReaderGenericCancel(
+      ScriptState*,
+      ReadableStreamDefaultReader*,
+      v8::Local<v8::Value> reason);
+
+  // https://streams.spec.whatwg.org/#readable-stream-reader-generic-initialize
+  static void ReaderGenericInitialize(ScriptState*,
+                                      ReadableStreamDefaultReader*,
+                                      ReadableStreamNative*);
+
+  // https://streams.spec.whatwg.org/#readable-stream-reader-generic-release
+  static void ReaderGenericRelease(ScriptState*, ReadableStreamDefaultReader*);
+
+  //
+  // TODO(ricea): Functions for transferable streams.
+  //
+
+  // Calls method |method_name| on |object|, passing no arguments, and ignoring
+  // errors. Used for Blink lock notifications.
+  static void CallNullaryMethod(ScriptState*,
+                                v8::Local<v8::Object> object,
+                                const char* method_name);
+
+  bool is_disturbed_ = false;
+  State state_ = kReadable;
+  TraceWrapperMember<ReadableStreamDefaultController>
+      readable_stream_controller_;
+  TraceWrapperMember<ReadableStreamDefaultReader> reader_;
+  TraceWrapperV8Reference<v8::Value> stored_error_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_NATIVE_H_
diff --git a/third_party/blink/renderer/core/streams/readable_stream_test.cc b/third_party/blink/renderer/core/streams/readable_stream_test.cc
index 16edeff..d94f0750 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_test.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_test.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/string_resource.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "v8/include/v8.h"
 
@@ -28,8 +29,10 @@
 namespace {
 
 // Web platform tests test ReadableStream more thoroughly from scripts.
-class ReadableStreamTest : public testing::Test {
+class ReadableStreamTest : public testing::TestWithParam<bool> {
  public:
+  ReadableStreamTest() : feature_(GetParam()) {}
+
   base::Optional<String> ReadAll(V8TestingScope& scope,
                                  ReadableStream* stream) {
     ScriptState* script_state = scope.GetScriptState();
@@ -89,9 +92,12 @@
     NOTREACHED();
     return base::nullopt;
   }
+
+ private:
+  ScopedStreamsNativeForTest feature_;
 };
 
-TEST_F(ReadableStreamTest, CreateWithoutArguments) {
+TEST_P(ReadableStreamTest, CreateWithoutArguments) {
   V8TestingScope scope;
 
   ReadableStream* stream =
@@ -100,7 +106,7 @@
   ASSERT_FALSE(scope.GetExceptionState().HadException());
 }
 
-TEST_F(ReadableStreamTest, CreateWithUnderlyingSourceOnly) {
+TEST_P(ReadableStreamTest, CreateWithUnderlyingSourceOnly) {
   V8TestingScope scope;
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
@@ -119,7 +125,7 @@
   EXPECT_TRUE(underlying_source->IsStartCalled());
 }
 
-TEST_F(ReadableStreamTest, CreateWithFullArguments) {
+TEST_P(ReadableStreamTest, CreateWithFullArguments) {
   V8TestingScope scope;
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
@@ -137,7 +143,7 @@
   EXPECT_TRUE(underlying_source->IsStartCalled());
 }
 
-TEST_F(ReadableStreamTest, CreateWithPathologicalStrategy) {
+TEST_P(ReadableStreamTest, CreateWithPathologicalStrategy) {
   V8TestingScope scope;
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
@@ -158,7 +164,7 @@
 }
 
 // Testing getReader, locked, IsLocked and IsDisturbed.
-TEST_F(ReadableStreamTest, GetReader) {
+TEST_P(ReadableStreamTest, GetReader) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
 
@@ -210,7 +216,7 @@
             base::make_optional(true));
 }
 
-TEST_F(ReadableStreamTest, Cancel) {
+TEST_P(ReadableStreamTest, Cancel) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
 
@@ -235,7 +241,7 @@
   EXPECT_FALSE(underlying_source->IsCancelledWithNull());
 }
 
-TEST_F(ReadableStreamTest, CancelWithNull) {
+TEST_P(ReadableStreamTest, CancelWithNull) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
 
@@ -265,7 +271,7 @@
 
 // TODO(yhirano): Write tests for pipeThrough and pipeTo.
 
-TEST_F(ReadableStreamTest, Tee) {
+TEST_P(ReadableStreamTest, Tee) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
 
@@ -318,7 +324,7 @@
   EXPECT_EQ(*result2, "hello, bye");
 }
 
-TEST_F(ReadableStreamTest, Close) {
+TEST_P(ReadableStreamTest, Close) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   ExceptionState& exception_state = scope.GetExceptionState();
@@ -347,7 +353,7 @@
             base::make_optional(false));
 }
 
-TEST_F(ReadableStreamTest, Error) {
+TEST_P(ReadableStreamTest, Error) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   ExceptionState& exception_state = scope.GetExceptionState();
@@ -377,7 +383,7 @@
             base::make_optional(true));
 }
 
-TEST_F(ReadableStreamTest, LockAndDisturb) {
+TEST_P(ReadableStreamTest, LockAndDisturb) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   ExceptionState& exception_state = scope.GetExceptionState();
@@ -403,7 +409,13 @@
             base::make_optional(true));
 }
 
-TEST_F(ReadableStreamTest, Serialize) {
+TEST_P(ReadableStreamTest, Serialize) {
+  if (GetParam()) {
+    // Serialize() is not yet supported in the C++ implementation.
+    return;
+  }
+
+  ScopedTransferableStreamsForTest enabled(true);
   RuntimeEnabledFeatures::SetTransferableStreamsEnabled(true);
 
   V8TestingScope scope;
@@ -434,7 +446,7 @@
             base::make_optional<String>("hello, bye"));
 }
 
-TEST_F(ReadableStreamTest, GetReadHandle) {
+TEST_P(ReadableStreamTest, GetReadHandle) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   auto* isolate = scope.GetIsolate();
@@ -514,6 +526,8 @@
   EXPECT_TRUE(done);
 }
 
+INSTANTIATE_TEST_SUITE_P(, ReadableStreamTest, ::testing::Values(false, true));
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_wrapper.cc b/third_party/blink/renderer/core/streams/readable_stream_wrapper.cc
index da9ca1d..ee6f205 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_wrapper.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_wrapper.cc
@@ -228,13 +228,7 @@
     return ScriptValue();
   }
 
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    // TODO(ricea): Replace this with a DCHECK once ReadableStreamNative is
-    // implemented.
-    exception_state.ThrowTypeError(
-        "pipeThrough disabled because StreamsNative feature is enabled");
-    return ScriptValue();
-  }
+  DCHECK(!RuntimeEnabledFeatures::StreamsNativeEnabled());
 
   // This cast is safe because the following code will only be run when the
   // native version of WritableStream is not in use.
@@ -280,13 +274,7 @@
   }
   DCHECK(destination);
 
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    // TODO(ricea): Replace this with a DCHECK once ReadableStreamNative is
-    // implemented.
-    exception_state.ThrowTypeError(
-        "pipeTo disabled because StreamsNative feature is enabled");
-    return ScriptPromise();
-  }
+  DCHECK(!RuntimeEnabledFeatures::StreamsNativeEnabled());
 
   // This cast is safe because the following code will only be run when the
   // native version of WritableStream is not in use.
diff --git a/third_party/blink/renderer/core/streams/underlying_source_base.h b/third_party/blink/renderer/core/streams/underlying_source_base.h
index 55abd8e..ef10266 100644
--- a/third_party/blink/renderer/core/streams/underlying_source_base.h
+++ b/third_party/blink/renderer/core/streams/underlying_source_base.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
@@ -59,7 +60,7 @@
   }
 
  private:
-  Member<ReadableStreamDefaultControllerInterface> controller_;
+  TraceWrapperMember<ReadableStreamDefaultControllerInterface> controller_;
   bool is_stream_locked_ = false;
 };
 
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.h b/third_party/blink/renderer/core/svg/graphics/svg_image.h
index 67bf415..e2391c5 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image.h
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image.h
@@ -236,6 +236,8 @@
   LoadState load_state_ = kDataChangedNotStarted;
 
   Persistent<SVGImageLocalFrameClient> frame_client_;
+  FRIEND_TEST_ALL_PREFIXES(ElementFragmentAnchorTest,
+                           SVGDocumentDoesntCreateFragment);
   FRIEND_TEST_ALL_PREFIXES(SVGImageTest, SupportsSubsequenceCaching);
   FRIEND_TEST_ALL_PREFIXES(SVGImageTest, JankTrackerDisabled);
   FRIEND_TEST_ALL_PREFIXES(SVGImageTest, SetSizeOnVisualViewport);
diff --git a/third_party/blink/renderer/core/testing/null_execution_context.cc b/third_party/blink/renderer/core/testing/null_execution_context.cc
index 6bcc92f..90e2f413 100644
--- a/third_party/blink/renderer/core/testing/null_execution_context.cc
+++ b/third_party/blink/renderer/core/testing/null_execution_context.cc
@@ -28,7 +28,7 @@
 }
 
 void NullExecutionContext::SetUpSecurityContext() {
-  ContentSecurityPolicy* policy = ContentSecurityPolicy::Create();
+  auto* policy = MakeGarbageCollected<ContentSecurityPolicy>();
   SecurityContext::SetSecurityOrigin(SecurityOrigin::Create(url_));
   policy->BindToDelegate(GetContentSecurityPolicyDelegate());
   SecurityContext::SetContentSecurityPolicy(policy);
diff --git a/third_party/blink/renderer/core/timing/window_performance_test.cc b/third_party/blink/renderer/core/timing/window_performance_test.cc
index d065896..dfcbc403 100644
--- a/third_party/blink/renderer/core/timing/window_performance_test.cc
+++ b/third_party/blink/renderer/core/timing/window_performance_test.cc
@@ -146,7 +146,7 @@
   DocumentInit init = DocumentInit::Create().WithDocumentLoader(
       GetFrame()->Loader().GetDocumentLoader());
   GetDocument()->Shutdown();
-  GetFrame()->SetDOMWindow(LocalDOMWindow::Create(*GetFrame()));
+  GetFrame()->SetDOMWindow(MakeGarbageCollected<LocalDOMWindow>(*GetFrame()));
   GetFrame()->DomWindow()->InstallNewDocument(AtomicString(), init, false);
 
   // m_performance is still alive, and should not crash when notified.
diff --git a/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc b/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
index 57f9dfc8..84faa8a 100644
--- a/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
+++ b/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
@@ -56,7 +56,7 @@
 
     // Set up the CSP for Document before starting MainThreadWorklet because
     // MainThreadWorklet inherits the owner Document's CSP.
-    ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+    auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
     csp->DidReceiveHeader(csp_header, kContentSecurityPolicyHeaderTypeEnforce,
                           kContentSecurityPolicyHeaderSourceHTTP);
     document->InitContentSecurityPolicy(csp);
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
index c53688a..3c72ec0 100644
--- a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
+++ b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
@@ -275,7 +275,7 @@
 TEST_F(ThreadedWorkletTest, ContentSecurityPolicy) {
   // Set up the CSP for Document before starting ThreadedWorklet because
   // ThreadedWorklet inherits the owner Document's CSP.
-  ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+  auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
   csp->DidReceiveHeader("script-src 'self' https://allowed.example.com",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -291,7 +291,7 @@
 }
 
 TEST_F(ThreadedWorkletTest, InvalidContentSecurityPolicy) {
-  ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+  auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
   csp->DidReceiveHeader("invalid-csp", kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
   GetDocument().InitContentSecurityPolicy(csp);
diff --git a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
index a766654..5e3c70c 100644
--- a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
+++ b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
@@ -310,7 +310,7 @@
   if (!response.CurrentRequestUrl().ProtocolIs("blob") &&
       !response.CurrentRequestUrl().ProtocolIs("file") &&
       !response.CurrentRequestUrl().ProtocolIs("filesystem")) {
-    content_security_policy_ = ContentSecurityPolicy::Create();
+    content_security_policy_ = MakeGarbageCollected<ContentSecurityPolicy>();
     content_security_policy_->SetOverrideURLForSelf(
         response.CurrentRequestUrl());
     content_security_policy_->DidReceiveHeaders(
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
index 7c6bdde7..0e9290ae9 100644
--- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -316,8 +316,7 @@
     const FetchClientSettingsObject& outside_settings_object) {
   DCHECK(IsContextThread());
 
-  ContentSecurityPolicy* content_security_policy =
-      ContentSecurityPolicy::Create();
+  auto* content_security_policy = MakeGarbageCollected<ContentSecurityPolicy>();
   for (const auto& policy_and_type : outside_content_security_policy_headers_) {
     content_security_policy->DidReceiveHeader(
         policy_and_type.first, policy_and_type.second,
@@ -383,7 +382,7 @@
 void WorkerOrWorkletGlobalScope::InitContentSecurityPolicyFromVector(
     const Vector<CSPHeaderAndType>& headers) {
   if (!GetContentSecurityPolicy()) {
-    ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+    auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
     SetContentSecurityPolicy(csp);
   }
   for (const auto& policy_and_type : headers) {
diff --git a/third_party/blink/renderer/core/xml/xslt_processor.cc b/third_party/blink/renderer/core/xml/xslt_processor.cc
index c421ca11..dd4d252 100644
--- a/third_party/blink/renderer/core/xml/xslt_processor.cc
+++ b/third_party/blink/renderer/core/xml/xslt_processor.cc
@@ -102,7 +102,7 @@
       result->SetCookieURL(old_document->CookieURL());
       result->EnforceSandboxFlags(old_document->GetSandboxFlags());
 
-      ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
+      auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
       csp->CopyStateFrom(old_document->GetContentSecurityPolicy());
       result->InitContentSecurityPolicy(csp);
     }
diff --git a/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js b/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
index 5ac6b17..4f69cc5c 100644
--- a/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
+++ b/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
@@ -578,6 +578,7 @@
   }
 
   /**
+   * The range of |minPercent| and |maxPercent| is [0, 100].
    * @param {number} minPercent
    * @param {number=} maxPercent
    * @param {number=} maxDescentLevel
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 3de42fab..24999f7 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -299,6 +299,7 @@
     "indexeddb/web_idb_cursor_impl_unittest.cc",
     "indexeddb/web_idb_transaction_impl_unittest.cc",
     "manifest/image_resource_type_converters_test.cc",
+    "manifest/manifest_parser_unittest.cc",
     "media_controls/elements/media_control_animated_arrow_container_element_test.cc",
     "media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc",
     "media_controls/elements/media_control_input_element_test.cc",
diff --git a/third_party/blink/renderer/modules/exported/BUILD.gn b/third_party/blink/renderer/modules/exported/BUILD.gn
index c034cde..74f7348 100644
--- a/third_party/blink/renderer/modules/exported/BUILD.gn
+++ b/third_party/blink/renderer/modules/exported/BUILD.gn
@@ -13,6 +13,7 @@
     "web_dom_media_stream_track.cc",
     "web_embedded_worker_impl.cc",
     "web_embedded_worker_impl.h",
+    "web_manifest_parser.cc",
     "web_storage_event_dispatcher_impl.cc",
     "web_user_media_request.cc",
   ]
diff --git a/third_party/blink/renderer/modules/exported/web_manifest_parser.cc b/third_party/blink/renderer/modules/exported/web_manifest_parser.cc
new file mode 100644
index 0000000..281fc55
--- /dev/null
+++ b/third_party/blink/renderer/modules/exported/web_manifest_parser.cc
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/web/web_manifest_parser.h"
+
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/renderer/modules/manifest/manifest_parser.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+namespace blink {
+
+bool WebManifestParser::ParseManifest(const base::StringPiece& data,
+                                      const WebURL& manifest_url,
+                                      const WebURL& document_url,
+                                      Manifest* manifest,
+                                      WebVector<ManifestError>* errors) {
+  ManifestParser parser(data, KURL(manifest_url), KURL(document_url));
+
+  parser.Parse();
+  parser.TakeErrors(errors);
+
+  if (parser.failed())
+    return false;
+
+  *manifest = parser.manifest();
+  return true;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/manifest/BUILD.gn b/third_party/blink/renderer/modules/manifest/BUILD.gn
index 383bf5b..31862cc 100644
--- a/third_party/blink/renderer/modules/manifest/BUILD.gn
+++ b/third_party/blink/renderer/modules/manifest/BUILD.gn
@@ -8,6 +8,8 @@
   sources = [
     "image_resource_type_converters.cc",
     "image_resource_type_converters.h",
+    "manifest_parser.cc",
+    "manifest_parser.h",
     "manifest_uma_util.cc",
     "manifest_uma_util.h",
   ]
diff --git a/third_party/blink/renderer/modules/manifest/DEPS b/third_party/blink/renderer/modules/manifest/DEPS
new file mode 100644
index 0000000..8aee5cb
--- /dev/null
+++ b/third_party/blink/renderer/modules/manifest/DEPS
@@ -0,0 +1,10 @@
+# TODO(https://crbug.com/704441) : Added temporarily.
+include_rules = [
+    "+base/json/json_reader.h",
+    "+base/memory/scoped_refptr.h",
+    "+base/strings",
+    "+base/values.h",
+    "+net/base/mime_util.h",
+    "+ui/gfx/geometry/size.h",
+    "+url",
+]
diff --git a/content/renderer/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
similarity index 76%
rename from content/renderer/manifest/manifest_parser.cc
rename to third_party/blink/renderer/modules/manifest/manifest_parser.cc
index 0b93647..201a4b8 100644
--- a/content/renderer/manifest/manifest_parser.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/manifest/manifest_parser.h"
+#include "third_party/blink/renderer/modules/manifest/manifest_parser.h"
 
 #include <stddef.h>
 #include <utility>
@@ -14,15 +14,22 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "content/renderer/manifest/manifest_uma_util.h"
 #include "net/base/mime_util.h"
 #include "third_party/blink/public/common/manifest/manifest_util.h"
+#include "third_party/blink/public/common/mime_util/mime_util.h"
 #include "third_party/blink/public/platform/web_icon_sizes_parser.h"
 #include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/web/web_css_parser.h"
+#include "third_party/blink/renderer/core/css/parser/css_parser.h"
+#include "third_party/blink/renderer/modules/manifest/manifest_uma_util.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
+
+namespace blink {
 
 namespace {
 
@@ -32,8 +39,8 @@
   return net::ParseMimeTypeWithoutParameter(mime_type, nullptr, nullptr);
 }
 
-bool VerifyFiles(const std::vector<blink::Manifest::FileFilter>& files) {
-  for (const blink::Manifest::FileFilter& file : files) {
+bool VerifyFiles(const std::vector<Manifest::FileFilter>& files) {
+  for (const Manifest::FileFilter& file : files) {
     for (const base::string16& utf_accept : file.accept) {
       std::string accept_type =
           base::ToLowerASCII(base::UTF16ToASCII(utf_accept));
@@ -46,19 +53,15 @@
 
 }  // anonymous namespace
 
-namespace content {
-
 ManifestParser::ManifestParser(const base::StringPiece& data,
-                               const GURL& manifest_url,
-                               const GURL& document_url)
+                               const KURL& manifest_url,
+                               const KURL& document_url)
     : data_(data),
       manifest_url_(manifest_url),
       document_url_(document_url),
-      failed_(false) {
-}
+      failed_(false) {}
 
-ManifestParser::~ManifestParser() {
-}
+ManifestParser::~ManifestParser() {}
 
 void ManifestParser::Parse() {
   std::string error_msg;
@@ -105,14 +108,13 @@
   ManifestUmaUtil::ParseSucceeded(manifest_);
 }
 
-const blink::Manifest& ManifestParser::manifest() const {
+const Manifest& ManifestParser::manifest() const {
   return manifest_;
 }
 
-void ManifestParser::TakeErrors(
-    std::vector<blink::mojom::ManifestErrorPtr>* errors) {
-  errors->clear();
-  errors->swap(errors_);
+void ManifestParser::TakeErrors(WebVector<ManifestError>* errors) {
+  errors->Clear();
+  errors->Assign(errors_);
 }
 
 bool ManifestParser::failed() const {
@@ -127,8 +129,7 @@
 
   bool value;
   if (!dictionary.GetBoolean(key, &value)) {
-    AddErrorInfo("property '" + key + "' ignored, type " +
-                 "boolean expected.");
+    AddErrorInfo("property '" + key + "' ignored, type " + "boolean expected.");
     return default_value;
   }
 
@@ -144,8 +145,7 @@
 
   base::string16 value;
   if (!dictionary.GetString(key, &value)) {
-    AddErrorInfo("property '" + key + "' ignored, type " +
-                 "string expected.");
+    AddErrorInfo("property '" + key + "' ignored, type " + "string expected.");
     return base::NullableString16();
   }
 
@@ -161,16 +161,17 @@
   if (parsed_color.is_null())
     return base::nullopt;
 
-  SkColor color;
-  if (!blink::WebCSSParser::ParseColor(
-          &color, blink::WebString::FromUTF16(parsed_color.string()))) {
+  Color color;
+  WebString color_string = WebString::FromUTF16(parsed_color);
+
+  if (!CSSParser::ParseColor(color, WTF::String(color_string), true)) {
     AddErrorInfo("property '" + key + "' ignored, '" +
                  base::UTF16ToUTF8(parsed_color.string()) + "' is not a " +
                  "valid color.");
     return base::nullopt;
   }
 
-  return color;
+  return color.Rgb();
 }
 
 GURL ManifestParser::ParseURL(const base::DictionaryValue& dictionary,
@@ -204,12 +205,12 @@
 }
 
 base::NullableString16 ManifestParser::ParseName(
-    const base::DictionaryValue& dictionary)  {
+    const base::DictionaryValue& dictionary) {
   return ParseString(dictionary, "name", Trim);
 }
 
 base::NullableString16 ManifestParser::ParseShortName(
-    const base::DictionaryValue& dictionary)  {
+    const base::DictionaryValue& dictionary) {
   return ParseString(dictionary, "short_name", Trim);
 }
 
@@ -240,31 +241,31 @@
   return scope;
 }
 
-blink::WebDisplayMode ManifestParser::ParseDisplay(
+WebDisplayMode ManifestParser::ParseDisplay(
     const base::DictionaryValue& dictionary) {
   base::NullableString16 display = ParseString(dictionary, "display", Trim);
   if (display.is_null())
-    return blink::kWebDisplayModeUndefined;
+    return kWebDisplayModeUndefined;
 
-  blink::WebDisplayMode display_enum =
-      blink::WebDisplayModeFromString(base::UTF16ToUTF8(display.string()));
-  if (display_enum == blink::kWebDisplayModeUndefined)
+  WebDisplayMode display_enum =
+      WebDisplayModeFromString(base::UTF16ToUTF8(display.string()));
+  if (display_enum == kWebDisplayModeUndefined)
     AddErrorInfo("unknown 'display' value ignored.");
   return display_enum;
 }
 
-blink::WebScreenOrientationLockType ManifestParser::ParseOrientation(
+WebScreenOrientationLockType ManifestParser::ParseOrientation(
     const base::DictionaryValue& dictionary) {
   base::NullableString16 orientation =
       ParseString(dictionary, "orientation", Trim);
 
   if (orientation.is_null())
-    return blink::kWebScreenOrientationLockDefault;
+    return kWebScreenOrientationLockDefault;
 
-  blink::WebScreenOrientationLockType orientation_enum =
-      blink::WebScreenOrientationLockTypeFromString(
+  WebScreenOrientationLockType orientation_enum =
+      WebScreenOrientationLockTypeFromString(
           base::UTF16ToUTF8(orientation.string()));
-  if (orientation_enum == blink::kWebScreenOrientationLockDefault)
+  if (orientation_enum == kWebScreenOrientationLockDefault)
     AddErrorInfo("unknown 'orientation' value ignored.");
   return orientation_enum;
 }
@@ -290,35 +291,34 @@
   if (sizes_str.is_null())
     return sizes;
 
-  blink::WebVector<blink::WebSize> web_sizes =
-      blink::WebIconSizesParser::ParseIconSizes(
-          blink::WebString::FromUTF16(sizes_str.string()));
+  WebVector<WebSize> web_sizes = WebIconSizesParser::ParseIconSizes(
+      WebString::FromUTF16(sizes_str.string()));
   sizes.resize(web_sizes.size());
   for (size_t i = 0; i < web_sizes.size(); ++i)
-    sizes[i] = web_sizes[i];
+    sizes[i] = gfx::Size(web_sizes[i]);
   if (sizes.empty()) {
     AddErrorInfo("found icon with no valid size.");
   }
   return sizes;
 }
 
-base::Optional<std::vector<blink::Manifest::ImageResource::Purpose>>
+base::Optional<std::vector<Manifest::ImageResource::Purpose>>
 ManifestParser::ParseIconPurpose(const base::DictionaryValue& icon) {
   base::NullableString16 purpose_str = ParseString(icon, "purpose", NoTrim);
-  std::vector<blink::Manifest::ImageResource::Purpose> purposes;
+  std::vector<Manifest::ImageResource::Purpose> purposes;
 
   if (purpose_str.is_null()) {
-    purposes.push_back(blink::Manifest::ImageResource::Purpose::ANY);
+    purposes.push_back(Manifest::ImageResource::Purpose::ANY);
     return purposes;
   }
 
-  std::vector<base::string16> keywords = base::SplitString(
-      purpose_str.string(), base::ASCIIToUTF16(" "),
-      base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  std::vector<base::string16> keywords =
+      base::SplitString(purpose_str.string(), base::ASCIIToUTF16(" "),
+                        base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
   // "any" is the default if there are no other keywords.
   if (keywords.empty()) {
-    purposes.push_back(blink::Manifest::ImageResource::Purpose::ANY);
+    purposes.push_back(Manifest::ImageResource::Purpose::ANY);
     return purposes;
   }
 
@@ -326,11 +326,11 @@
 
   for (const base::string16& keyword : keywords) {
     if (base::LowerCaseEqualsASCII(keyword, "any")) {
-      purposes.push_back(blink::Manifest::ImageResource::Purpose::ANY);
+      purposes.push_back(Manifest::ImageResource::Purpose::ANY);
     } else if (base::LowerCaseEqualsASCII(keyword, "badge")) {
-      purposes.push_back(blink::Manifest::ImageResource::Purpose::BADGE);
+      purposes.push_back(Manifest::ImageResource::Purpose::BADGE);
     } else if (base::LowerCaseEqualsASCII(keyword, "maskable")) {
-      purposes.push_back(blink::Manifest::ImageResource::Purpose::MASKABLE);
+      purposes.push_back(Manifest::ImageResource::Purpose::MASKABLE);
     } else {
       unrecognised_purpose = true;
     }
@@ -342,7 +342,9 @@
   if (purposes.empty()) {
     AddErrorInfo("found icon with no valid purpose; ignoring it.");
     return base::nullopt;
-  } else if (unrecognised_purpose) {
+  }
+
+  if (unrecognised_purpose) {
     AddErrorInfo(
         "found icon with one or more invalid purposes; those purposes are "
         "ignored.");
@@ -351,9 +353,9 @@
   return purposes;
 }
 
-std::vector<blink::Manifest::ImageResource> ManifestParser::ParseIcons(
+std::vector<Manifest::ImageResource> ManifestParser::ParseIcons(
     const base::DictionaryValue& dictionary) {
-  std::vector<blink::Manifest::ImageResource> icons;
+  std::vector<Manifest::ImageResource> icons;
   if (!dictionary.HasKey("icons"))
     return icons;
 
@@ -368,7 +370,7 @@
     if (!icons_list->GetDictionary(i, &icon_dictionary))
       continue;
 
-    blink::Manifest::ImageResource icon;
+    Manifest::ImageResource icon;
     icon.src = ParseIconSrc(*icon_dictionary);
     // An icon MUST have a valid src. If it does not, it MUST be ignored.
     if (!icon.src.is_valid())
@@ -436,10 +438,10 @@
   return accept_types;
 }
 
-std::vector<blink::Manifest::FileFilter> ManifestParser::ParseTargetFiles(
+std::vector<Manifest::FileFilter> ManifestParser::ParseTargetFiles(
     const base::StringPiece& key,
     const base::DictionaryValue& from) {
-  std::vector<blink::Manifest::FileFilter> files;
+  std::vector<Manifest::FileFilter> files;
   if (!from.HasKey(key))
     return files;
 
@@ -475,8 +477,8 @@
 
 void ManifestParser::ParseFileFilter(
     const base::DictionaryValue& file_dictionary,
-    std::vector<blink::Manifest::FileFilter>* files) {
-  blink::Manifest::FileFilter file;
+    std::vector<Manifest::FileFilter>* files) {
+  Manifest::FileFilter file;
   file.name = ParseFileFilterName(file_dictionary);
   if (file.name.empty()) {
     // https://wicg.github.io/web-share-target/level-2/#share_target-member
@@ -493,15 +495,15 @@
   files->push_back(file);
 }
 
-base::Optional<blink::Manifest::ShareTarget::Method>
+base::Optional<Manifest::ShareTarget::Method>
 ManifestParser::ParseShareTargetMethod(
     const base::DictionaryValue& share_target_dict) {
   if (!share_target_dict.HasKey("method")) {
     AddErrorInfo(
         "Method should be set to either GET or POST. It currently defaults to "
         "GET.");
-    return base::Optional<blink::Manifest::ShareTarget::Method>(
-        blink::Manifest::ShareTarget::Method::kGet);
+    return base::Optional<Manifest::ShareTarget::Method>(
+        Manifest::ShareTarget::Method::kGet);
   }
 
   base::string16 value;
@@ -510,14 +512,14 @@
 
   std::string method = base::ToUpperASCII(base::UTF16ToASCII(value));
   if (method == "GET")
-    return blink::Manifest::ShareTarget::Method::kGet;
+    return Manifest::ShareTarget::Method::kGet;
   if (method == "POST")
-    return blink::Manifest::ShareTarget::Method::kPost;
+    return Manifest::ShareTarget::Method::kPost;
 
   return base::nullopt;
 }
 
-base::Optional<blink::Manifest::ShareTarget::Enctype>
+base::Optional<Manifest::ShareTarget::Enctype>
 ManifestParser::ParseShareTargetEnctype(
     const base::DictionaryValue& share_target_dict) {
   if (!share_target_dict.HasKey("enctype")) {
@@ -525,8 +527,8 @@
         "Enctype should be set to either application/x-www-form-urlencoded or "
         "multipart/form-data. It currently defaults to "
         "application/x-www-form-urlencoded");
-    return base::Optional<blink::Manifest::ShareTarget::Enctype>(
-        blink::Manifest::ShareTarget::Enctype::kApplication);
+    return base::Optional<Manifest::ShareTarget::Enctype>(
+        Manifest::ShareTarget::Enctype::kApplication);
   }
 
   base::string16 value;
@@ -535,19 +537,22 @@
   }
 
   std::string enctype = base::ToLowerASCII(base::UTF16ToASCII(value));
-  if (enctype == "application/x-www-form-urlencoded")
-    return base::Optional<blink::Manifest::ShareTarget::Enctype>(
-        blink::Manifest::ShareTarget::Enctype::kApplication);
-  if (enctype == "multipart/form-data")
-    return base::Optional<blink::Manifest::ShareTarget::Enctype>(
-        blink::Manifest::ShareTarget::Enctype::kMultipart);
+  if (enctype == "application/x-www-form-urlencoded") {
+    return base::Optional<Manifest::ShareTarget::Enctype>(
+        Manifest::ShareTarget::Enctype::kApplication);
+  }
+
+  if (enctype == "multipart/form-data") {
+    return base::Optional<Manifest::ShareTarget::Enctype>(
+        Manifest::ShareTarget::Enctype::kMultipart);
+  }
 
   return base::nullopt;
 }
 
-blink::Manifest::ShareTargetParams ManifestParser::ParseShareTargetParams(
+Manifest::ShareTargetParams ManifestParser::ParseShareTargetParams(
     const base::DictionaryValue& share_target_params) {
-  blink::Manifest::ShareTargetParams params;
+  Manifest::ShareTargetParams params;
   // NOTE: These are key names for query parameters, which are filled with share
   // data. As such, |params.url| is just a string.
   params.text = ParseString(share_target_params, "text", Trim);
@@ -557,12 +562,12 @@
   return params;
 }
 
-base::Optional<blink::Manifest::ShareTarget> ManifestParser::ParseShareTarget(
+base::Optional<Manifest::ShareTarget> ManifestParser::ParseShareTarget(
     const base::DictionaryValue& dictionary) {
   if (!dictionary.HasKey("share_target"))
     return base::nullopt;
 
-  blink::Manifest::ShareTarget share_target;
+  Manifest::ShareTarget share_target;
   const base::DictionaryValue* share_target_dict = nullptr;
   dictionary.GetDictionary("share_target", &share_target_dict);
   share_target.action = ParseURL(*share_target_dict, "action", manifest_url_,
@@ -574,9 +579,9 @@
     return base::nullopt;
   }
 
-  base::Optional<blink::Manifest::ShareTarget::Method> method =
+  base::Optional<Manifest::ShareTarget::Method> method =
       ParseShareTargetMethod(*share_target_dict);
-  base::Optional<blink::Manifest::ShareTarget::Enctype> enctype =
+  base::Optional<Manifest::ShareTarget::Enctype> enctype =
       ParseShareTargetEnctype(*share_target_dict);
 
   const base::DictionaryValue* share_target_params_dict = nullptr;
@@ -603,23 +608,22 @@
     return base::nullopt;
   }
 
-  if (method == base::Optional<blink::Manifest::ShareTarget::Method>(
-                    blink::Manifest::ShareTarget::Method::kGet)) {
-    share_target.method = blink::Manifest::ShareTarget::Method::kGet;
+  if (method == base::Optional<Manifest::ShareTarget::Method>(
+                    Manifest::ShareTarget::Method::kGet)) {
+    share_target.method = Manifest::ShareTarget::Method::kGet;
   } else {
-    share_target.method = blink::Manifest::ShareTarget::Method::kPost;
+    share_target.method = Manifest::ShareTarget::Method::kPost;
   }
 
-  if (enctype == base::Optional<blink::Manifest::ShareTarget::Enctype>(
-                     blink::Manifest::ShareTarget::Enctype::kMultipart)) {
-    share_target.enctype = blink::Manifest::ShareTarget::Enctype::kMultipart;
+  if (enctype == base::Optional<Manifest::ShareTarget::Enctype>(
+                     Manifest::ShareTarget::Enctype::kMultipart)) {
+    share_target.enctype = Manifest::ShareTarget::Enctype::kMultipart;
   } else {
-    share_target.enctype = blink::Manifest::ShareTarget::Enctype::kApplication;
+    share_target.enctype = Manifest::ShareTarget::Enctype::kApplication;
   }
 
-  if (share_target.method == blink::Manifest::ShareTarget::Method::kGet) {
-    if (share_target.enctype ==
-        blink::Manifest::ShareTarget::Enctype::kMultipart) {
+  if (share_target.method == Manifest::ShareTarget::Method::kGet) {
+    if (share_target.enctype == Manifest::ShareTarget::Enctype::kMultipart) {
       AddErrorInfo(
           "invalid enctype for GET method. Only "
           "application/x-www-form-urlencoded is allowed.");
@@ -628,9 +632,8 @@
   }
 
   if (share_target.params.files.size() > 0) {
-    if (share_target.method != blink::Manifest::ShareTarget::Method::kPost ||
-        share_target.enctype !=
-            blink::Manifest::ShareTarget::Enctype::kMultipart) {
+    if (share_target.method != Manifest::ShareTarget::Method::kPost ||
+        share_target.enctype != Manifest::ShareTarget::Enctype::kMultipart) {
       AddErrorInfo("files are only supported with multipart/form-data POST.");
       return base::nullopt;
     }
@@ -641,23 +644,23 @@
     return base::nullopt;
   }
 
-  return base::Optional<blink::Manifest::ShareTarget>(std::move(share_target));
+  return base::Optional<Manifest::ShareTarget>(std::move(share_target));
 }
 
-base::Optional<blink::Manifest::FileHandler> ManifestParser::ParseFileHandler(
+base::Optional<Manifest::FileHandler> ManifestParser::ParseFileHandler(
     const base::DictionaryValue& dictionary) {
   constexpr char file_handler_key[] = "file_handler";
   if (!dictionary.HasKey(file_handler_key))
     return base::nullopt;
 
-  blink::Manifest::FileHandler file_handler =
+  Manifest::FileHandler file_handler =
       ParseTargetFiles(file_handler_key, dictionary);
   if (file_handler.size() == 0) {
     AddErrorInfo("no file handlers were specified.");
     return base::nullopt;
   }
 
-  return base::Optional<blink::Manifest::FileHandler>(std::move(file_handler));
+  return base::Optional<Manifest::FileHandler>(std::move(file_handler));
 }
 
 base::NullableString16 ManifestParser::ParseRelatedApplicationPlatform(
@@ -676,17 +679,18 @@
   return ParseString(application, "id", Trim);
 }
 
-std::vector<blink::Manifest::RelatedApplication>
+std::vector<Manifest::RelatedApplication>
 ManifestParser::ParseRelatedApplications(
     const base::DictionaryValue& dictionary) {
-  std::vector<blink::Manifest::RelatedApplication> applications;
+  std::vector<Manifest::RelatedApplication> applications;
   if (!dictionary.HasKey("related_applications"))
     return applications;
 
   const base::ListValue* applications_list = nullptr;
   if (!dictionary.GetList("related_applications", &applications_list)) {
-    AddErrorInfo("property 'related_applications' ignored,"
-                 " type array expected.");
+    AddErrorInfo(
+        "property 'related_applications' ignored,"
+        " type array expected.");
     return applications;
   }
 
@@ -695,13 +699,14 @@
     if (!applications_list->GetDictionary(i, &application_dictionary))
       continue;
 
-    blink::Manifest::RelatedApplication application;
+    Manifest::RelatedApplication application;
     application.platform =
         ParseRelatedApplicationPlatform(*application_dictionary);
     // "If platform is undefined, move onto the next item if any are left."
     if (application.platform.is_null()) {
-      AddErrorInfo("'platform' is a required field, related application"
-                   " ignored.");
+      AddErrorInfo(
+          "'platform' is a required field, related application"
+          " ignored.");
       continue;
     }
 
@@ -710,8 +715,9 @@
     // "If both id and url are undefined, move onto the next item if any are
     // left."
     if (application.url.is_empty() && application.id.is_null()) {
-      AddErrorInfo("one of 'url' or 'id' is required, related application"
-                   " ignored.");
+      AddErrorInfo(
+          "one of 'url' or 'id' is required, related application"
+          " ignored.");
       continue;
     }
 
@@ -743,7 +749,7 @@
 }
 
 base::NullableString16 ManifestParser::ParseGCMSenderID(
-    const base::DictionaryValue& dictionary)  {
+    const base::DictionaryValue& dictionary) {
   return ParseString(dictionary, "gcm_sender_id", Trim);
 }
 
@@ -751,8 +757,8 @@
                                   bool critical,
                                   int error_line,
                                   int error_column) {
-  errors_.push_back(
-      {base::in_place, error_msg, critical, error_line, error_column});
+  ManifestError error = {error_msg, critical, error_line, error_column};
+  errors_.push_back(error);
 }
 
-} // namespace content
+}  // namespace blink
diff --git a/content/renderer/manifest/manifest_parser.h b/third_party/blink/renderer/modules/manifest/manifest_parser.h
similarity index 88%
rename from content/renderer/manifest/manifest_parser.h
rename to third_party/blink/renderer/modules/manifest/manifest_parser.h
index 1a473504..7e058d6 100644
--- a/content/renderer/manifest/manifest_parser.h
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MANIFEST_MANIFEST_PARSER_H_
-#define CONTENT_RENDERER_MANIFEST_MANIFEST_PARSER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MANIFEST_MANIFEST_PARSER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MANIFEST_MANIFEST_PARSER_H_
 
 #include <stdint.h>
 
@@ -13,9 +13,10 @@
 #include "base/optional.h"
 #include "base/strings/nullable_string16.h"
 #include "base/strings/string_piece.h"
-#include "content/common/content_export.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
-#include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
+#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 class GURL;
@@ -24,33 +25,32 @@
 class DictionaryValue;
 }
 
-namespace content {
+namespace blink {
+
+class KURL;
 
 // ManifestParser handles the logic of parsing the Web Manifest from a string.
 // It implements:
 // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-manifest
-class CONTENT_EXPORT ManifestParser {
+class MODULES_EXPORT ManifestParser {
  public:
   ManifestParser(const base::StringPiece& data,
-                 const GURL& manifest_url,
-                 const GURL& document_url);
+                 const KURL& manifest_url,
+                 const KURL& document_url);
   ~ManifestParser();
 
   // Parse the Manifest from a string using following:
   // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-manifest
   void Parse();
 
-  const blink::Manifest& manifest() const;
+  const Manifest& manifest() const;
   bool failed() const;
 
-  void TakeErrors(std::vector<blink::mojom::ManifestErrorPtr>* errors);
+  void TakeErrors(WebVector<ManifestError>* errors);
 
  private:
   // Used to indicate whether to strip whitespace when parsing a string.
-  enum TrimType {
-    Trim,
-    NoTrim
-  };
+  enum TrimType { Trim, NoTrim };
 
   // Indicate whether a parsed URL should be restricted to document origin.
   enum class ParseURLOriginRestrictions {
@@ -115,13 +115,13 @@
   // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-display-member
   // Returns the parsed DisplayMode if any, WebDisplayModeUndefined if the
   // parsing failed.
-  blink::WebDisplayMode ParseDisplay(const base::DictionaryValue& dictionary);
+  WebDisplayMode ParseDisplay(const base::DictionaryValue& dictionary);
 
   // Parses the 'orientation' field of the manifest, as defined in:
   // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-orientation-member
   // Returns the parsed WebScreenOrientationLockType if any,
   // WebScreenOrientationLockDefault if the parsing failed.
-  blink::WebScreenOrientationLockType ParseOrientation(
+  WebScreenOrientationLockType ParseOrientation(
       const base::DictionaryValue& dictionary);
 
   // Parses the 'src' field of an icon, as defined in:
@@ -145,14 +145,14 @@
   // https://w3c.github.io/manifest/#dfn-steps-for-processing-a-purpose-member-of-an-image
   // Returns a vector of Manifest::Icon::IconPurpose with the successfully
   // parsed icon purposes, and nullopt if the parsing failed.
-  base::Optional<std::vector<blink::Manifest::ImageResource::Purpose>>
+  base::Optional<std::vector<Manifest::ImageResource::Purpose>>
   ParseIconPurpose(const base::DictionaryValue& icon);
 
   // Parses the 'icons' field of a Manifest, as defined in:
   // https://w3c.github.io/manifest/#dfn-steps-for-processing-an-array-of-images
   // Returns a vector of Manifest::Icon with the successfully parsed icons, if
   // any. An empty vector if the field was not present or empty.
-  std::vector<blink::Manifest::ImageResource> ParseIcons(
+  std::vector<Manifest::ImageResource> ParseIcons(
       const base::DictionaryValue& dictionary);
 
   // Parses the name field of a share target file, as defined in:
@@ -170,46 +170,46 @@
   // Parses the |key| field of |from| as a list of FileFilters.
   // This is used to parse |file_handlers| and |share_target.params.files|
   // Returns a parsed vector of share target files.
-  std::vector<blink::Manifest::FileFilter> ParseTargetFiles(
+  std::vector<Manifest::FileFilter> ParseTargetFiles(
       const base::StringPiece& key,
       const base::DictionaryValue& from);
 
   // Parses a single FileFilter (see above comment) and appends it to
   // the given |files| vector.
   void ParseFileFilter(const base::DictionaryValue& file_dictionary,
-                       std::vector<blink::Manifest::FileFilter>* files);
+                       std::vector<Manifest::FileFilter>* files);
 
   // Parses the method field of a Share Target, as defined in:
   // https://github.com/WICG/web-share-target/blob/master/docs/interface.md
   // Returns an optional share target method enum object..
-  base::Optional<blink::Manifest::ShareTarget::Method> ParseShareTargetMethod(
+  base::Optional<Manifest::ShareTarget::Method> ParseShareTargetMethod(
       const base::DictionaryValue& share_target_dict);
 
   // Parses the enctype field of a Share Target, as defined in:
   // https://github.com/WICG/web-share-target/blob/master/docs/interface.md
   // Returns an optional share target enctype enum object.
-  base::Optional<blink::Manifest::ShareTarget::Enctype> ParseShareTargetEnctype(
+  base::Optional<Manifest::ShareTarget::Enctype> ParseShareTargetEnctype(
       const base::DictionaryValue& share_target_dict);
 
   // Parses the 'params' field of a Share Target, as defined in:
   // https://wicg.github.io/web-share-target/level-2/#sharetargetparams-and-its-members
   // Returns a parsed Manifest::ShareTargetParams, not all fields need to be
   // populated.
-  blink::Manifest::ShareTargetParams ParseShareTargetParams(
+  Manifest::ShareTargetParams ParseShareTargetParams(
       const base::DictionaryValue& share_target_params);
 
   // Parses the 'share_target' field of a Manifest, as defined in:
   // https://github.com/WICG/web-share-target/blob/master/docs/interface.md
   // Returns the parsed Web Share target. The returned Share Target is null if
   // the field didn't exist, parsing failed, or it was empty.
-  base::Optional<blink::Manifest::ShareTarget> ParseShareTarget(
+  base::Optional<Manifest::ShareTarget> ParseShareTarget(
       const base::DictionaryValue& dictionary);
 
   // Parses the 'file_handler' field of a Manifest, as defined in:
   // https://github.com/WICG/file-handling/blob/master/explainer.md
   // Returns the parsed file handler information. The returned FileHandler is
   // null if the field didn't exist, parsing failed, or it was empty.
-  base::Optional<blink::Manifest::FileHandler> ParseFileHandler(
+  base::Optional<Manifest::FileHandler> ParseFileHandler(
       const base::DictionaryValue& dictionary);
 
   // Parses the 'platform' field of a related application, as defined in:
@@ -234,7 +234,7 @@
   // Returns a vector of Manifest::RelatedApplication with the successfully
   // parsed applications, if any. An empty vector if the field was not present
   // or empty.
-  std::vector<blink::Manifest::RelatedApplication> ParseRelatedApplications(
+  std::vector<Manifest::RelatedApplication> ParseRelatedApplications(
       const base::DictionaryValue& dictionary);
 
   // Parses the 'prefer_related_applications' field on the manifest, as defined
@@ -275,12 +275,12 @@
   GURL document_url_;
 
   bool failed_;
-  blink::Manifest manifest_;
-  std::vector<blink::mojom::ManifestErrorPtr> errors_;
+  Manifest manifest_;
+  Vector<ManifestError> errors_;
 
   DISALLOW_COPY_AND_ASSIGN(ManifestParser);
 };
 
-} // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_MANIFEST_MANIFEST_PARSER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MANIFEST_MANIFEST_PARSER_H_
diff --git a/content/renderer/manifest/manifest_parser_unittest.cc b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
similarity index 76%
rename from content/renderer/manifest/manifest_parser_unittest.cc
rename to third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
index 94475fd5..98e3ead 100644
--- a/content/renderer/manifest/manifest_parser_unittest.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/manifest/manifest_parser.h"
+#include "third_party/blink/renderer/modules/manifest/manifest_parser.h"
 
 #include <stdint.h>
 
@@ -14,40 +14,37 @@
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
-namespace content {
+namespace blink {
 
-class ManifestParserTest : public testing::Test  {
+class ManifestParserTest : public testing::Test {
  protected:
   ManifestParserTest() {}
   ~ManifestParserTest() override {}
 
-  blink::Manifest ParseManifestWithURLs(const base::StringPiece& data,
-                                        const GURL& manifest_url,
-                                        const GURL& document_url) {
-    ManifestParser parser(data, manifest_url, document_url);
+  Manifest ParseManifestWithURLs(const base::StringPiece& data,
+                                 const GURL& manifest_url,
+                                 const GURL& document_url) {
+    ManifestParser parser(data, KURL(manifest_url), KURL(document_url));
     parser.Parse();
-    std::vector<blink::mojom::ManifestErrorPtr> errors;
+    WebVector<ManifestError> errors;
     parser.TakeErrors(&errors);
 
     errors_.clear();
     for (auto& error : errors)
-      errors_.push_back(std::move(error->message));
+      errors_.push_back(std::move(error.message));
     return parser.manifest();
   }
 
-  blink::Manifest ParseManifest(const base::StringPiece& data) {
-    return ParseManifestWithURLs(
-        data, default_manifest_url, default_document_url);
+  Manifest ParseManifest(const base::StringPiece& data) {
+    return ParseManifestWithURLs(data, default_manifest_url,
+                                 default_document_url);
   }
 
-  const std::vector<std::string>& errors() const {
-    return errors_;
-  }
+  const std::vector<std::string>& errors() const { return errors_; }
 
-  unsigned int GetErrorCount() const {
-    return errors_.size();
-  }
+  unsigned int GetErrorCount() const { return errors_.size(); }
 
   static const GURL default_document_url;
   static const GURL default_manifest_url;
@@ -66,10 +63,11 @@
 TEST_F(ManifestParserTest, CrashTest) {
   // Passing temporary variables should not crash.
   const base::StringPiece json = "{\"start_url\": \"/\"}";
-  GURL url("http://example.com");
+  KURL url("http://example.com");
   ManifestParser parser(json, url, url);
+
   parser.Parse();
-  std::vector<blink::mojom::ManifestErrorPtr> errors;
+  WebVector<ManifestError> errors;
   parser.TakeErrors(&errors);
 
   // .Parse() should have been call without crashing and succeeded.
@@ -78,20 +76,19 @@
 }
 
 TEST_F(ManifestParserTest, EmptyStringNull) {
-  blink::Manifest manifest = ParseManifest("");
+  Manifest manifest = ParseManifest("");
 
   // This Manifest is not a valid JSON object, it's a parsing error.
   EXPECT_EQ(1u, GetErrorCount());
-  EXPECT_EQ("Line: 1, column: 1, Unexpected token.",
-            errors()[0]);
+  EXPECT_EQ("Line: 1, column: 1, Unexpected token.", errors()[0]);
 
   // A parsing error is equivalent to an empty manifest.
   ASSERT_TRUE(manifest.IsEmpty());
   ASSERT_TRUE(manifest.name.is_null());
   ASSERT_TRUE(manifest.short_name.is_null());
   ASSERT_TRUE(manifest.start_url.is_empty());
-  ASSERT_EQ(manifest.display, blink::kWebDisplayModeUndefined);
-  ASSERT_EQ(manifest.orientation, blink::kWebScreenOrientationLockDefault);
+  ASSERT_EQ(manifest.display, kWebDisplayModeUndefined);
+  ASSERT_EQ(manifest.orientation, kWebScreenOrientationLockDefault);
   ASSERT_FALSE(manifest.theme_color.has_value());
   ASSERT_FALSE(manifest.background_color.has_value());
   ASSERT_TRUE(manifest.splash_screen_url.is_empty());
@@ -100,7 +97,7 @@
 }
 
 TEST_F(ManifestParserTest, ValidNoContentParses) {
-  blink::Manifest manifest = ParseManifest("{}");
+  Manifest manifest = ParseManifest("{}");
 
   // Empty Manifest is not a parsing error.
   EXPECT_EQ(0u, GetErrorCount());
@@ -110,8 +107,8 @@
   ASSERT_TRUE(manifest.name.is_null());
   ASSERT_TRUE(manifest.short_name.is_null());
   ASSERT_TRUE(manifest.start_url.is_empty());
-  ASSERT_EQ(manifest.display, blink::kWebDisplayModeUndefined);
-  ASSERT_EQ(manifest.orientation, blink::kWebScreenOrientationLockDefault);
+  ASSERT_EQ(manifest.display, kWebDisplayModeUndefined);
+  ASSERT_EQ(manifest.orientation, kWebScreenOrientationLockDefault);
   ASSERT_FALSE(manifest.theme_color.has_value());
   ASSERT_FALSE(manifest.background_color.has_value());
   ASSERT_TRUE(manifest.splash_screen_url.is_empty());
@@ -120,7 +117,7 @@
 }
 
 TEST_F(ManifestParserTest, MultipleErrorsReporting) {
-  blink::Manifest manifest = ParseManifest(
+  Manifest manifest = ParseManifest(
       "{ \"name\": 42, \"short_name\": 4,"
       "\"orientation\": {}, \"display\": \"foo\","
       "\"start_url\": null, \"icons\": {}, \"theme_color\": 42,"
@@ -128,18 +125,14 @@
 
   EXPECT_EQ(8u, GetErrorCount());
 
-  EXPECT_EQ("property 'name' ignored, type string expected.",
-            errors()[0]);
+  EXPECT_EQ("property 'name' ignored, type string expected.", errors()[0]);
   EXPECT_EQ("property 'short_name' ignored, type string expected.",
             errors()[1]);
-  EXPECT_EQ("property 'start_url' ignored, type string expected.",
-            errors()[2]);
-  EXPECT_EQ("unknown 'display' value ignored.",
-            errors()[3]);
+  EXPECT_EQ("property 'start_url' ignored, type string expected.", errors()[2]);
+  EXPECT_EQ("unknown 'display' value ignored.", errors()[3]);
   EXPECT_EQ("property 'orientation' ignored, type string expected.",
             errors()[4]);
-  EXPECT_EQ("property 'icons' ignored, type array expected.",
-            errors()[5]);
+  EXPECT_EQ("property 'icons' ignored, type array expected.", errors()[5]);
   EXPECT_EQ("property 'theme_color' ignored, type string expected.",
             errors()[6]);
   EXPECT_EQ("property 'background_color' ignored, type string expected.",
@@ -149,7 +142,7 @@
 TEST_F(ManifestParserTest, NameParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest = ParseManifest("{ \"name\": \"foo\" }");
+    Manifest manifest = ParseManifest("{ \"name\": \"foo\" }");
     ASSERT_TRUE(base::EqualsASCII(manifest.name.string(), "foo"));
     ASSERT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
@@ -157,34 +150,32 @@
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest = ParseManifest("{ \"name\": \"  foo  \" }");
+    Manifest manifest = ParseManifest("{ \"name\": \"  foo  \" }");
     ASSERT_TRUE(base::EqualsASCII(manifest.name.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Don't parse if name isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"name\": {} }");
+    Manifest manifest = ParseManifest("{ \"name\": {} }");
     ASSERT_TRUE(manifest.name.is_null());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'name' ignored, type string expected.",
-              errors()[0]);
+    EXPECT_EQ("property 'name' ignored, type string expected.", errors()[0]);
   }
 
   // Don't parse if name isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"name\": 42 }");
+    Manifest manifest = ParseManifest("{ \"name\": 42 }");
     ASSERT_TRUE(manifest.name.is_null());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'name' ignored, type string expected.",
-              errors()[0]);
+    EXPECT_EQ("property 'name' ignored, type string expected.", errors()[0]);
   }
 }
 
 TEST_F(ManifestParserTest, ShortNameParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest = ParseManifest("{ \"short_name\": \"foo\" }");
+    Manifest manifest = ParseManifest("{ \"short_name\": \"foo\" }");
     ASSERT_TRUE(base::EqualsASCII(manifest.short_name.string(), "foo"));
     ASSERT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
@@ -192,14 +183,14 @@
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest = ParseManifest("{ \"short_name\": \"  foo  \" }");
+    Manifest manifest = ParseManifest("{ \"short_name\": \"  foo  \" }");
     ASSERT_TRUE(base::EqualsASCII(manifest.short_name.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Don't parse if name isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"short_name\": {} }");
+    Manifest manifest = ParseManifest("{ \"short_name\": {} }");
     ASSERT_TRUE(manifest.short_name.is_null());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'short_name' ignored, type string expected.",
@@ -208,7 +199,7 @@
 
   // Don't parse if name isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"short_name\": 42 }");
+    Manifest manifest = ParseManifest("{ \"short_name\": 42 }");
     ASSERT_TRUE(manifest.short_name.is_null());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'short_name' ignored, type string expected.",
@@ -219,8 +210,7 @@
 TEST_F(ManifestParserTest, StartURLParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"start_url\": \"land.html\" }");
+    Manifest manifest = ParseManifest("{ \"start_url\": \"land.html\" }");
     ASSERT_EQ(manifest.start_url.spec(),
               default_document_url.Resolve("land.html").spec());
     ASSERT_FALSE(manifest.IsEmpty());
@@ -229,8 +219,7 @@
 
   // Whitespaces.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"start_url\": \"  land.html  \" }");
+    Manifest manifest = ParseManifest("{ \"start_url\": \"  land.html  \" }");
     ASSERT_EQ(manifest.start_url.spec(),
               default_document_url.Resolve("land.html").spec());
     EXPECT_EQ(0u, GetErrorCount());
@@ -238,7 +227,7 @@
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"start_url\": {} }");
+    Manifest manifest = ParseManifest("{ \"start_url\": {} }");
     ASSERT_TRUE(manifest.start_url.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'start_url' ignored, type string expected.",
@@ -247,7 +236,7 @@
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"start_url\": 42 }");
+    Manifest manifest = ParseManifest("{ \"start_url\": 42 }");
     ASSERT_TRUE(manifest.start_url.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'start_url' ignored, type string expected.",
@@ -256,7 +245,7 @@
 
   // Don't parse if property isn't a valid URL.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"start_url\": \"http://www.google.ca:a\" }");
     ASSERT_TRUE(manifest.start_url.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
@@ -265,7 +254,7 @@
 
   // Absolute start_url, same origin with document.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifestWithURLs("{ \"start_url\": \"http://foo.com/land.html\" }",
                               GURL("http://foo.com/manifest.json"),
                               GURL("http://foo.com/index.html"));
@@ -275,20 +264,21 @@
 
   // Absolute start_url, cross origin with document.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifestWithURLs("{ \"start_url\": \"http://bar.com/land.html\" }",
                               GURL("http://foo.com/manifest.json"),
                               GURL("http://foo.com/index.html"));
     ASSERT_TRUE(manifest.start_url.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'start_url' ignored, should "
-              "be same origin as document.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'start_url' ignored, should "
+        "be same origin as document.",
+        errors()[0]);
   }
 
   // Resolving has to happen based on the manifest_url.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifestWithURLs("{ \"start_url\": \"land.html\" }",
                               GURL("http://foo.com/landing/manifest.json"),
                               GURL("http://foo.com/index.html"));
@@ -300,7 +290,7 @@
 TEST_F(ManifestParserTest, ScopeParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"scope\": \"land\", \"start_url\": \"land/landing.html\" }");
     ASSERT_EQ(manifest.scope.spec(),
               default_document_url.Resolve("land").spec());
@@ -310,7 +300,7 @@
 
   // Whitespaces.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"scope\": \"  land  \", \"start_url\": \"land/landing.html\" }");
     ASSERT_EQ(manifest.scope.spec(),
               default_document_url.Resolve("land").spec());
@@ -319,7 +309,7 @@
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"scope\": {} }");
+    Manifest manifest = ParseManifest("{ \"scope\": {} }");
     ASSERT_TRUE(manifest.scope.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'scope' ignored, type string expected.", errors()[0]);
@@ -327,7 +317,7 @@
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"scope\": 42 }");
+    Manifest manifest = ParseManifest("{ \"scope\": 42 }");
     ASSERT_TRUE(manifest.scope.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'scope' ignored, type string expected.", errors()[0]);
@@ -335,7 +325,7 @@
 
   // Absolute scope, start URL is in scope.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"scope\": \"http://foo.com/land\", "
         "\"start_url\": \"http://foo.com/land/landing.html\" }",
         GURL("http://foo.com/manifest.json"),
@@ -346,21 +336,22 @@
 
   // Absolute scope, start URL is not in scope.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"scope\": \"http://foo.com/land\", "
         "\"start_url\": \"http://foo.com/index.html\" }",
         GURL("http://foo.com/manifest.json"),
         GURL("http://foo.com/index.html"));
     ASSERT_TRUE(manifest.scope.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'scope' ignored. Start url should be within scope "
-              "of scope URL.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'scope' ignored. Start url should be within scope "
+        "of scope URL.",
+        errors()[0]);
   }
 
   // Absolute scope, start URL has different origin than scope URL.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"scope\": \"http://foo.com/land\", "
         "\"start_url\": \"http://bar.com/land/landing.html\" }",
         GURL("http://foo.com/manifest.json"),
@@ -370,14 +361,15 @@
     EXPECT_EQ(
         "property 'start_url' ignored, should be same origin as document.",
         errors()[0]);
-    EXPECT_EQ("property 'scope' ignored. Start url should be within scope "
-              "of scope URL.",
-              errors()[1]);
+    EXPECT_EQ(
+        "property 'scope' ignored. Start url should be within scope "
+        "of scope URL.",
+        errors()[1]);
   }
 
   // scope and start URL have diferent origin than document URL.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"scope\": \"http://foo.com/land\", "
         "\"start_url\": \"http://foo.com/land/landing.html\" }",
         GURL("http://foo.com/manifest.json"),
@@ -393,7 +385,7 @@
 
   // No start URL. Document URL is in scope.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifestWithURLs("{ \"scope\": \"http://foo.com/land\" }",
                               GURL("http://foo.com/manifest.json"),
                               GURL("http://foo.com/land/index.html"));
@@ -403,19 +395,20 @@
 
   // No start URL. Document is out of scope.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifestWithURLs("{ \"scope\": \"http://foo.com/land\" }",
                               GURL("http://foo.com/manifest.json"),
                               GURL("http://foo.com/index.html"));
     ASSERT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'scope' ignored. Start url should be within scope "
-              "of scope URL.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'scope' ignored. Start url should be within scope "
+        "of scope URL.",
+        errors()[0]);
   }
 
   // Resolving has to happen based on the manifest_url.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"scope\": \"treasure\" }", GURL("http://foo.com/map/manifest.json"),
         GURL("http://foo.com/map/treasure/island/index.html"));
     ASSERT_EQ(manifest.scope.spec(), "http://foo.com/map/treasure");
@@ -424,7 +417,7 @@
 
   // Scope is parent directory.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"scope\": \"..\" }", GURL("http://foo.com/map/manifest.json"),
         GURL("http://foo.com/index.html"));
     ASSERT_EQ(manifest.scope.spec(), "http://foo.com/");
@@ -433,7 +426,7 @@
 
   // Scope tries to go up past domain.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"scope\": \"../..\" }", GURL("http://foo.com/map/manifest.json"),
         GURL("http://foo.com/index.html"));
     ASSERT_EQ(manifest.scope.spec(), "http://foo.com/");
@@ -444,82 +437,81 @@
 TEST_F(ManifestParserTest, DisplayParserRules) {
   // Smoke test.
   {
-    blink::Manifest manifest = ParseManifest("{ \"display\": \"browser\" }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeBrowser);
+    Manifest manifest = ParseManifest("{ \"display\": \"browser\" }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeBrowser);
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"display\": \"  browser  \" }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeBrowser);
+    Manifest manifest = ParseManifest("{ \"display\": \"  browser  \" }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeBrowser);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Don't parse if name isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"display\": {} }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeUndefined);
+    Manifest manifest = ParseManifest("{ \"display\": {} }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeUndefined);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'display' ignored,"
-              " type string expected.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'display' ignored,"
+        " type string expected.",
+        errors()[0]);
   }
 
   // Don't parse if name isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"display\": 42 }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeUndefined);
+    Manifest manifest = ParseManifest("{ \"display\": 42 }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeUndefined);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'display' ignored,"
-              " type string expected.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'display' ignored,"
+        " type string expected.",
+        errors()[0]);
   }
 
   // Parse fails if string isn't known.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"display\": \"browser_something\" }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeUndefined);
+    Manifest manifest = ParseManifest("{ \"display\": \"browser_something\" }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeUndefined);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("unknown 'display' value ignored.",
-              errors()[0]);
+    EXPECT_EQ("unknown 'display' value ignored.", errors()[0]);
   }
 
   // Accept 'fullscreen'.
   {
-    blink::Manifest manifest = ParseManifest("{ \"display\": \"fullscreen\" }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeFullscreen);
+    Manifest manifest = ParseManifest("{ \"display\": \"fullscreen\" }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeFullscreen);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'fullscreen'.
   {
-    blink::Manifest manifest = ParseManifest("{ \"display\": \"standalone\" }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeStandalone);
+    Manifest manifest = ParseManifest("{ \"display\": \"standalone\" }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeStandalone);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'minimal-ui'.
   {
-    blink::Manifest manifest = ParseManifest("{ \"display\": \"minimal-ui\" }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeMinimalUi);
+    Manifest manifest = ParseManifest("{ \"display\": \"minimal-ui\" }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeMinimalUi);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'browser'.
   {
-    blink::Manifest manifest = ParseManifest("{ \"display\": \"browser\" }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeBrowser);
+    Manifest manifest = ParseManifest("{ \"display\": \"browser\" }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeBrowser);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Case insensitive.
   {
-    blink::Manifest manifest = ParseManifest("{ \"display\": \"BROWSER\" }");
-    EXPECT_EQ(manifest.display, blink::kWebDisplayModeBrowser);
+    Manifest manifest = ParseManifest("{ \"display\": \"BROWSER\" }");
+    EXPECT_EQ(manifest.display, kWebDisplayModeBrowser);
     EXPECT_EQ(0u, GetErrorCount());
   }
 }
@@ -527,25 +519,23 @@
 TEST_F(ManifestParserTest, OrientationParserRules) {
   // Smoke test.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"orientation\": \"natural\" }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockNatural);
+    Manifest manifest = ParseManifest("{ \"orientation\": \"natural\" }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockNatural);
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"orientation\": \"natural\" }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockNatural);
+    Manifest manifest = ParseManifest("{ \"orientation\": \"natural\" }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockNatural);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Don't parse if name isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"orientation\": {} }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockDefault);
+    Manifest manifest = ParseManifest("{ \"orientation\": {} }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockDefault);
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'orientation' ignored, type string expected.",
               errors()[0]);
@@ -553,8 +543,8 @@
 
   // Don't parse if name isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"orientation\": 42 }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockDefault);
+    Manifest manifest = ParseManifest("{ \"orientation\": 42 }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockDefault);
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'orientation' ignored, type string expected.",
               errors()[0]);
@@ -562,86 +552,77 @@
 
   // Parse fails if string isn't known.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"orientation\": \"naturalish\" }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockDefault);
+    Manifest manifest = ParseManifest("{ \"orientation\": \"naturalish\" }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockDefault);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("unknown 'orientation' value ignored.",
-              errors()[0]);
+    EXPECT_EQ("unknown 'orientation' value ignored.", errors()[0]);
   }
 
   // Accept 'any'.
   {
-    blink::Manifest manifest = ParseManifest("{ \"orientation\": \"any\" }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockAny);
+    Manifest manifest = ParseManifest("{ \"orientation\": \"any\" }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockAny);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'natural'.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"orientation\": \"natural\" }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockNatural);
+    Manifest manifest = ParseManifest("{ \"orientation\": \"natural\" }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockNatural);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'landscape'.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"orientation\": \"landscape\" }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockLandscape);
+    Manifest manifest = ParseManifest("{ \"orientation\": \"landscape\" }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockLandscape);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'landscape-primary'.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"orientation\": \"landscape-primary\" }");
-    EXPECT_EQ(manifest.orientation,
-              blink::kWebScreenOrientationLockLandscapePrimary);
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockLandscapePrimary);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'landscape-secondary'.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"orientation\": \"landscape-secondary\" }");
     EXPECT_EQ(manifest.orientation,
-              blink::kWebScreenOrientationLockLandscapeSecondary);
+              kWebScreenOrientationLockLandscapeSecondary);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'portrait'.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"orientation\": \"portrait\" }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockPortrait);
+    Manifest manifest = ParseManifest("{ \"orientation\": \"portrait\" }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockPortrait);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'portrait-primary'.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"orientation\": \"portrait-primary\" }");
-    EXPECT_EQ(manifest.orientation,
-              blink::kWebScreenOrientationLockPortraitPrimary);
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockPortraitPrimary);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept 'portrait-secondary'.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"orientation\": \"portrait-secondary\" }");
-    EXPECT_EQ(manifest.orientation,
-              blink::kWebScreenOrientationLockPortraitSecondary);
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockPortraitSecondary);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Case insensitive.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"orientation\": \"LANDSCAPE\" }");
-    EXPECT_EQ(manifest.orientation, blink::kWebScreenOrientationLockLandscape);
+    Manifest manifest = ParseManifest("{ \"orientation\": \"LANDSCAPE\" }");
+    EXPECT_EQ(manifest.orientation, kWebScreenOrientationLockLandscape);
     EXPECT_EQ(0u, GetErrorCount());
   }
 }
@@ -649,7 +630,7 @@
 TEST_F(ManifestParserTest, IconsParseRules) {
   // Smoke test: if no icon, empty list.
   {
-    blink::Manifest manifest = ParseManifest("{ \"icons\": [] }");
+    Manifest manifest = ParseManifest("{ \"icons\": [] }");
     EXPECT_EQ(manifest.icons.size(), 0u);
     EXPECT_TRUE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
@@ -657,7 +638,7 @@
 
   // Smoke test: if empty icon, empty list.
   {
-    blink::Manifest manifest = ParseManifest("{ \"icons\": [ {} ] }");
+    Manifest manifest = ParseManifest("{ \"icons\": [ {} ] }");
     EXPECT_EQ(manifest.icons.size(), 0u);
     EXPECT_TRUE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
@@ -665,8 +646,7 @@
 
   // Smoke test: icon with invalid src, empty list.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"icons\": [ { \"icons\": [] } ] }");
+    Manifest manifest = ParseManifest("{ \"icons\": [ { \"icons\": [] } ] }");
     EXPECT_EQ(manifest.icons.size(), 0u);
     EXPECT_TRUE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
@@ -674,8 +654,7 @@
 
   // Smoke test: if icon with empty src, it will be present in the list.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"icons\": [ { \"src\": \"\" } ] }");
+    Manifest manifest = ParseManifest("{ \"icons\": [ { \"src\": \"\" } ] }");
     EXPECT_EQ(manifest.icons.size(), 1u);
     EXPECT_EQ(manifest.icons[0].src.spec(), "http://foo.com/manifest.json");
     EXPECT_FALSE(manifest.IsEmpty());
@@ -684,7 +663,7 @@
 
   // Smoke test: if one icons with valid src, it will be present in the list.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"icons\": [{ \"src\": \"foo.jpg\" }] }");
     EXPECT_EQ(manifest.icons.size(), 1u);
     EXPECT_EQ(manifest.icons[0].src.spec(), "http://foo.com/foo.jpg");
@@ -696,7 +675,7 @@
 TEST_F(ManifestParserTest, IconSrcParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"foo.png\" } ] }");
     EXPECT_EQ(manifest.icons[0].src.spec(),
               default_document_url.Resolve("foo.png").spec());
@@ -705,7 +684,7 @@
 
   // Whitespaces.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"   foo.png   \" } ] }");
     EXPECT_EQ(manifest.icons[0].src.spec(),
               default_document_url.Resolve("foo.png").spec());
@@ -714,27 +693,23 @@
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"icons\": [ {\"src\": {} } ] }");
+    Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": {} } ] }");
     EXPECT_TRUE(manifest.icons.empty());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'src' ignored, type string expected.",
-              errors()[0]);
+    EXPECT_EQ("property 'src' ignored, type string expected.", errors()[0]);
   }
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"icons\": [ {\"src\": 42 } ] }");
+    Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": 42 } ] }");
     EXPECT_TRUE(manifest.icons.empty());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'src' ignored, type string expected.",
-              errors()[0]);
+    EXPECT_EQ("property 'src' ignored, type string expected.", errors()[0]);
   }
 
   // Resolving has to happen based on the document_url.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"icons\": [ {\"src\": \"icons/foo.png\" } ] }",
         GURL("http://foo.com/landing/index.html"), default_manifest_url);
     EXPECT_EQ(manifest.icons[0].src.spec(),
@@ -746,7 +721,7 @@
 TEST_F(ManifestParserTest, IconTypeParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": \"foo\" } ] }");
     EXPECT_TRUE(base::EqualsASCII(manifest.icons[0].type, "foo"));
     EXPECT_EQ(0u, GetErrorCount());
@@ -754,7 +729,7 @@
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         " \"type\": \"  foo  \" } ] }");
     EXPECT_TRUE(base::EqualsASCII(manifest.icons[0].type, "foo"));
@@ -763,29 +738,27 @@
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": {} } ] }");
     EXPECT_TRUE(manifest.icons[0].type.empty());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'type' ignored, type string expected.",
-              errors()[0]);
+    EXPECT_EQ("property 'type' ignored, type string expected.", errors()[0]);
   }
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": 42 } ] }");
     EXPECT_TRUE(manifest.icons[0].type.empty());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'type' ignored, type string expected.",
-              errors()[0]);
+    EXPECT_EQ("property 'type' ignored, type string expected.", errors()[0]);
   }
 }
 
 TEST_F(ManifestParserTest, IconSizesParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"42x42\" } ] }");
     EXPECT_EQ(manifest.icons[0].sizes.size(), 1u);
@@ -794,7 +767,7 @@
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"  42x42  \" } ] }");
     EXPECT_EQ(manifest.icons[0].sizes.size(), 1u);
@@ -803,29 +776,27 @@
 
   // Ignore sizes if property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": {} } ] }");
     EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'sizes' ignored, type string expected.",
-              errors()[0]);
+    EXPECT_EQ("property 'sizes' ignored, type string expected.", errors()[0]);
   }
 
   // Ignore sizes if property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": 42 } ] }");
     EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'sizes' ignored, type string expected.",
-              errors()[0]);
+    EXPECT_EQ("property 'sizes' ignored, type string expected.", errors()[0]);
   }
 
   // Smoke test: value correctly parsed.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"42x42  48x48\" } ] }");
     EXPECT_EQ(manifest.icons[0].sizes[0], gfx::Size(42, 42));
@@ -835,7 +806,7 @@
 
   // <WIDTH>'x'<HEIGHT> and <WIDTH>'X'<HEIGHT> are equivalent.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"42X42  48X48\" } ] }");
     EXPECT_EQ(manifest.icons[0].sizes[0], gfx::Size(42, 42));
@@ -845,7 +816,7 @@
 
   // Twice the same value is parsed twice.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"42X42  42x42\" } ] }");
     EXPECT_EQ(manifest.icons[0].sizes[0], gfx::Size(42, 42));
@@ -855,29 +826,27 @@
 
   // Width or height can't start with 0.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"004X007  042x00\" } ] }");
     EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("found icon with no valid size.",
-              errors()[0]);
+    EXPECT_EQ("found icon with no valid size.", errors()[0]);
   }
 
   // Width and height MUST contain digits.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"e4X1.0  55ax1e10\" } ] }");
     EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("found icon with no valid size.",
-              errors()[0]);
+    EXPECT_EQ("found icon with no valid size.", errors()[0]);
   }
 
   // 'any' is correctly parsed and transformed to gfx::Size(0,0).
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"any AnY ANY aNy\" } ] }");
     gfx::Size any = gfx::Size(0, 0);
@@ -891,13 +860,12 @@
 
   // Some invalid width/height combinations.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"sizes\": \"x 40xx 1x2x3 x42 42xx42\" } ] }");
     EXPECT_EQ(manifest.icons[0].sizes.size(), 0u);
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("found icon with no valid size.",
-              errors()[0]);
+    EXPECT_EQ("found icon with no valid size.", errors()[0]);
   }
 }
 
@@ -912,7 +880,7 @@
 
   // Smoke test.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": \"any\" } ] }");
     EXPECT_EQ(manifest.icons[0].purpose.size(), 1u);
@@ -921,7 +889,7 @@
 
   // Trim leading and trailing whitespaces.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": \"  any  \" } ] }");
     EXPECT_EQ(manifest.icons[0].purpose.size(), 1u);
@@ -930,23 +898,22 @@
 
   // 'any' is added when property isn't present.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"icons\": [ {\"src\": \"\" } ] }");
+    Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\" } ] }");
     EXPECT_EQ(manifest.icons[0].purpose.size(), 1u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
-              blink::Manifest::ImageResource::Purpose::ANY);
+              Manifest::ImageResource::Purpose::ANY);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // 'any' is added with error message when property isn't a string (is a
   // number).
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": 42 } ] }");
     EXPECT_EQ(manifest.icons[0].purpose.size(), 1u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
-              blink::Manifest::ImageResource::Purpose::ANY);
+              Manifest::ImageResource::Purpose::ANY);
     ASSERT_EQ(1u, GetErrorCount());
     EXPECT_EQ(kPurposeParseStringError, errors()[0]);
   }
@@ -954,72 +921,72 @@
   // 'any' is added with error message when property isn't a string (is a
   // dictionary).
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": {} } ] }");
     EXPECT_EQ(manifest.icons[0].purpose.size(), 1u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
-              blink::Manifest::ImageResource::Purpose::ANY);
+              Manifest::ImageResource::Purpose::ANY);
     ASSERT_EQ(1u, GetErrorCount());
     EXPECT_EQ(kPurposeParseStringError, errors()[0]);
   }
 
   // Smoke test: values correctly parsed.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": \"Any Badge Maskable\" } ] }");
     ASSERT_EQ(manifest.icons[0].purpose.size(), 3u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
-              blink::Manifest::ImageResource::Purpose::ANY);
+              Manifest::ImageResource::Purpose::ANY);
     EXPECT_EQ(manifest.icons[0].purpose[1],
-              blink::Manifest::ImageResource::Purpose::BADGE);
+              Manifest::ImageResource::Purpose::BADGE);
     EXPECT_EQ(manifest.icons[0].purpose[2],
-              blink::Manifest::ImageResource::Purpose::MASKABLE);
+              Manifest::ImageResource::Purpose::MASKABLE);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Trim whitespaces between values.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": \"  Any   Badge  \" } ] }");
     ASSERT_EQ(manifest.icons[0].purpose.size(), 2u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
-              blink::Manifest::ImageResource::Purpose::ANY);
+              Manifest::ImageResource::Purpose::ANY);
     EXPECT_EQ(manifest.icons[0].purpose[1],
-              blink::Manifest::ImageResource::Purpose::BADGE);
+              Manifest::ImageResource::Purpose::BADGE);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Twice the same value is parsed twice.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": \"badge badge\" } ] }");
     ASSERT_EQ(manifest.icons[0].purpose.size(), 2u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
-              blink::Manifest::ImageResource::Purpose::BADGE);
+              Manifest::ImageResource::Purpose::BADGE);
     EXPECT_EQ(manifest.icons[0].purpose[1],
-              blink::Manifest::ImageResource::Purpose::BADGE);
+              Manifest::ImageResource::Purpose::BADGE);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Invalid icon purpose is ignored.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": \"badge fizzbuzz\" } ] }");
     ASSERT_EQ(manifest.icons[0].purpose.size(), 1u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
-              blink::Manifest::ImageResource::Purpose::BADGE);
+              Manifest::ImageResource::Purpose::BADGE);
     ASSERT_EQ(1u, GetErrorCount());
     EXPECT_EQ(kSomeInvalidPurposeError, errors()[0]);
   }
 
   // If developer-supplied purpose is invalid, entire icon is removed.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
         "\"purpose\": \"fizzbuzz\" } ] }");
     ASSERT_EQ(0u, manifest.icons.size());
@@ -1029,13 +996,13 @@
 
   // Two icons, one with an invalid purpose and the other normal.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\", \"purpose\": \"fizzbuzz\" }, "
         "               {\"src\": \"\" }] }");
     ASSERT_EQ(1u, manifest.icons.size());
     ASSERT_EQ(manifest.icons[0].purpose.size(), 1u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
-              blink::Manifest::ImageResource::Purpose::ANY);
+              Manifest::ImageResource::Purpose::ANY);
     ASSERT_EQ(1u, GetErrorCount());
     EXPECT_EQ(kPurposeInvalidValueError, errors()[0]);
   }
@@ -1044,7 +1011,7 @@
 TEST_F(ManifestParserTest, FileHandlerParseRules) {
   // Contains file_handler field but no keys.
   {
-    blink::Manifest manifest = ParseManifest("{ \"file_handler\": [] }");
+    Manifest manifest = ParseManifest("{ \"file_handler\": [] }");
     EXPECT_FALSE(manifest.file_handler.has_value());
     EXPECT_TRUE(manifest.IsEmpty());
     EXPECT_EQ(1u, GetErrorCount());
@@ -1053,7 +1020,7 @@
 
   // Single accept value can be parsed from string.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{"
         "  \"file_handler\": ["
         "    {"
@@ -1074,7 +1041,7 @@
 
   // Single accept value can be parsed from list.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{"
         "  \"file_handler\": ["
         "    {"
@@ -1095,7 +1062,7 @@
 
   // Multiple accept values can be parsed.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{"
         "  \"file_handler\": ["
         "    {"
@@ -1117,7 +1084,7 @@
 
   // Multiple file handlers can be parsed.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{"
         "  \"file_handler\": ["
         "    {"
@@ -1152,7 +1119,7 @@
 TEST_F(ManifestParserTest, ShareTargetParseRules) {
   // Contains share_target field but no keys.
   {
-    blink::Manifest manifest = ParseManifest("{ \"share_target\": {} }");
+    Manifest manifest = ParseManifest("{ \"share_target\": {} }");
     EXPECT_FALSE(manifest.share_target.has_value());
     EXPECT_TRUE(manifest.IsEmpty());
     EXPECT_EQ(1u, GetErrorCount());
@@ -1162,7 +1129,7 @@
 
   // Contains share_target field but no params key.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"share_target\": { \"action\": \"\" } }");
     EXPECT_FALSE(manifest.share_target.has_value());
     EXPECT_TRUE(manifest.IsEmpty());
@@ -1184,7 +1151,7 @@
 
   // Contains share_target field but no action key.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"share_target\": { \"params\": {} } }");
     EXPECT_FALSE(manifest.share_target.has_value());
     EXPECT_TRUE(manifest.IsEmpty());
@@ -1195,7 +1162,7 @@
 
   // Key in share_target that isn't valid.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"share_target\": {\"incorrect_key\": \"some_value\" } }");
     ASSERT_FALSE(manifest.share_target.has_value());
     EXPECT_TRUE(manifest.IsEmpty());
@@ -1211,7 +1178,7 @@
 
   // Contains share_target, but action is empty.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"\", \"params\": {} } }",
         manifest_url, document_url);
     ASSERT_TRUE(manifest.share_target.has_value());
@@ -1234,7 +1201,7 @@
 
   // Parse but throw an error if url_template property isn't a string.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"\", \"params\": {} } }",
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
@@ -1257,7 +1224,7 @@
 
   // Don't parse if action property isn't a string.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": {}, \"params\": {} } }",
         manifest_url, document_url);
     EXPECT_FALSE(manifest.share_target.has_value());
@@ -1270,7 +1237,7 @@
 
   // Don't parse if action property isn't a string.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": 42, \"params\": {} } }",
         manifest_url, document_url);
     EXPECT_FALSE(manifest.share_target.has_value());
@@ -1283,7 +1250,7 @@
 
   // Don't parse if params property isn't a dict.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"\", \"params\": \"\" } }",
         manifest_url, document_url);
     EXPECT_FALSE(manifest.share_target.has_value());
@@ -1306,7 +1273,7 @@
 
   // Don't parse if params property isn't a dict.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"\", \"params\": 42 } }",
         manifest_url, document_url);
     EXPECT_FALSE(manifest.share_target.has_value());
@@ -1329,7 +1296,7 @@
 
   // Ignore params keys with invalid types.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"\", \"params\": { \"text\": 42 }"
         " } }",
         manifest_url, document_url);
@@ -1354,7 +1321,7 @@
 
   // Ignore params keys with invalid types.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"\", "
         "\"params\": { \"title\": 42 } } }",
         manifest_url, document_url);
@@ -1379,7 +1346,7 @@
 
   // Don't parse if params property has keys with invalid types.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"\", \"params\": { \"url\": {}, "
         "\"text\": \"hi\" } } }",
         manifest_url, document_url);
@@ -1405,7 +1372,7 @@
 
   // Don't parse if action property isn't a valid URL.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com:a\", \"params\": "
         "{} } }",
         manifest_url, document_url);
@@ -1420,7 +1387,7 @@
   // Fail parsing if action is at a different origin than the Web
   // Manifest.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo2.com/\" }, "
         "\"params\": {} }",
         manifest_url, document_url);
@@ -1437,7 +1404,7 @@
 
   // Smoke test: Contains share_target and action, and action is valid.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": {\"action\": \"share/\", \"params\": {} } }",
         manifest_url, document_url);
     ASSERT_TRUE(manifest.share_target.has_value());
@@ -1461,7 +1428,7 @@
   // Smoke test: Contains share_target and action, and action is valid, params
   // is populated.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": {\"action\": \"share/\", \"params\": { \"text\": "
         "\"foo\", \"title\": \"bar\", \"url\": \"baz\" } } }",
         manifest_url, document_url);
@@ -1489,7 +1456,7 @@
   // Backwards compatibility test: Contains share_target, url_template and
   // action, and action is valid, params is populated.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"url_template\": "
         "\"foo.com/share?title={title}\", "
         "\"action\": \"share/\", \"params\": { \"text\": "
@@ -1519,7 +1486,7 @@
   // Smoke test: Contains share_target, action and params. action is
   // valid and is absolute.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"params\": "
         "{ \"title\": \"mytitle\" } } "
         "}",
@@ -1545,7 +1512,7 @@
 
   // Return undefined if method or enctype is not string.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "10, \"enctype\": 10, \"params\": "
         "{ \"title\": \"mytitle\" } } "
@@ -1561,7 +1528,7 @@
 
   // Valid method and enctype.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"GET\", \"enctype\": \"application/x-www-form-urlencoded\", "
         "\"params\": "
@@ -1570,29 +1537,29 @@
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
     EXPECT_EQ(manifest.share_target->method,
-              blink::Manifest::ShareTarget::Method::kGet);
+              Manifest::ShareTarget::Method::kGet);
     EXPECT_EQ(manifest.share_target->enctype,
-              blink::Manifest::ShareTarget::Enctype::kApplication);
+              Manifest::ShareTarget::Enctype::kApplication);
   }
 
   // Auto-fill in "GET" for method and "application/x-www-form-urlencoded" for
   // enctype.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"params\": "
         "{ \"title\": \"mytitle\" } } "
         "}",
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
     EXPECT_EQ(manifest.share_target->method,
-              blink::Manifest::ShareTarget::Method::kGet);
+              Manifest::ShareTarget::Method::kGet);
     EXPECT_EQ(manifest.share_target->enctype,
-              blink::Manifest::ShareTarget::Enctype::kApplication);
+              Manifest::ShareTarget::Enctype::kApplication);
   }
 
   // Invalid method values, return undefined.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"\", \"enctype\": \"application/x-www-form-urlencoded\", \"params\": "
         "{ \"title\": \"mytitle\" } } "
@@ -1609,7 +1576,7 @@
   // When method is "GET", enctype cannot be anything other than
   // "application/x-www-form-urlencoded".
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"GET\", \"enctype\": \"RANDOM\", \"params\": "
         "{ \"title\": \"mytitle\" } } "
@@ -1626,7 +1593,7 @@
   // When method is "POST", enctype cannot be anything other than
   // "application/x-www-form-urlencoded" or "multipart/form-data".
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"random\", \"params\": "
         "{ \"title\": \"mytitle\" } } "
@@ -1642,7 +1609,7 @@
 
   // Valid enctype for when method is "POST".
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"application/x-www-form-urlencoded\", "
         "\"params\": "
@@ -1651,15 +1618,15 @@
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
     EXPECT_EQ(manifest.share_target->method,
-              blink::Manifest::ShareTarget::Method::kPost);
+              Manifest::ShareTarget::Method::kPost);
     EXPECT_EQ(manifest.share_target->enctype,
-              blink::Manifest::ShareTarget::Enctype::kApplication);
+              Manifest::ShareTarget::Enctype::kApplication);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Valid enctype for when method is "POST".
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\" } } "
@@ -1667,15 +1634,15 @@
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
     EXPECT_EQ(manifest.share_target->method,
-              blink::Manifest::ShareTarget::Method::kPost);
+              Manifest::ShareTarget::Method::kPost);
     EXPECT_EQ(manifest.share_target->enctype,
-              blink::Manifest::ShareTarget::Enctype::kMultipart);
+              Manifest::ShareTarget::Enctype::kMultipart);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Ascii in-sensitive.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"PosT\", \"enctype\": \"mUltIparT/Form-dAta\", \"params\": "
         "{ \"title\": \"mytitle\" } } "
@@ -1683,15 +1650,15 @@
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
     EXPECT_EQ(manifest.share_target->method,
-              blink::Manifest::ShareTarget::Method::kPost);
+              Manifest::ShareTarget::Method::kPost);
     EXPECT_EQ(manifest.share_target->enctype,
-              blink::Manifest::ShareTarget::Enctype::kMultipart);
+              Manifest::ShareTarget::Enctype::kMultipart);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // No files is okay.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [] } } "
@@ -1699,16 +1666,16 @@
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
     EXPECT_EQ(manifest.share_target->method,
-              blink::Manifest::ShareTarget::Method::kPost);
+              Manifest::ShareTarget::Method::kPost);
     EXPECT_EQ(manifest.share_target->enctype,
-              blink::Manifest::ShareTarget::Enctype::kMultipart);
+              Manifest::ShareTarget::Enctype::kMultipart);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Nonempty file must have POST method and multipart/form-data enctype.
   // GET method, for example, will cause an error in this case.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"GET\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [{ \"name\": \"name\", "
@@ -1726,7 +1693,7 @@
   // Nonempty file must have POST method and multipart/form-data enctype.
   // Enctype other than multipart/form-data will cause an error.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"application/x-www-form-urlencoded\", "
         "\"params\": "
@@ -1743,7 +1710,7 @@
   // Nonempty file must have POST method and multipart/form-data enctype.
   // This case is valid.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [{ \"name\": \"name\", "
@@ -1757,7 +1724,7 @@
 
   // Invalid mimetype.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [{ \"name\": \"name\", "
@@ -1771,7 +1738,7 @@
 
   // Invalid mimetype.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [{ \"name\": \"name\", "
@@ -1785,7 +1752,7 @@
 
   // Invalid mimetype.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [{ \"name\": \"name\", "
@@ -1799,7 +1766,7 @@
 
   // Invalid mimetype.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [{ \"name\": \"name\", "
@@ -1813,7 +1780,7 @@
 
   // Invalid mimetype.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [{ \"name\": \"name\", "
@@ -1827,7 +1794,7 @@
 
   // Accept field is empty.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"share_target\": { \"action\": \"https://foo.com/#\", \"method\": "
         "\"POST\", \"enctype\": \"multipart/form-data\", \"params\": "
         "{ \"title\": \"mytitle\", \"files\": [{ \"name\": \"name\", "
@@ -1841,7 +1808,7 @@
 
   // Accept sequence contains non-string elements.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{"
         "  \"share_target\": {"
         "    \"action\": \"https://foo.com/#\","
@@ -1857,12 +1824,11 @@
         "  }"
         "}",
         manifest_url, document_url);
-    const base::Optional<blink::Manifest::ShareTarget> share_target =
+    const base::Optional<Manifest::ShareTarget> share_target =
         manifest.share_target;
     EXPECT_TRUE(share_target.has_value());
 
-    const std::vector<blink::Manifest::FileFilter>& files =
-        share_target->params.files;
+    const std::vector<Manifest::FileFilter>& files = share_target->params.files;
     EXPECT_EQ(1u, files.size());
     EXPECT_TRUE(base::EqualsASCII(files.at(0).name, "name"));
 
@@ -1877,7 +1843,7 @@
 
   // Accept is just a single string.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{"
         "  \"share_target\": {"
         "    \"action\": \"https://foo.com/#\","
@@ -1893,12 +1859,11 @@
         "  }"
         "}",
         manifest_url, document_url);
-    const base::Optional<blink::Manifest::ShareTarget> share_target =
+    const base::Optional<Manifest::ShareTarget> share_target =
         manifest.share_target;
     EXPECT_TRUE(share_target.has_value());
 
-    const std::vector<blink::Manifest::FileFilter>& files =
-        share_target->params.files;
+    const std::vector<Manifest::FileFilter>& files = share_target->params.files;
     EXPECT_EQ(1u, files.size());
     EXPECT_TRUE(base::EqualsASCII(files.at(0).name, "name"));
 
@@ -1910,7 +1875,7 @@
 
   // Accept is neither a string nor an array of strings.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{"
         "  \"share_target\": {"
         "    \"action\": \"https://foo.com/#\","
@@ -1926,12 +1891,11 @@
         "  }"
         "}",
         manifest_url, document_url);
-    const base::Optional<blink::Manifest::ShareTarget> share_target =
+    const base::Optional<Manifest::ShareTarget> share_target =
         manifest.share_target;
     EXPECT_TRUE(share_target.has_value());
 
-    const std::vector<blink::Manifest::FileFilter>& files =
-        share_target->params.files;
+    const std::vector<Manifest::FileFilter>& files = share_target->params.files;
     EXPECT_EQ(0u, files.size());
 
     EXPECT_EQ(1u, GetErrorCount());
@@ -1941,7 +1905,7 @@
 
   // Files is just a single FileFilter (not an array).
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{"
         "  \"share_target\": {"
         "    \"action\": \"https://foo.com/#\","
@@ -1959,8 +1923,7 @@
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
 
-    const blink::Manifest::ShareTargetParams& params =
-        manifest.share_target->params;
+    const Manifest::ShareTargetParams& params = manifest.share_target->params;
     EXPECT_EQ(1u, params.files.size());
     EXPECT_TRUE(base::EqualsASCII(params.files.at(0).name, "name"));
 
@@ -1972,7 +1935,7 @@
 
   // Files is neither array nor FileFilter.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{"
         "  \"share_target\": {"
         "    \"action\": \"https://foo.com/#\","
@@ -1985,12 +1948,11 @@
         "  }"
         "}",
         manifest_url, document_url);
-    const base::Optional<blink::Manifest::ShareTarget> share_target =
+    const base::Optional<Manifest::ShareTarget> share_target =
         manifest.share_target;
     EXPECT_TRUE(share_target.has_value());
 
-    const std::vector<blink::Manifest::FileFilter>& files =
-        share_target->params.files;
+    const std::vector<Manifest::FileFilter>& files = share_target->params.files;
     EXPECT_EQ(0u, files.size());
 
     EXPECT_EQ(1u, GetErrorCount());
@@ -2000,7 +1962,7 @@
 
   // Files contains a non-dictionary entry.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{"
         "  \"share_target\": {"
         "    \"action\": \"https://foo.com/#\","
@@ -2019,12 +1981,11 @@
         "  }"
         "}",
         manifest_url, document_url);
-    const base::Optional<blink::Manifest::ShareTarget> share_target =
+    const base::Optional<Manifest::ShareTarget> share_target =
         manifest.share_target;
     EXPECT_TRUE(share_target.has_value());
 
-    const std::vector<blink::Manifest::FileFilter>& files =
-        share_target->params.files;
+    const std::vector<Manifest::FileFilter>& files = share_target->params.files;
     EXPECT_EQ(1u, files.size());
     EXPECT_TRUE(base::EqualsASCII(files.at(0).name, "name"));
 
@@ -2039,7 +2000,7 @@
 
   // Files contains empty file.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{"
         "  \"share_target\": {"
         "    \"action\": \"https://foo.com/#\","
@@ -2058,12 +2019,11 @@
         "  }"
         "}",
         manifest_url, document_url);
-    const base::Optional<blink::Manifest::ShareTarget> share_target =
+    const base::Optional<Manifest::ShareTarget> share_target =
         manifest.share_target;
     EXPECT_TRUE(share_target.has_value());
 
-    const std::vector<blink::Manifest::FileFilter>& files =
-        share_target->params.files;
+    const std::vector<Manifest::FileFilter>& files = share_target->params.files;
     EXPECT_EQ(1u, files.size());
     EXPECT_TRUE(base::EqualsASCII(files.at(0).name, "name"));
 
@@ -2079,7 +2039,7 @@
 TEST_F(ManifestParserTest, RelatedApplicationsParseRules) {
   // If no application, empty list.
   {
-    blink::Manifest manifest = ParseManifest("{ \"related_applications\": []}");
+    Manifest manifest = ParseManifest("{ \"related_applications\": []}");
     EXPECT_EQ(manifest.related_applications.size(), 0u);
     EXPECT_TRUE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
@@ -2087,8 +2047,7 @@
 
   // If empty application, empty list.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"related_applications\": [{}]}");
+    Manifest manifest = ParseManifest("{ \"related_applications\": [{}]}");
     EXPECT_EQ(manifest.related_applications.size(), 0u);
     EXPECT_TRUE(manifest.IsEmpty());
     EXPECT_EQ(1u, GetErrorCount());
@@ -2098,22 +2057,22 @@
 
   // If invalid platform, application is ignored.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"related_applications\": [{\"platform\": 123}]}");
     EXPECT_EQ(manifest.related_applications.size(), 0u);
     EXPECT_TRUE(manifest.IsEmpty());
     EXPECT_EQ(2u, GetErrorCount());
+    EXPECT_EQ("property 'platform' ignored, type string expected.",
+              errors()[0]);
     EXPECT_EQ(
-        "property 'platform' ignored, type string expected.",
-        errors()[0]);
-    EXPECT_EQ("'platform' is a required field, "
-              "related application ignored.",
-              errors()[1]);
+        "'platform' is a required field, "
+        "related application ignored.",
+        errors()[1]);
   }
 
   // If missing platform, application is ignored.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"related_applications\": [{\"id\": \"foo\"}]}");
     EXPECT_EQ(manifest.related_applications.size(), 0u);
     EXPECT_TRUE(manifest.IsEmpty());
@@ -2124,7 +2083,7 @@
 
   // If missing id and url, application is ignored.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"related_applications\": [{\"platform\": \"play\"}]}");
     EXPECT_EQ(manifest.related_applications.size(), 0u);
     EXPECT_TRUE(manifest.IsEmpty());
@@ -2135,13 +2094,12 @@
 
   // Valid application, with url.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"related_applications\": ["
         "{\"platform\": \"play\", \"url\": \"http://www.foo.com\"}]}");
     EXPECT_EQ(manifest.related_applications.size(), 1u);
     EXPECT_TRUE(base::EqualsASCII(
-        manifest.related_applications[0].platform.string(),
-        "play"));
+        manifest.related_applications[0].platform.string(), "play"));
     EXPECT_EQ(manifest.related_applications[0].url.spec(),
               "http://www.foo.com/");
     EXPECT_FALSE(manifest.IsEmpty());
@@ -2150,7 +2108,7 @@
 
   // Application with an invalid url.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"related_applications\": ["
         "{\"platform\": \"play\", \"url\": \"http://www.foo.com:co&uk\"}]}");
     EXPECT_TRUE(manifest.IsEmpty());
@@ -2162,36 +2120,33 @@
 
   // Valid application, with id.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"related_applications\": ["
         "{\"platform\": \"itunes\", \"id\": \"foo\"}]}");
     EXPECT_EQ(manifest.related_applications.size(), 1u);
     EXPECT_TRUE(base::EqualsASCII(
-        manifest.related_applications[0].platform.string(),
-        "itunes"));
-    EXPECT_TRUE(base::EqualsASCII(manifest.related_applications[0].id.string(),
-                                  "foo"));
+        manifest.related_applications[0].platform.string(), "itunes"));
+    EXPECT_TRUE(
+        base::EqualsASCII(manifest.related_applications[0].id.string(), "foo"));
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // All valid applications are in list.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"related_applications\": ["
         "{\"platform\": \"play\", \"id\": \"foo\"},"
         "{\"platform\": \"itunes\", \"id\": \"bar\"}]}");
     EXPECT_EQ(manifest.related_applications.size(), 2u);
     EXPECT_TRUE(base::EqualsASCII(
-        manifest.related_applications[0].platform.string(),
-        "play"));
-    EXPECT_TRUE(base::EqualsASCII(manifest.related_applications[0].id.string(),
-                                  "foo"));
+        manifest.related_applications[0].platform.string(), "play"));
+    EXPECT_TRUE(
+        base::EqualsASCII(manifest.related_applications[0].id.string(), "foo"));
     EXPECT_TRUE(base::EqualsASCII(
-        manifest.related_applications[1].platform.string(),
-        "itunes"));
-    EXPECT_TRUE(base::EqualsASCII(manifest.related_applications[1].id.string(),
-                                  "bar"));
+        manifest.related_applications[1].platform.string(), "itunes"));
+    EXPECT_TRUE(
+        base::EqualsASCII(manifest.related_applications[1].id.string(), "bar"));
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
   }
@@ -2199,17 +2154,16 @@
   // Two invalid applications and one valid. Only the valid application should
   // be in the list.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"related_applications\": ["
         "{\"platform\": \"itunes\"},"
         "{\"platform\": \"play\", \"id\": \"foo\"},"
         "{}]}");
     EXPECT_EQ(manifest.related_applications.size(), 1u);
     EXPECT_TRUE(base::EqualsASCII(
-        manifest.related_applications[0].platform.string(),
-        "play"));
-    EXPECT_TRUE(base::EqualsASCII(manifest.related_applications[0].id.string(),
-                                  "foo"));
+        manifest.related_applications[0].platform.string(), "play"));
+    EXPECT_TRUE(
+        base::EqualsASCII(manifest.related_applications[0].id.string(), "foo"));
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(2u, GetErrorCount());
     EXPECT_EQ("one of 'url' or 'id' is required, related application ignored.",
@@ -2222,7 +2176,7 @@
 TEST_F(ManifestParserTest, ParsePreferRelatedApplicationsParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"prefer_related_applications\": true }");
     EXPECT_TRUE(manifest.prefer_related_applications);
     EXPECT_EQ(0u, GetErrorCount());
@@ -2230,7 +2184,7 @@
 
   // Don't parse if the property isn't a boolean.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"prefer_related_applications\": {} }");
     EXPECT_FALSE(manifest.prefer_related_applications);
     EXPECT_EQ(1u, GetErrorCount());
@@ -2240,7 +2194,7 @@
         errors()[0]);
   }
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"prefer_related_applications\": \"true\" }");
     EXPECT_FALSE(manifest.prefer_related_applications);
     EXPECT_EQ(1u, GetErrorCount());
@@ -2250,8 +2204,7 @@
         errors()[0]);
   }
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"prefer_related_applications\": 1 }");
+    Manifest manifest = ParseManifest("{ \"prefer_related_applications\": 1 }");
     EXPECT_FALSE(manifest.prefer_related_applications);
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ(
@@ -2262,7 +2215,7 @@
 
   // "False" should set the boolean false without throwing errors.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"prefer_related_applications\": false }");
     EXPECT_FALSE(manifest.prefer_related_applications);
     EXPECT_EQ(0u, GetErrorCount());
@@ -2272,8 +2225,7 @@
 TEST_F(ManifestParserTest, ThemeColorParserRules) {
   // Smoke test.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"theme_color\": \"#FF0000\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"#FF0000\" }");
     EXPECT_EQ(*manifest.theme_color, 0xFFFF0000u);
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
@@ -2281,15 +2233,14 @@
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"theme_color\": \"  blue   \" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"  blue   \" }");
     EXPECT_EQ(*manifest.theme_color, 0xFF0000FFu);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Don't parse if theme_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": {} }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": {} }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'theme_color' ignored, type string expected.",
@@ -2298,7 +2249,7 @@
 
   // Don't parse if theme_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": false }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": false }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'theme_color' ignored, type string expected.",
@@ -2307,7 +2258,7 @@
 
   // Don't parse if theme_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": null }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": null }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'theme_color' ignored, type string expected.",
@@ -2316,7 +2267,7 @@
 
   // Don't parse if theme_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": [] }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": [] }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'theme_color' ignored, type string expected.",
@@ -2325,7 +2276,7 @@
 
   // Don't parse if theme_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": 42 }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": 42 }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'theme_color' ignored, type string expected.",
@@ -2334,18 +2285,18 @@
 
   // Parse fails if string is not in a known format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"theme_color\": \"foo(bar)\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"foo(bar)\" }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'theme_color' ignored,"
-              " 'foo(bar)' is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'theme_color' ignored,"
+        " 'foo(bar)' is not a valid color.",
+        errors()[0]);
   }
 
   // Parse fails if string is not in a known format.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": \"bleu\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"bleu\" }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'theme_color' ignored, 'bleu' is not a valid color.",
@@ -2354,76 +2305,76 @@
 
   // Parse fails if string is not in a known format.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": \"FF00FF\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"FF00FF\" }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'theme_color' ignored, 'FF00FF'"
-              " is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'theme_color' ignored, 'FF00FF'"
+        " is not a valid color.",
+        errors()[0]);
   }
 
   // Parse fails if multiple values for theme_color are given.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"theme_color\": \"#ABC #DEF\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"#ABC #DEF\" }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'theme_color' ignored, "
-              "'#ABC #DEF' is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'theme_color' ignored, "
+        "'#ABC #DEF' is not a valid color.",
+        errors()[0]);
   }
 
   // Parse fails if multiple values for theme_color are given.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"theme_color\": \"#AABBCC #DDEEFF\" }");
     EXPECT_FALSE(manifest.theme_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'theme_color' ignored, "
-              "'#AABBCC #DDEEFF' is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'theme_color' ignored, "
+        "'#AABBCC #DDEEFF' is not a valid color.",
+        errors()[0]);
   }
 
   // Accept CSS color keyword format.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": \"blue\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"blue\" }");
     EXPECT_EQ(*manifest.theme_color, 0xFF0000FFu);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept CSS color keyword format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"theme_color\": \"chartreuse\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"chartreuse\" }");
     EXPECT_EQ(*manifest.theme_color, 0xFF7FFF00u);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept CSS RGB format.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": \"#FFF\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"#FFF\" }");
     EXPECT_EQ(*manifest.theme_color, 0xFFFFFFFFu);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept CSS RGB format.
   {
-    blink::Manifest manifest = ParseManifest("{ \"theme_color\": \"#ABC\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"#ABC\" }");
     EXPECT_EQ(*manifest.theme_color, 0xFFAABBCCu);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept CSS RRGGBB format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"theme_color\": \"#FF0000\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"#FF0000\" }");
     EXPECT_EQ(*manifest.theme_color, 0xFFFF0000u);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept translucent colors.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"theme_color\": \"rgba(255,0,0,"
         "0.4)\" }");
     EXPECT_EQ(*manifest.theme_color, 0x66FF0000u);
@@ -2432,8 +2383,7 @@
 
   // Accept transparent colors.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"theme_color\": \"rgba(0,0,0,0)\" }");
+    Manifest manifest = ParseManifest("{ \"theme_color\": \"rgba(0,0,0,0)\" }");
     EXPECT_EQ(*manifest.theme_color, 0x00000000u);
     EXPECT_EQ(0u, GetErrorCount());
   }
@@ -2442,8 +2392,7 @@
 TEST_F(ManifestParserTest, BackgroundColorParserRules) {
   // Smoke test.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"background_color\": \"#FF0000\" }");
+    Manifest manifest = ParseManifest("{ \"background_color\": \"#FF0000\" }");
     EXPECT_EQ(*manifest.background_color, 0xFFFF0000u);
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
@@ -2451,7 +2400,7 @@
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"background_color\": \"  blue   \" }");
     EXPECT_EQ(*manifest.background_color, 0xFF0000FFu);
     EXPECT_EQ(0u, GetErrorCount());
@@ -2459,7 +2408,7 @@
 
   // Don't parse if background_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"background_color\": {} }");
+    Manifest manifest = ParseManifest("{ \"background_color\": {} }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'background_color' ignored, type string expected.",
@@ -2468,7 +2417,7 @@
 
   // Don't parse if background_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"background_color\": false }");
+    Manifest manifest = ParseManifest("{ \"background_color\": false }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'background_color' ignored, type string expected.",
@@ -2477,7 +2426,7 @@
 
   // Don't parse if background_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"background_color\": null }");
+    Manifest manifest = ParseManifest("{ \"background_color\": null }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'background_color' ignored, type string expected.",
@@ -2486,7 +2435,7 @@
 
   // Don't parse if background_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"background_color\": [] }");
+    Manifest manifest = ParseManifest("{ \"background_color\": [] }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'background_color' ignored, type string expected.",
@@ -2495,7 +2444,7 @@
 
   // Don't parse if background_color isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"background_color\": 42 }");
+    Manifest manifest = ParseManifest("{ \"background_color\": 42 }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'background_color' ignored, type string expected.",
@@ -2504,70 +2453,71 @@
 
   // Parse fails if string is not in a known format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"background_color\": \"foo(bar)\" }");
+    Manifest manifest = ParseManifest("{ \"background_color\": \"foo(bar)\" }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'background_color' ignored,"
-              " 'foo(bar)' is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'background_color' ignored,"
+        " 'foo(bar)' is not a valid color.",
+        errors()[0]);
   }
 
   // Parse fails if string is not in a known format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"background_color\": \"bleu\" }");
+    Manifest manifest = ParseManifest("{ \"background_color\": \"bleu\" }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'background_color' ignored,"
-              " 'bleu' is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'background_color' ignored,"
+        " 'bleu' is not a valid color.",
+        errors()[0]);
   }
 
   // Parse fails if string is not in a known format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"background_color\": \"FF00FF\" }");
+    Manifest manifest = ParseManifest("{ \"background_color\": \"FF00FF\" }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'background_color' ignored,"
-              " 'FF00FF' is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'background_color' ignored,"
+        " 'FF00FF' is not a valid color.",
+        errors()[0]);
   }
 
   // Parse fails if multiple values for background_color are given.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"background_color\": \"#ABC #DEF\" }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'background_color' ignored, "
-              "'#ABC #DEF' is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'background_color' ignored, "
+        "'#ABC #DEF' is not a valid color.",
+        errors()[0]);
   }
 
   // Parse fails if multiple values for background_color are given.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"background_color\": \"#AABBCC #DDEEFF\" }");
     EXPECT_FALSE(manifest.background_color.has_value());
     EXPECT_EQ(1u, GetErrorCount());
-    EXPECT_EQ("property 'background_color' ignored, "
-              "'#AABBCC #DDEEFF' is not a valid color.",
-              errors()[0]);
+    EXPECT_EQ(
+        "property 'background_color' ignored, "
+        "'#AABBCC #DDEEFF' is not a valid color.",
+        errors()[0]);
   }
 
   // Accept CSS color keyword format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"background_color\": \"blue\" }");
+    Manifest manifest = ParseManifest("{ \"background_color\": \"blue\" }");
     EXPECT_EQ(*manifest.background_color, 0xFF0000FFu);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept CSS color keyword format.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"background_color\": \"chartreuse\" }");
     EXPECT_EQ(*manifest.background_color, 0xFF7FFF00u);
     EXPECT_EQ(0u, GetErrorCount());
@@ -2575,31 +2525,28 @@
 
   // Accept CSS RGB format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"background_color\": \"#FFF\" }");
+    Manifest manifest = ParseManifest("{ \"background_color\": \"#FFF\" }");
     EXPECT_EQ(*manifest.background_color, 0xFFFFFFFFu);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept CSS RGB format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"background_color\": \"#ABC\" }");
+    Manifest manifest = ParseManifest("{ \"background_color\": \"#ABC\" }");
     EXPECT_EQ(*manifest.background_color, 0xFFAABBCCu);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept CSS RRGGBB format.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"background_color\": \"#FF0000\" }");
+    Manifest manifest = ParseManifest("{ \"background_color\": \"#FF0000\" }");
     EXPECT_EQ(*manifest.background_color, 0xFFFF0000u);
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Accept translucent colors.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"background_color\": \"rgba(255,0,0,"
         "0.4)\" }");
     EXPECT_EQ(*manifest.background_color, 0x66FF0000u);
@@ -2608,7 +2555,7 @@
 
   // Accept transparent colors.
   {
-    blink::Manifest manifest = ParseManifest(
+    Manifest manifest = ParseManifest(
         "{ \"background_color\": \"rgba(0,0,0,"
         "0)\" }");
     EXPECT_EQ(*manifest.background_color, 0x00000000u);
@@ -2619,7 +2566,7 @@
 TEST_F(ManifestParserTest, SplashScreenUrlParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"splash_screen_url\": \"splash.html\" }");
     ASSERT_EQ(manifest.splash_screen_url.spec(),
               default_document_url.Resolve("splash.html").spec());
@@ -2629,7 +2576,7 @@
 
   // Whitespaces.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"splash_screen_url\": \"    splash.html\" }");
     ASSERT_EQ(manifest.splash_screen_url.spec(),
               default_document_url.Resolve("splash.html").spec());
@@ -2638,7 +2585,7 @@
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"splash_screen_url\": {} }");
+    Manifest manifest = ParseManifest("{ \"splash_screen_url\": {} }");
     ASSERT_TRUE(manifest.splash_screen_url.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'splash_screen_url' ignored, type string expected.",
@@ -2647,7 +2594,7 @@
 
   // Don't parse if property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"splash_screen_url\": 42 }");
+    Manifest manifest = ParseManifest("{ \"splash_screen_url\": 42 }");
     ASSERT_TRUE(manifest.splash_screen_url.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'splash_screen_url' ignored, type string expected.",
@@ -2656,7 +2603,7 @@
 
   // Don't parse if property isn't a valid URL.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifest("{ \"splash_screen_url\": \"http://www.google.ca:a\" }");
     ASSERT_TRUE(manifest.splash_screen_url.is_empty());
     EXPECT_EQ(1u, GetErrorCount());
@@ -2666,7 +2613,7 @@
 
   // Absolute splash_screen_url, same origin with document.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"splash_screen_url\": \"http://foo.com/splash.html\" }",
         GURL("http://foo.com/manifest.json"),
         GURL("http://foo.com/index.html"));
@@ -2676,7 +2623,7 @@
 
   // Absolute splash_screen_url, cross origin with document.
   {
-    blink::Manifest manifest = ParseManifestWithURLs(
+    Manifest manifest = ParseManifestWithURLs(
         "{ \"splash_screen_url\": \"http://bar.com/splash.html\" }",
         GURL("http://foo.com/manifest.json"),
         GURL("http://foo.com/index.html"));
@@ -2690,7 +2637,7 @@
 
   // Resolving has to happen based on the manifest_url.
   {
-    blink::Manifest manifest =
+    Manifest manifest =
         ParseManifestWithURLs("{ \"splash_screen_url\": \"splash.html\" }",
                               GURL("http://foo.com/splashy/manifest.json"),
                               GURL("http://foo.com/index.html"));
@@ -2703,29 +2650,28 @@
 TEST_F(ManifestParserTest, GCMSenderIDParseRules) {
   // Smoke test.
   {
-    blink::Manifest manifest = ParseManifest("{ \"gcm_sender_id\": \"foo\" }");
+    Manifest manifest = ParseManifest("{ \"gcm_sender_id\": \"foo\" }");
     EXPECT_TRUE(base::EqualsASCII(manifest.gcm_sender_id.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Trim whitespaces.
   {
-    blink::Manifest manifest =
-        ParseManifest("{ \"gcm_sender_id\": \"  foo  \" }");
+    Manifest manifest = ParseManifest("{ \"gcm_sender_id\": \"  foo  \" }");
     EXPECT_TRUE(base::EqualsASCII(manifest.gcm_sender_id.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Don't parse if the property isn't a string.
   {
-    blink::Manifest manifest = ParseManifest("{ \"gcm_sender_id\": {} }");
+    Manifest manifest = ParseManifest("{ \"gcm_sender_id\": {} }");
     EXPECT_TRUE(manifest.gcm_sender_id.is_null());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'gcm_sender_id' ignored, type string expected.",
               errors()[0]);
   }
   {
-    blink::Manifest manifest = ParseManifest("{ \"gcm_sender_id\": 42 }");
+    Manifest manifest = ParseManifest("{ \"gcm_sender_id\": 42 }");
     EXPECT_TRUE(manifest.gcm_sender_id.is_null());
     EXPECT_EQ(1u, GetErrorCount());
     EXPECT_EQ("property 'gcm_sender_id' ignored, type string expected.",
@@ -2733,4 +2679,4 @@
   }
 }
 
-} // namespace content
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
index 9597eaa..4cacbec 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
@@ -284,8 +284,13 @@
   return channel()->negotiated();
 }
 
-uint16_t RTCDataChannel::id() const {
+uint16_t RTCDataChannel::id(bool& is_null) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (channel()->id() == -1) {
+    is_null = true;
+    return 0;
+  }
+  is_null = false;
   return channel()->id();
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
index c43ce09..90701053 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
@@ -76,7 +76,7 @@
   uint16_t maxRetransmits() const;
   String protocol() const;
   bool negotiated() const;
-  uint16_t id() const;
+  uint16_t id(bool& is_null) const;
   String readyState() const;
   unsigned bufferedAmount() const;
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.idl b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.idl
index b33b731..92e630b 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.idl
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.idl
@@ -46,7 +46,7 @@
     [Measure] readonly attribute unsigned short maxRetransmits;
     readonly attribute USVString protocol;
     readonly attribute boolean negotiated;
-    readonly attribute unsigned short id;
+    readonly attribute unsigned short? id;
     readonly attribute RTCDataChannelState readyState;
     readonly attribute unsigned long bufferedAmount;
              attribute unsigned long bufferedAmountLowThreshold;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
index 0fc44e3..5a4b478 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.h
@@ -33,7 +33,7 @@
                     RTCRtpSender*,
                     RTCRtpReceiver*);
 
-  // rtc_rtp_transciever.idl
+  // rtc_rtp_transceiver.idl
   String mid() const;
   RTCRtpSender* sender() const;
   RTCRtpReceiver* receiver() const;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 52a2c24..f78a6e4 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -238,7 +238,7 @@
   // Construct a ContentSecurityPolicy object to convert
   // ContentSecurityPolicyResponseHeaders to CSPHeaderAndType.
   // TODO(nhiroki): Find an efficient way to do this.
-  auto* content_security_policy = ContentSecurityPolicy::Create();
+  auto* content_security_policy = MakeGarbageCollected<ContentSecurityPolicy>();
   content_security_policy->DidReceiveHeaders(
       script_data->GetContentSecurityPolicyResponseHeaders());
 
diff --git a/third_party/blink/renderer/modules/vr/vr_get_devices_callback.h b/third_party/blink/renderer/modules/vr/vr_get_devices_callback.h
index ba133ce..84792920 100644
--- a/third_party/blink/renderer/modules/vr/vr_get_devices_callback.h
+++ b/third_party/blink/renderer/modules/vr/vr_get_devices_callback.h
@@ -6,7 +6,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_VR_VR_GET_DEVICES_CALLBACK_H_
 
 #include "device/vr/public/mojom/vr_service.mojom-blink.h"
-#include "third_party/blink/public/platform/web_callbacks.h"
 #include "third_party/blink/renderer/modules/vr/vr_display.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
@@ -15,16 +14,15 @@
 class ScriptPromiseResolver;
 
 // Success and failure callbacks for getDisplays.
-using WebVRGetDisplaysCallback = WebCallbacks<VRDisplayVector, void>;
-class VRGetDevicesCallback final : public WebVRGetDisplaysCallback {
+class VRGetDevicesCallback final {
   USING_FAST_MALLOC(VRGetDevicesCallback);
 
  public:
   VRGetDevicesCallback(ScriptPromiseResolver*);
-  ~VRGetDevicesCallback() override;
+  ~VRGetDevicesCallback();
 
-  void OnSuccess(VRDisplayVector) override;
-  void OnError() override;
+  void OnSuccess(VRDisplayVector);
+  void OnError();
 
  private:
   Persistent<ScriptPromiseResolver> resolver_;
diff --git a/third_party/blink/renderer/modules/webdatabase/database.cc b/third_party/blink/renderer/modules/webdatabase/database.cc
index 00d05f7..47fa3aa 100644
--- a/third_party/blink/renderer/modules/webdatabase/database.cc
+++ b/third_party/blink/renderer/modules/webdatabase/database.cc
@@ -229,15 +229,13 @@
       guid_(0),
       opened_(false),
       new_(false),
+      database_authorizer_(kInfoTableName),
       transaction_in_progress_(false),
       is_transaction_queue_enabled_(true) {
   DCHECK(IsMainThread());
   context_thread_security_origin_ =
       database_context_->GetSecurityOrigin()->IsolatedCopy();
 
-  database_authorizer_ =
-      DatabaseAuthorizer::Create(database_context, kInfoTableName);
-
   if (name_.IsNull())
     name_ = "";
 
@@ -273,8 +271,6 @@
 
 void Database::Trace(blink::Visitor* visitor) {
   visitor->Trace(database_context_);
-  visitor->Trace(sqlite_database_);
-  visitor->Trace(database_authorizer_);
   ScriptWrappable::Trace(visitor);
 }
 
@@ -585,8 +581,7 @@
     return false;
   }
 
-  DCHECK(database_authorizer_);
-  sqlite_database_.SetAuthorizer(database_authorizer_.Get());
+  sqlite_database_.SetAuthorizer(&database_authorizer_);
 
   // See comment at the top this file regarding calling addOpenDatabase().
   DatabaseTracker::Tracker().AddOpenDatabase(this);
@@ -631,7 +626,7 @@
   String query(String("SELECT value FROM ") + kInfoTableName +
                " WHERE key = '" + kVersionKey + "';");
 
-  database_authorizer_->Disable();
+  database_authorizer_.Disable();
 
   bool result =
       RetrieveTextResultFromDatabase(sqlite_database_, query, version);
@@ -643,7 +638,7 @@
                 << DatabaseDebugName();
   }
 
-  database_authorizer_->Enable();
+  database_authorizer_.Enable();
 
   return result;
 }
@@ -656,7 +651,7 @@
   String query(String("INSERT INTO ") + kInfoTableName +
                " (key, value) VALUES ('" + kVersionKey + "', ?);");
 
-  database_authorizer_->Disable();
+  database_authorizer_.Disable();
 
   bool result = SetTextValueInDatabase(sqlite_database_, query, version);
   if (result) {
@@ -667,7 +662,7 @@
                 << query << ")";
   }
 
-  database_authorizer_->Enable();
+  database_authorizer_.Enable();
 
   return result;
 }
@@ -696,43 +691,35 @@
 }
 
 void Database::DisableAuthorizer() {
-  DCHECK(database_authorizer_);
-  database_authorizer_->Disable();
+  database_authorizer_.Disable();
 }
 
 void Database::EnableAuthorizer() {
-  DCHECK(database_authorizer_);
-  database_authorizer_->Enable();
+  database_authorizer_.Enable();
 }
 
 void Database::SetAuthorizerPermissions(int permissions) {
-  DCHECK(database_authorizer_);
-  database_authorizer_->SetPermissions(permissions);
+  database_authorizer_.SetPermissions(permissions);
 }
 
 bool Database::LastActionChangedDatabase() {
-  DCHECK(database_authorizer_);
-  return database_authorizer_->LastActionChangedDatabase();
+  return database_authorizer_.LastActionChangedDatabase();
 }
 
 bool Database::LastActionWasInsert() {
-  DCHECK(database_authorizer_);
-  return database_authorizer_->LastActionWasInsert();
+  return database_authorizer_.LastActionWasInsert();
 }
 
 void Database::ResetDeletes() {
-  DCHECK(database_authorizer_);
-  database_authorizer_->ResetDeletes();
+  database_authorizer_.ResetDeletes();
 }
 
 bool Database::HadDeletes() {
-  DCHECK(database_authorizer_);
-  return database_authorizer_->HadDeletes();
+  return database_authorizer_.HadDeletes();
 }
 
 void Database::ResetAuthorizer() {
-  if (database_authorizer_)
-    database_authorizer_->Reset();
+  database_authorizer_.Reset();
 }
 
 uint64_t Database::MaximumSize() const {
diff --git a/third_party/blink/renderer/modules/webdatabase/database.h b/third_party/blink/renderer/modules/webdatabase/database.h
index 217580a..fb327b27 100644
--- a/third_party/blink/renderer/modules/webdatabase/database.h
+++ b/third_party/blink/renderer/modules/webdatabase/database.h
@@ -29,6 +29,7 @@
 #include <atomic>
 #include "base/single_thread_task_runner.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_database_callback.h"
+#include "third_party/blink/renderer/modules/webdatabase/database_authorizer.h"
 #include "third_party/blink/renderer/modules/webdatabase/database_basic_types.h"
 #include "third_party/blink/renderer/modules/webdatabase/database_error.h"
 #include "third_party/blink/renderer/modules/webdatabase/sql_transaction.h"
@@ -189,9 +190,9 @@
 
   bool new_;
 
+  DatabaseAuthorizer database_authorizer_;
   SQLiteDatabase sqlite_database_;
 
-  Member<DatabaseAuthorizer> database_authorizer_;
   Deque<CrossThreadPersistent<SQLTransactionBackend>> transaction_queue_;
   Mutex transaction_in_progress_mutex_;
   bool transaction_in_progress_;
diff --git a/third_party/blink/renderer/modules/webdatabase/database_authorizer.cc b/third_party/blink/renderer/modules/webdatabase/database_authorizer.cc
index b15f5a5..75140f4 100644
--- a/third_party/blink/renderer/modules/webdatabase/database_authorizer.cc
+++ b/third_party/blink/renderer/modules/webdatabase/database_authorizer.cc
@@ -29,7 +29,6 @@
 #include "third_party/blink/renderer/modules/webdatabase/database_authorizer.h"
 
 #include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/modules/webdatabase/database_context.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
@@ -37,23 +36,16 @@
 
 namespace blink {
 
-DatabaseAuthorizer* DatabaseAuthorizer::Create(
-    DatabaseContext* database_context,
-    const String& database_info_table_name) {
-  return MakeGarbageCollected<DatabaseAuthorizer>(database_context,
-                                                  database_info_table_name);
-}
-
-DatabaseAuthorizer::DatabaseAuthorizer(DatabaseContext* database_context,
-                                       const String& database_info_table_name)
+DatabaseAuthorizer::DatabaseAuthorizer(const String& database_info_table_name)
     : security_enabled_(false),
-      database_info_table_name_(database_info_table_name),
-      database_context_(database_context) {
+      database_info_table_name_(database_info_table_name) {
   DCHECK(IsMainThread());
 
   Reset();
 }
 
+DatabaseAuthorizer::~DatabaseAuthorizer() = default;
+
 void DatabaseAuthorizer::Reset() {
   last_action_was_insert_ = false;
   last_action_changed_database_ = false;
@@ -253,8 +245,6 @@
   if (!DeprecatedEqualIgnoringCase(module_name, "fts3"))
     return kSQLAuthDeny;
 
-  UseCounter::Count(database_context_->GetExecutionContext(),
-                    WebFeature::kWebDatabaseCreateDropFTS3Table);
   last_action_changed_database_ = true;
   return DenyBasedOnTableName(table_name);
 }
@@ -268,8 +258,6 @@
   if (!DeprecatedEqualIgnoringCase(module_name, "fts3"))
     return kSQLAuthDeny;
 
-  UseCounter::Count(database_context_->GetExecutionContext(),
-                    WebFeature::kWebDatabaseCreateDropFTS3Table);
   return UpdateDeletesBasedOnTableName(table_name);
 }
 
@@ -371,8 +359,4 @@
   return allow;
 }
 
-void DatabaseAuthorizer::Trace(blink::Visitor* visitor) {
-  visitor->Trace(database_context_);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webdatabase/database_authorizer.h b/third_party/blink/renderer/modules/webdatabase/database_authorizer.h
index 4af1926..d28c7a0 100644
--- a/third_party/blink/renderer/modules/webdatabase/database_authorizer.h
+++ b/third_party/blink/renderer/modules/webdatabase/database_authorizer.h
@@ -28,8 +28,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBDATABASE_DATABASE_AUTHORIZER_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBDATABASE_DATABASE_AUTHORIZER_H_
 
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
@@ -37,10 +36,9 @@
 extern const int kSQLAuthAllow;
 extern const int kSQLAuthDeny;
 
-class DatabaseContext;
+class DatabaseAuthorizer {
+  DISALLOW_NEW();
 
-class DatabaseAuthorizer
-    : public GarbageCollectedFinalized<DatabaseAuthorizer> {
  public:
   enum Permissions {
     kReadWriteMask = 0,
@@ -48,13 +46,8 @@
     kNoAccessMask = 1 << 2
   };
 
-  static DatabaseAuthorizer* Create(DatabaseContext*,
-                                    const String& database_info_table_name);
-
-  explicit DatabaseAuthorizer(DatabaseContext*,
-                              const String& database_info_table_name);
-
-  void Trace(blink::Visitor*);
+  explicit DatabaseAuthorizer(const String& database_info_table_name);
+  ~DatabaseAuthorizer();
 
   int CreateTable(const String& table_name);
   int CreateTempTable(const String& table_name);
@@ -119,8 +112,6 @@
   bool had_deletes_ : 1;
 
   const String database_info_table_name_;
-
-  Member<DatabaseContext> database_context_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
index 674ef3a8..34a88205 100644
--- a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
+++ b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
@@ -72,6 +72,11 @@
     return false;
   }
 
+  if (!db_) {
+    open_error_message_ = "sqlite_open returned null";
+    return false;
+  }
+
   open_error_ = sqlite3_extended_result_codes(db_, 1);
   if (open_error_ != SQLITE_OK) {
     open_error_message_ = sqlite3_errmsg(db_);
@@ -95,10 +100,7 @@
     return false;
   }
 
-  if (IsOpen())
-    opening_thread_ = CurrentThread();
-  else
-    open_error_message_ = "sqlite_open returned null";
+  opening_thread_ = CurrentThread();
 
   if (!SQLiteStatement(*this, "PRAGMA temp_store = MEMORY;").ExecuteCommand())
     DLOG(ERROR) << "SQLite database could not set temp_store to memory";
@@ -108,7 +110,7 @@
   if (!SQLiteStatement(*this, "PRAGMA foreign_keys = OFF;").ExecuteCommand())
     DLOG(ERROR) << "SQLite database could not turn off foreign_keys";
 
-  return IsOpen();
+  return true;
 }
 
 void SQLiteDatabase::Close() {
@@ -208,7 +210,7 @@
 }
 
 bool SQLiteDatabase::TableExists(const String& tablename) {
-  if (!IsOpen())
+  if (!db_)
     return false;
 
   String statement =
@@ -349,7 +351,7 @@
   return kSQLAuthDeny;
 }
 
-void SQLiteDatabase::SetAuthorizer(DatabaseAuthorizer* auth) {
+void SQLiteDatabase::SetAuthorizer(DatabaseAuthorizer* authorizer) {
   if (!db_) {
     NOTREACHED() << "Attempt to set an authorizer on a non-open SQL database";
     return;
@@ -357,17 +359,18 @@
 
   MutexLocker locker(authorizer_lock_);
 
-  authorizer_ = auth;
+  authorizer_ = authorizer;
 
   EnableAuthorizer(true);
 }
 
 void SQLiteDatabase::EnableAuthorizer(bool enable) {
-  if (authorizer_ && enable)
-    sqlite3_set_authorizer(db_, SQLiteDatabase::AuthorizerFunction,
-                           authorizer_.Get());
-  else
+  if (authorizer_ && enable) {
+    sqlite3_set_authorizer(db_, &SQLiteDatabase::AuthorizerFunction,
+                           authorizer_);
+  } else {
     sqlite3_set_authorizer(db_, nullptr, nullptr);
+  }
 }
 
 bool SQLiteDatabase::IsAutoCommitOn() const {
diff --git a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h
index b132901..a3bdd07 100644
--- a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h
+++ b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h
@@ -29,7 +29,7 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
@@ -58,7 +58,6 @@
   ~SQLiteDatabase();
 
   bool Open(const String& filename);
-  bool IsOpen() const { return db_; }
   void Close();
 
   void UpdateLastChangesCount();
@@ -102,6 +101,9 @@
 
   bool IsAutoCommitOn() const;
 
+  bool TurnOnIncrementalAutoVacuum();
+
+ private:
   // The SQLite AUTO_VACUUM pragma can be either NONE, FULL, or INCREMENTAL.
   // NONE - SQLite does not do any vacuuming
   // FULL - SQLite moves all empty pages to the end of the DB file and truncates
@@ -114,13 +116,9 @@
   enum AutoVacuumPragma {
     kAutoVacuumNone = 0,
     kAutoVacuumFull = 1,
-    kAutoVacuumIncremental = 2
+    kAutoVacuumIncremental = 2,
   };
-  bool TurnOnIncrementalAutoVacuum();
 
-  void Trace(blink::Visitor* visitor) {}
-
- private:
   static int AuthorizerFunction(void*,
                                 int,
                                 const char*,
@@ -138,7 +136,11 @@
   bool transaction_in_progress_;
 
   Mutex authorizer_lock_;
-  CrossThreadPersistent<DatabaseAuthorizer> authorizer_;
+
+  // The raw pointer usage is safe because the DatabaseAuthorizer is guaranteed
+  // to outlive this instance. The DatabaseAuthorizer is owned by the same
+  // Database that owns this instance.
+  DatabaseAuthorizer* authorizer_;
 
   base::PlatformThreadId opening_thread_;
 
diff --git a/third_party/blink/renderer/platform/geometry/layout_unit.h b/third_party/blink/renderer/platform/geometry/layout_unit.h
index ceae67c0..1cb5b143 100644
--- a/third_party/blink/renderer/platform/geometry/layout_unit.h
+++ b/third_party/blink/renderer/platform/geometry/layout_unit.h
@@ -31,17 +31,18 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LAYOUT_UNIT_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LAYOUT_UNIT_H_
 
+#include <climits>
 #include <iosfwd>
 #include <limits>
 
 #include "base/compiler_specific.h"
 #include "base/numerics/clamped_math.h"
 #include "base/numerics/safe_conversions.h"
+#include "build/build_config.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/saturated_arithmetic.h"
 
 namespace blink {
 
@@ -59,6 +60,30 @@
 const int kIntMaxForLayoutUnit = INT_MAX / kFixedPointDenominator;
 const int kIntMinForLayoutUnit = INT_MIN / kFixedPointDenominator;
 
+#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) && \
+    defined(COMPILER_GCC) && !defined(OS_NACL) && __OPTIMIZE__
+inline int GetMaxSaturatedSetResultForTesting() {
+  // For ARM Asm version the set function maxes out to the biggest
+  // possible integer part with the fractional part zero'd out.
+  // e.g. 0x7fffffc0.
+  return std::numeric_limits<int>::max() & ~(kFixedPointDenominator - 1);
+}
+
+inline int GetMinSaturatedSetResultForTesting() {
+  return std::numeric_limits<int>::min();
+}
+#else
+ALWAYS_INLINE int GetMaxSaturatedSetResultForTesting() {
+  // For C version the set function maxes out to max int, this differs from
+  // the ARM asm version.
+  return std::numeric_limits<int>::max();
+}
+
+ALWAYS_INLINE int GetMinSaturatedSetResultForTesting() {
+  return std::numeric_limits<int>::min();
+}
+#endif  // CPU(ARM) && COMPILER(GCC)
+
 // TODO(thakis): Remove these two lines once http://llvm.org/PR26504 is resolved
 class PLATFORM_EXPORT LayoutUnit;
 constexpr inline bool operator<(const LayoutUnit&, const LayoutUnit&);
@@ -71,9 +96,9 @@
   template <typename IntegerType>
   explicit LayoutUnit(IntegerType value) {
     if (std::is_signed<IntegerType>::value)
-      SetValue(static_cast<int>(value));
+      SaturatedSet(static_cast<int>(value));
     else
-      SetValue(static_cast<unsigned>(value));
+      SaturatedSet(static_cast<unsigned>(value));
   }
   explicit LayoutUnit(uint64_t value) {
     value_ = base::saturated_cast<int>(value * kFixedPointDenominator);
@@ -246,13 +271,78 @@
            std::numeric_limits<int>::max() / kFixedPointDenominator;
   }
 
-  ALWAYS_INLINE void SetValue(int value) {
-    value_ = SaturatedSet<kLayoutUnitFractionalBits>(value);
+#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) && \
+    defined(COMPILER_GCC) && !defined(OS_NACL) && __OPTIMIZE__
+  // If we're building ARM 32-bit on GCC we replace the C++ versions with some
+  // native ARM assembly for speed.
+  inline void SaturatedSet(int value) {
+    // Figure out how many bits are left for storing the integer part of
+    // the fixed point number, and saturate our input to that
+    enum { Saturate = 32 - kLayoutUnitFractionalBits };
+
+    int result;
+
+    // The following ARM code will Saturate the passed value to the number of
+    // bits used for the whole part of the fixed point representation, then
+    // shift it up into place. This will result in the low
+    // <kLayoutUnitFractionalBits> bits all being 0's. When the value saturates
+    // this gives a different result to from the C++ case; in the C++ code a
+    // saturated value has all the low bits set to 1 (for a +ve number at
+    // least). This cannot be done rapidly in ARM ... we live with the
+    // difference, for the sake of speed.
+
+    asm("ssat %[output],%[saturate],%[value]\n\t"
+        "lsl  %[output],%[shift]"
+        : [output] "=r"(result)
+        : [value] "r"(value), [saturate] "n"(Saturate),
+          [shift] "n"(kLayoutUnitFractionalBits));
+
+    value_ = result;
   }
 
-  inline void SetValue(unsigned value) {
-    value_ = SaturatedSet<kLayoutUnitFractionalBits>(value);
+  inline void SaturatedSet(unsigned value) {
+    // Here we are being passed an unsigned value to saturate,
+    // even though the result is returned as a signed integer. The ARM
+    // instruction for unsigned saturation therefore needs to be given one
+    // less bit (i.e. the sign bit) for the saturation to work correctly; hence
+    // the '31' below.
+    enum { Saturate = 31 - kLayoutUnitFractionalBits };
+
+    // The following ARM code will Saturate the passed value to the number of
+    // bits used for the whole part of the fixed point representation, then
+    // shift it up into place. This will result in the low
+    // <kLayoutUnitFractionalBits> bits all being 0's. When the value saturates
+    // this gives a different result to from the C++ case; in the C++ code a
+    // saturated value has all the low bits set to 1. This cannot be done
+    // rapidly in ARM, so we live with the difference, for the sake of speed.
+
+    int result;
+
+    asm("usat %[output],%[saturate],%[value]\n\t"
+        "lsl  %[output],%[shift]"
+        : [output] "=r"(result)
+        : [value] "r"(value), [saturate] "n"(Saturate),
+          [shift] "n"(kLayoutUnitFractionalBits));
+
+    value_ = result;
   }
+#else
+  ALWAYS_INLINE void SaturatedSet(int value) {
+    if (value > kIntMaxForLayoutUnit)
+      value_ = std::numeric_limits<int>::max();
+    else if (value < kIntMinForLayoutUnit)
+      value_ = std::numeric_limits<int>::min();
+    else
+      value_ = static_cast<unsigned>(value) << kLayoutUnitFractionalBits;
+  }
+
+  ALWAYS_INLINE void SaturatedSet(unsigned value) {
+    if (value >= (unsigned)kIntMaxForLayoutUnit)
+      value_ = std::numeric_limits<int>::max();
+    else
+      value_ = value << kLayoutUnitFractionalBits;
+  }
+#endif  // CPU(ARM) && COMPILER(GCC)
 
   int value_;
 };
diff --git a/third_party/blink/renderer/platform/geometry/layout_unit_test.cc b/third_party/blink/renderer/platform/geometry/layout_unit_test.cc
index 4a38137..db1fa1f61 100644
--- a/third_party/blink/renderer/platform/geometry/layout_unit_test.cc
+++ b/third_party/blink/renderer/platform/geometry/layout_unit_test.cc
@@ -62,6 +62,40 @@
   EXPECT_EQ(kIntMaxForLayoutUnit, LayoutUnit(kIntMaxForLayoutUnit + 1).ToInt());
   EXPECT_EQ(kIntMaxForLayoutUnit, LayoutUnit(INT_MAX / 2).ToInt());
   EXPECT_EQ(kIntMaxForLayoutUnit, LayoutUnit(INT_MAX).ToInt());
+
+  // Test the raw unsaturated value
+  EXPECT_EQ(0, LayoutUnit(0).RawValue());
+  // Internally the max number we can represent (without saturating)
+  // is all the (non-sign) bits set except for the bottom n fraction bits
+  const int max_internal_representation =
+      std::numeric_limits<int>::max() ^ ((1 << kLayoutUnitFractionalBits) - 1);
+  EXPECT_EQ(max_internal_representation,
+            LayoutUnit(kIntMaxForLayoutUnit).RawValue());
+  EXPECT_EQ(GetMaxSaturatedSetResultForTesting(),
+            LayoutUnit(kIntMaxForLayoutUnit + 100).RawValue());
+  EXPECT_EQ((kIntMaxForLayoutUnit - 100) << kLayoutUnitFractionalBits,
+            LayoutUnit(kIntMaxForLayoutUnit - 100).RawValue());
+  EXPECT_EQ(GetMinSaturatedSetResultForTesting(),
+            LayoutUnit(kIntMinForLayoutUnit).RawValue());
+  EXPECT_EQ(GetMinSaturatedSetResultForTesting(),
+            LayoutUnit(kIntMinForLayoutUnit - 100).RawValue());
+  // Shifting negative numbers left has undefined behavior, so use
+  // multiplication instead of direct shifting here.
+  EXPECT_EQ((kIntMinForLayoutUnit + 100) * (1 << kLayoutUnitFractionalBits),
+            LayoutUnit(kIntMinForLayoutUnit + 100).RawValue());
+}
+
+TEST(LayoutUnitTest, LayoutUnitUnsigned) {
+  // Test the raw unsaturated value
+  EXPECT_EQ(0, LayoutUnit((unsigned)0).RawValue());
+  EXPECT_EQ(GetMaxSaturatedSetResultForTesting(),
+            LayoutUnit((unsigned)kIntMaxForLayoutUnit).RawValue());
+  const unsigned kOverflowed = kIntMaxForLayoutUnit + 100;
+  EXPECT_EQ(GetMaxSaturatedSetResultForTesting(),
+            LayoutUnit(kOverflowed).RawValue());
+  const unsigned kNotOverflowed = kIntMaxForLayoutUnit - 100;
+  EXPECT_EQ((kIntMaxForLayoutUnit - 100) << kLayoutUnitFractionalBits,
+            LayoutUnit(kNotOverflowed).RawValue());
 }
 
 TEST(LayoutUnitTest, LayoutUnitFloat) {
diff --git a/third_party/blink/renderer/platform/graphics/paint/display_item_list.h b/third_party/blink/renderer/platform/graphics/paint/display_item_list.h
index c6c87fb3..a8189d4 100644
--- a/third_party/blink/renderer/platform/graphics/paint/display_item_list.h
+++ b/third_party/blink/renderer/platform/graphics/paint/display_item_list.h
@@ -44,11 +44,16 @@
     // on item which replaces it with a tombstone/"dead display item" that
     // can be safely destructed but should never be used except for debugging.
     DCHECK(item.IsTombstone());
-    DCHECK(item.GetId() == result.GetId());
     // We need |visual_rect_| and |outset_for_raster_effects_| of the old
-    // display item for raster invalidation. As their values were initialized
-    // to default values in DisplayItem's default constructor, now copy their
-    // original values back from |result|.
+    // display item for raster invalidation. Also, the fields that make up the
+    // ID (|client_|, |type_| and |fragment_|) need to match. As their values
+    // were either initialized to default values or were left uninitialized by
+    // DisplayItem's default constructor, now copy their original values back
+    // from |result|.
+    item.client_ = result.client_;
+    item.type_ = result.type_;
+    item.fragment_ = result.fragment_;
+    DCHECK(item.GetId() == result.GetId());
     item.visual_rect_ = result.visual_rect_;
     item.outset_for_raster_effects_ = result.outset_for_raster_effects_;
     return result;
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.cc b/third_party/blink/renderer/platform/heap/heap_compact.cc
index 3b18dd177..cd16fd7 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact.cc
+++ b/third_party/blink/renderer/platform/heap/heap_compact.cc
@@ -381,11 +381,13 @@
 
   if (reason != BlinkGC::GCReason::kIdleGC &&
       reason != BlinkGC::GCReason::kPreciseGC &&
-      reason != BlinkGC::GCReason::kForcedGC &&
-      reason != BlinkGC::GCReason::kIncrementalIdleGC &&
-      reason != BlinkGC::GCReason::kUnifiedHeapGC)
+      reason != BlinkGC::GCReason::kForcedGC)
     return false;
 
+  // TODO(keishi): crbug.com/918064 Heap compaction for incremental marking
+  // needs to be disabled until this crash is fixed.
+  CHECK_NE(marking_type, BlinkGC::kIncrementalMarking);
+
   // Compaction enable rules:
   //  - It's been a while since the last time.
   //  - "Considerable" amount of heap memory is bound up in freelist
diff --git a/third_party/blink/renderer/platform/image-decoders/DEPS b/third_party/blink/renderer/platform/image-decoders/DEPS
index f7f523f2..c6ae663 100644
--- a/third_party/blink/renderer/platform/image-decoders/DEPS
+++ b/third_party/blink/renderer/platform/image-decoders/DEPS
@@ -19,7 +19,7 @@
 
 specific_include_rules = {
     'image_decoder_base_test\.cc': [
-        "+base/md5.h",
+        "+base/hash/md5.h",
         "+base/path_service.h",
         "+base/strings/utf_string_conversions.h",
     ],
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.cc
index 810ea43..6eb4223 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder_base_test.cc
@@ -11,7 +11,7 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/md5.h"
+#include "base/hash/md5.h"
 #include "base/path_service.h"
 #include "base/strings/pattern.h"
 #include "base/strings/string_util.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
index b79df9c..4b4e536 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
@@ -4,7 +4,10 @@
 
 #include "third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h"
 
+#include <algorithm>
 #include <memory>
+#include <string>
+
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram.h"
 #include "base/numerics/safe_conversions.h"
@@ -747,7 +750,7 @@
       "Some resource load requests were throttled while the tab was in "
       "background, and no request was sent from the queue in the last 1 "
       "minute. This means previously requested in-flight requests haven't "
-      "received any response from servers. See"
+      "received any response from servers. See "
       "https://www.chromestatus.com/feature/5527160148197376 for more details");
   is_console_info_shown_ = true;
 }
diff --git a/third_party/blink/renderer/platform/wtf/BUILD.gn b/third_party/blink/renderer/platform/wtf/BUILD.gn
index a4d51f2..59cc04ea 100644
--- a/third_party/blink/renderer/platform/wtf/BUILD.gn
+++ b/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -107,8 +107,6 @@
     "ref_counted.h",
     "ref_vector.h",
     "sanitizers.h",
-    "saturated_arithmetic.h",
-    "saturated_arithmetic_arm.h",
     "scoped_logger.cc",
     "scoped_logger.h",
     "size_assertions.h",
@@ -309,7 +307,6 @@
     "pod_red_black_tree_test.cc",
     "pod_tree_test_helpers.cc",
     "pod_tree_test_helpers.h",
-    "saturated_arithmetic_test.cc",
     "scoped_logger_test.cc",
     "string_hasher_test.cc",
     "testing/run_all_tests.cc",
diff --git a/third_party/blink/renderer/platform/wtf/math_extras_test.cc b/third_party/blink/renderer/platform/wtf/math_extras_test.cc
index bb0be6a3..4b796ca1 100644
--- a/third_party/blink/renderer/platform/wtf/math_extras_test.cc
+++ b/third_party/blink/renderer/platform/wtf/math_extras_test.cc
@@ -51,26 +51,7 @@
   }
 }
 
-TEST(MathExtrasTest, clampToIntLong) {
-  if (sizeof(long) == sizeof(int))
-    return;
-
-  long max_int = std::numeric_limits<int>::max();
-  long min_int = std::numeric_limits<int>::min();
-  long overflow_int = max_int + 1;
-  long underflow_int = min_int - 1;
-
-  EXPECT_GT(overflow_int, max_int);
-  EXPECT_LT(underflow_int, min_int);
-
-  EXPECT_EQ(max_int, clampTo<int>(max_int));
-  EXPECT_EQ(min_int, clampTo<int>(min_int));
-
-  EXPECT_EQ(max_int, clampTo<int>(overflow_int));
-  EXPECT_EQ(min_int, clampTo<int>(underflow_int));
-}
-
-TEST(MathExtrasTest, clampToIntLongLong) {
+TEST(MathExtrasTest, clampToIntInt64) {
   int64_t max_int = std::numeric_limits<int>::max();
   int64_t min_int = std::numeric_limits<int>::min();
   int64_t overflow_int = max_int + 1;
@@ -162,7 +143,7 @@
             clampTo<double>(std::numeric_limits<uint64_t>::max(), 0.0, 3.5));
 }
 
-TEST(MathExtrasText, clampToLongLongDouble) {
+TEST(MathExtrasText, clampToInt64Double) {
   double overflow_ll =
       static_cast<double>(std::numeric_limits<int64_t>::max()) * 2;
   EXPECT_EQ(std::numeric_limits<int64_t>::max(), clampTo<int64_t>(overflow_ll));
@@ -170,7 +151,7 @@
             clampTo<int64_t>(-overflow_ll));
 }
 
-TEST(MathExtrasText, clampToUnsignedLongLongDouble) {
+TEST(MathExtrasText, clampToUint64Double) {
   double overflow_ull =
       static_cast<double>(std::numeric_limits<uint64_t>::max()) * 2;
   EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
@@ -206,27 +187,27 @@
   EXPECT_EQ(0u, clampTo<unsigned>(-1));
 }
 
-TEST(MathExtrasTest, clampToLongLongUnsignedLongLong) {
-  int64_t max_long_long_ll = std::numeric_limits<int64_t>::max();
-  uint64_t max_long_long_ull = max_long_long_ll;
-  uint64_t overflow_long_long = max_long_long_ull + 1;
+TEST(MathExtrasTest, clampToInt64Uint64) {
+  int64_t max_int64 = std::numeric_limits<int64_t>::max();
+  uint64_t max_uint64 = max_int64;
+  uint64_t overflow_int64 = max_uint64 + 1;
 
-  EXPECT_GT(overflow_long_long, max_long_long_ull);
+  EXPECT_GT(overflow_int64, max_uint64);
 
-  EXPECT_EQ(max_long_long_ll, clampTo<int64_t>(max_long_long_ull));
-  EXPECT_EQ(max_long_long_ll - 1, clampTo<int64_t>(max_long_long_ull - 1));
-  EXPECT_EQ(max_long_long_ll, clampTo<int64_t>(overflow_long_long));
+  EXPECT_EQ(max_int64, clampTo<int64_t>(max_uint64));
+  EXPECT_EQ(max_int64 - 1, clampTo<int64_t>(max_uint64 - 1));
+  EXPECT_EQ(max_int64, clampTo<int64_t>(overflow_int64));
 
   EXPECT_EQ(-3LL, clampTo<int64_t>(2ULL, -5LL, -3LL));
 }
 
-TEST(MathExtrasTest, clampToUnsignedLongLongInt) {
+TEST(MathExtrasTest, clampToUint64Int) {
   EXPECT_EQ(0ULL, clampTo<uint64_t>(-1));
   EXPECT_EQ(0ULL, clampTo<uint64_t>(0));
   EXPECT_EQ(1ULL, clampTo<uint64_t>(1));
 }
 
-TEST(MathExtrasTest, clampToUnsignedLongLongUnsignedLongLong) {
+TEST(MathExtrasTest, clampToUint64Uint64) {
   EXPECT_EQ(0ULL, clampTo<uint64_t>(0ULL));
   EXPECT_EQ(1ULL, clampTo<uint64_t>(0ULL, 1ULL, 2ULL));
   EXPECT_EQ(2ULL, clampTo<uint64_t>(3ULL, 1ULL, 2ULL));
diff --git a/third_party/blink/renderer/platform/wtf/saturated_arithmetic.h b/third_party/blink/renderer/platform/wtf/saturated_arithmetic.h
deleted file mode 100644
index 171b6178..0000000
--- a/third_party/blink/renderer/platform/wtf/saturated_arithmetic.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2012, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_SATURATED_ARITHMETIC_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_SATURATED_ARITHMETIC_H_
-
-#include "base/compiler_specific.h"
-#include "build/build_config.h"
-
-#include <stdint.h>
-
-#include <limits>
-
-#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) && \
-    defined(COMPILER_GCC) && !defined(OS_NACL) && __OPTIMIZE__
-
-// If we're building ARM 32-bit on GCC we replace the C++ versions with some
-// native ARM assembly for speed.
-#include "third_party/blink/renderer/platform/wtf/saturated_arithmetic_arm.h"
-
-#else
-
-namespace WTF {
-
-ALWAYS_INLINE int GetMaxSaturatedSetResultForTesting(int fractional_shift) {
-  // For C version the set function maxes out to max int, this differs from
-  // the ARM asm version, see saturated_arithmetic_arm.h for the equivalent asm
-  // version.
-  return std::numeric_limits<int>::max();
-}
-
-ALWAYS_INLINE int GetMinSaturatedSetResultForTesting(int fractional_shift) {
-  return std::numeric_limits<int>::min();
-}
-
-template <int fractional_shift>
-ALWAYS_INLINE int SaturatedSet(int value) {
-  const int kIntMaxForLayoutUnit =
-      std::numeric_limits<int>::max() >> fractional_shift;
-
-  const int kIntMinForLayoutUnit =
-      std::numeric_limits<int>::min() >> fractional_shift;
-
-  if (value > kIntMaxForLayoutUnit)
-    return std::numeric_limits<int>::max();
-
-  if (value < kIntMinForLayoutUnit)
-    return std::numeric_limits<int>::min();
-
-  return static_cast<unsigned>(value) << fractional_shift;
-}
-
-template <int fractional_shift>
-ALWAYS_INLINE int SaturatedSet(unsigned value) {
-  const unsigned kIntMaxForLayoutUnit =
-      std::numeric_limits<int>::max() >> fractional_shift;
-
-  if (value >= kIntMaxForLayoutUnit)
-    return std::numeric_limits<int>::max();
-
-  return value << fractional_shift;
-}
-
-}  // namespace WTF.
-
-#endif  // CPU(ARM) && COMPILER(GCC)
-
-using WTF::SaturatedSet;
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_SATURATED_ARITHMETIC_H_
diff --git a/third_party/blink/renderer/platform/wtf/saturated_arithmetic_arm.h b/third_party/blink/renderer/platform/wtf/saturated_arithmetic_arm.h
deleted file mode 100644
index c6f172be..0000000
--- a/third_party/blink/renderer/platform/wtf/saturated_arithmetic_arm.h
+++ /dev/null
@@ -1,78 +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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_SATURATED_ARITHMETIC_ARM_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_SATURATED_ARITHMETIC_ARM_H_
-
-#include <limits>
-
-namespace WTF {
-
-inline int GetMaxSaturatedSetResultForTesting(int fractional_shift) {
-  // For ARM Asm version the set function maxes out to the biggest
-  // possible integer part with the fractional part zero'd out.
-  // e.g. 0x7fffffc0.
-  return std::numeric_limits<int>::max() & ~((1 << fractional_shift) - 1);
-}
-
-inline int GetMinSaturatedSetResultForTesting(int fractional_shift) {
-  return std::numeric_limits<int>::min();
-}
-
-template <int fractional_shift>
-inline int SaturatedSet(int value) {
-  // Figure out how many bits are left for storing the integer part of
-  // the fixed point number, and saturate our input to that
-  enum { Saturate = 32 - fractional_shift };
-
-  int result;
-
-  // The following ARM code will Saturate the passed value to the number of
-  // bits used for the whole part of the fixed point representation, then
-  // shift it up into place. This will result in the low <FractionShift> bits
-  // all being 0's. When the value saturates this gives a different result
-  // to from the C++ case; in the C++ code a saturated value has all the low
-  // bits set to 1 (for a +ve number at least). This cannot be done rapidly
-  // in ARM ... we live with the difference, for the sake of speed.
-
-  asm("ssat %[output],%[saturate],%[value]\n\t"
-      "lsl  %[output],%[shift]"
-      : [output] "=r"(result)
-      : [value] "r"(value), [saturate] "n"(Saturate),
-        [shift] "n"(fractional_shift));
-
-  return result;
-}
-
-template <int fractional_shift>
-inline int SaturatedSet(unsigned value) {
-  // Here we are being passed an unsigned value to saturate,
-  // even though the result is returned as a signed integer. The ARM
-  // instruction for unsigned saturation therefore needs to be given one
-  // less bit (i.e. the sign bit) for the saturation to work correctly; hence
-  // the '31' below.
-  enum { Saturate = 31 - fractional_shift };
-
-  // The following ARM code will Saturate the passed value to the number of
-  // bits used for the whole part of the fixed point representation, then
-  // shift it up into place. This will result in the low <FractionShift> bits
-  // all being 0's. When the value saturates this gives a different result
-  // to from the C++ case; in the C++ code a saturated value has all the low
-  // bits set to 1. This cannot be done rapidly in ARM, so we live with the
-  // difference, for the sake of speed.
-
-  int result;
-
-  asm("usat %[output],%[saturate],%[value]\n\t"
-      "lsl  %[output],%[shift]"
-      : [output] "=r"(result)
-      : [value] "r"(value), [saturate] "n"(Saturate),
-        [shift] "n"(fractional_shift));
-
-  return result;
-}
-
-}  // namespace WTF
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_SATURATED_ARITHMETIC_ARM_H_
diff --git a/third_party/blink/renderer/platform/wtf/saturated_arithmetic_test.cc b/third_party/blink/renderer/platform/wtf/saturated_arithmetic_test.cc
deleted file mode 100644
index 0933021..0000000
--- a/third_party/blink/renderer/platform/wtf/saturated_arithmetic_test.cc
+++ /dev/null
@@ -1,69 +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 <limits>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/wtf/saturated_arithmetic.h"
-
-namespace WTF {
-
-TEST(SaturatedArithmeticTest, SetSigned) {
-  int int_max = std::numeric_limits<int>::max();
-  int int_min = std::numeric_limits<int>::min();
-
-  const int kFractionBits = 6;
-  const int kIntMaxForLayoutUnit = int_max >> kFractionBits;
-  const int kIntMinForLayoutUnit = int_min >> kFractionBits;
-
-  EXPECT_EQ(0, SaturatedSet<kFractionBits>(0));
-
-  // Internally the max number we can represent (without saturating)
-  // is all the (non-sign) bits set except for the bottom n fraction bits
-  const int max_internal_representation = int_max ^ ((1 << kFractionBits) - 1);
-  EXPECT_EQ(max_internal_representation,
-            SaturatedSet<kFractionBits>(kIntMaxForLayoutUnit));
-
-  EXPECT_EQ(GetMaxSaturatedSetResultForTesting(kFractionBits),
-            SaturatedSet<kFractionBits>(kIntMaxForLayoutUnit + 100));
-
-  EXPECT_EQ((kIntMaxForLayoutUnit - 100) << kFractionBits,
-            SaturatedSet<kFractionBits>(kIntMaxForLayoutUnit - 100));
-
-  EXPECT_EQ(GetMinSaturatedSetResultForTesting(kFractionBits),
-            SaturatedSet<kFractionBits>(kIntMinForLayoutUnit));
-
-  EXPECT_EQ(GetMinSaturatedSetResultForTesting(kFractionBits),
-            SaturatedSet<kFractionBits>(kIntMinForLayoutUnit - 100));
-
-  // Shifting negative numbers left has undefined behavior, so use
-  // multiplication instead of direct shifting here.
-  EXPECT_EQ((kIntMinForLayoutUnit + 100) * (1 << kFractionBits),
-            SaturatedSet<kFractionBits>(kIntMinForLayoutUnit + 100));
-}
-
-TEST(SaturatedArithmeticTest, SetUnsigned) {
-  int int_max = std::numeric_limits<int>::max();
-
-  const int kFractionBits = 6;
-  const int kIntMaxForLayoutUnit = int_max >> kFractionBits;
-
-  EXPECT_EQ(0, SaturatedSet<kFractionBits>((unsigned)0));
-
-  EXPECT_EQ(GetMaxSaturatedSetResultForTesting(kFractionBits),
-            SaturatedSet<kFractionBits>((unsigned)kIntMaxForLayoutUnit));
-
-  const unsigned kOverflowed = kIntMaxForLayoutUnit + 100;
-  EXPECT_EQ(GetMaxSaturatedSetResultForTesting(kFractionBits),
-            SaturatedSet<kFractionBits>(kOverflowed));
-
-  const unsigned kNotOverflowed = kIntMaxForLayoutUnit - 100;
-  EXPECT_EQ((kIntMaxForLayoutUnit - 100) << kFractionBits,
-            SaturatedSet<kFractionBits>(kNotOverflowed));
-}
-
-}  // namespace WTF
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index ed51969..4a9876e7 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -647,6 +647,22 @@
             'base::OnTaskRunnerDeleter',
             'sigslot::.+',
         ],
+    },
+    # TODO(https://crbug.com/704441) : Added temporarily.
+    {
+        'paths': ['third_party/blink/renderer/modules/exported/web_manifest_parser.cc'],
+        'allowed': [
+            'base::StringPiece',
+            'GURL',
+        ],
+    },
+    {
+        'paths': ['third_party/blink/renderer/modules/manifest/'],
+        'allowed': [
+            'base::.+',
+            'net::ParseMimeTypeWithoutParameter',
+            'GURL',
+        ],
     }
 ]
 
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index fdf12cb9..71425315 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -88,7 +88,6 @@
 crbug.com/922437 external/wpt/css/css-text/word-break/word-break-break-all-013.html [ Skip ]
 
 # New failures are appended below by the script.
-crbug.com/591099 accessibility/spelling-markers.html [ Failure Pass ]
 crbug.com/591099 bluetooth/server/getPrimaryService/gen-reconnect-during-error.html [ Pass ]
 crbug.com/591099 compositing/animation/busy-indicator.html [ Pass ]
 crbug.com/591099 compositing/scrollbars/nested-overlay-scrollbars.html [ Failure ]
@@ -206,7 +205,6 @@
 crbug.com/40634 external/wpt/css/css-text/white-space/trailing-space-before-br-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-transforms/transform-box/view-box-mutation.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-transitions/properties-value-003.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-ui/text-overflow-010.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-ui/text-overflow-026.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-values/attr-invalid-type-008.html [ Failure ]
@@ -307,6 +305,7 @@
 crbug.com/591099 external/wpt/css/cssom-view/elementsFromPoint-inline-vrl-ltr.html [ Pass ]
 crbug.com/591099 external/wpt/css/cssom-view/elementsFromPoint-inline-vrl-rtl.html [ Pass ]
 crbug.com/591099 external/wpt/css/cssom-view/offsetTopLeftInline.html [ Pass ]
+crbug.com/591099 external/wpt/css/filter-effects/css-filters-animation-opacity.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-align-self-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-align-self-vertWM-003.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-justify-content-003.html [ Failure ]
@@ -349,7 +348,7 @@
 crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
 crbug.com/591099 external/wpt/fullscreen/api/element-ready-check-containing-iframe-manual.html [ Pass ]
 crbug.com/591099 external/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual.html [ Failure Pass ]
-crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Crash ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_parent [ Pass ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_top [ Pass ]
@@ -368,9 +367,9 @@
 crbug.com/591099 external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Pass ]
 crbug.com/591099 external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Pass ]
 crbug.com/591099 external/wpt/referrer-policy/same-origin/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/same-origin-insecure.http.html [ Failure ]
-crbug.com/591099 external/wpt/screen-orientation/onchange-event.html [ Failure Timeout ]
+crbug.com/591099 external/wpt/screen-orientation/onchange-event.html [ Failure ]
 crbug.com/591099 external/wpt/svg/text/reftests/text-inline-size-101.svg [ Failure ]
-crbug.com/591099 external/wpt/wasm/webapi/rejected-arg.any.serviceworker.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/wasm/webapi/rejected-arg.any.serviceworker.html [ Pass ]
 crbug.com/591099 external/wpt/webauthn/createcredential-extensions.https.html [ Pass ]
 crbug.com/591099 external/wpt/webmessaging/without-ports/001.html [ Failure ]
 crbug.com/591099 external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html [ Pass ]
@@ -400,7 +399,6 @@
 crbug.com/591099 fast/block/float/4145535Crash.html [ Pass ]
 crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
 crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ]
-crbug.com/591099 fast/css-grid-layout/grid-baseline.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-css-tables-collapsed.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-tables.html [ Failure Pass ]
@@ -411,7 +409,7 @@
 crbug.com/591099 fast/dom/SelectorAPI/resig-SelectorsAPI-test.xhtml [ Pass ]
 crbug.com/591099 fast/dom/shadow/focus-controller-recursion-crash.html [ Pass ]
 crbug.com/591099 fast/dom/shadow/svg-style-in-shadow-tree-crash.html [ Pass ]
-crbug.com/591099 fast/events/before-unload-return-value-from-listener.html [ Pass Timeout ]
+crbug.com/591099 fast/events/before-unload-return-value-from-listener.html [ Pass ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
@@ -436,7 +434,7 @@
 crbug.com/591099 http/tests/devtools/elements/shadow/shadow-distribution.js [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/styles-1/edit-value-url-with-color.js [ Pass ]
 crbug.com/591099 http/tests/devtools/elements/user-properties.js [ Pass ]
-crbug.com/591099 http/tests/devtools/service-workers/service-worker-v8-cache.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/service-workers/service-worker-v8-cache.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Pass ]
 crbug.com/591099 http/tests/devtools/tracing-session-id.js [ Pass ]
@@ -456,6 +454,7 @@
 crbug.com/591099 http/tests/media/autoplay/document-user-activation-cross-origin-feature-policy-disabled.html [ Failure Pass ]
 crbug.com/591099 http/tests/media/video-load-metadata-decode-error.html [ Pass ]
 crbug.com/591099 http/tests/multipart/multipart-main-resource.html [ Pass ]
+crbug.com/591099 http/tests/security/inactive-document-with-empty-security-origin.html [ Pass ]
 crbug.com/591099 http/tests/security/isolatedWorld/media-query-wrapper-leaks.html [ Failure ]
 crbug.com/591099 http/tests/security/upgrade-insecure-requests/iframe-upgrade.https.html [ Crash ]
 crbug.com/591099 http/tests/security/video-poster-cross-origin-crash2.html [ Pass ]
@@ -492,8 +491,8 @@
 crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_05_rtl_multi_line.html [ Failure ]
 crbug.com/591099 virtual/binary-for-devtools/http/tests/devtools/elements/highlight/highlight-css-grid.js [ Failure ]
 crbug.com/591099 virtual/binary-for-devtools/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js [ Crash Pass ]
-crbug.com/591099 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/fetch/fetch-basic.js [ Pass Timeout ]
-crbug.com/591099 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/fetch/fetch-renderer.js [ Pass Timeout ]
+crbug.com/591099 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/fetch/fetch-basic.js [ Pass ]
+crbug.com/591099 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/fetch/fetch-renderer.js [ Pass ]
 crbug.com/591099 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/interception-multiclient.js [ Pass ]
 crbug.com/916511 virtual/composite-after-paint/paint/background/scrolling-background-with-negative-z-child.html [ Crash ]
 crbug.com/591099 virtual/composite-after-paint/paint/invalidation/box/margin.html [ Failure Pass ]
@@ -510,7 +509,7 @@
 crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/fractional-scroll-offset-fixed-position-non-composited.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Pass ]
 crbug.com/591099 virtual/gpu-rasterization/images/image-page-injected-script-crash.html [ Pass ]
-crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-filter.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-arc-circumference-fill.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blend-image.html [ Pass ]
@@ -528,7 +527,7 @@
 crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/origin/http-rp/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Failure ]
 crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/origin/meta-referrer/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Failure ]
 crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/strict-origin-when-cross-origin/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/same-insecure.http.html [ Failure ]
-crbug.com/591099 virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations.html [ Failure Pass ]
+crbug.com/591099 virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations.html [ Failure ]
 crbug.com/591099 virtual/omt-worker-fetch/external/wpt/workers/semantics/multiple-workers/003.html [ Timeout ]
 crbug.com/591099 virtual/outofblink-cors/ [ Skip ]
 crbug.com/591099 virtual/paint-timing/external/wpt/paint-timing/sibling-painting-first-image.html [ Failure ]
@@ -540,6 +539,9 @@
 crbug.com/591099 virtual/streaming-preload/http/tests/fetch/chromium/response-json-gc-crash.html [ Pass ]
 crbug.com/591099 virtual/streaming-preload/http/tests/fetch/serviceworker/thorough/cors-base-https-other-https.html [ Pass ]
 crbug.com/591099 virtual/streaming-preload/http/tests/fetch/workers/thorough/cors-preflight-base-https-other-https.html [ Pass ]
+crbug.com/591099 virtual/streams-native/external/wpt/fetch/api/basic/error-after-response.html [ Pass ]
+crbug.com/591099 virtual/streams-native/external/wpt/fetch/api/request/request-cache-default-conditional.html [ Pass ]
+crbug.com/591099 virtual/streams-native/external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
 crbug.com/591099 virtual/threaded/ [ Skip ]
 crbug.com/591099 virtual/user-activation-v2/fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
 crbug.com/591099 virtual/user-activation-v2/fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 357c2b0..167fed3 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -307,6 +307,13 @@
 crbug.com/853977 [ Linux ] virtual/outofblink-cors/http/tests/fetch/chromium/release-handle-crash.html [ Slow ]
 crbug.com/853977 [ Linux ] virtual/streaming-preload/http/tests/fetch/chromium/call-extra-crash-tee.html [ Slow ]
 crbug.com/853977 [ Linux ] virtual/streaming-preload/http/tests/fetch/chromium/release-handle-crash.html [ Slow ]
+crbug.com/853977 [ Linux ] virtual/streams-native/http/tests/fetch/chromium/call-extra-crash-tee.html [ Slow ]
+crbug.com/853977 [ Linux ] virtual/streams-native/http/tests/fetch/chromium/release-handle-crash.html [ Slow ]
+crbug.com/853977 [ Linux ] virtual/streams-native/http/tests/fetch/chromium/response-array-buffer-gc-crash.html [ Slow ]
+crbug.com/853977 [ Linux ] virtual/streams-native/http/tests/fetch/chromium/response-blob-gc-crash.html [ Slow ]
+crbug.com/853977 [ Linux ] virtual/streams-native/http/tests/fetch/chromium/response-form-data-gc-crash.html [ Slow ]
+crbug.com/853977 [ Linux ] virtual/streams-native/http/tests/fetch/chromium/response-json-gc-crash.html [ Slow ]
+crbug.com/853977 [ Linux ] virtual/streams-native/http/tests/fetch/chromium/response-text-gc-crash.html [ Slow ]
 
 crbug.com/864887 [ Mac ] fast/scroll-snap/snaps-after-scrollbar-scrolling.html [ Slow ]
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 239c237..65535f4e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3199,6 +3199,7 @@
 crbug.com/626703 [ Mac10.13 ] external/wpt/preload/dynamic-adding-preload-imagesrcset.html [ Timeout ]
 crbug.com/906369 external/wpt/css/css-text/text-transform/text-transform-capitalize-033.html [ Failure ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/content-type/response.window.html [ Timeout ]
+crbug.com/626703 virtual/streams-native/external/wpt/fetch/content-type/response.window.html [ Timeout ]
 crbug.com/626703 [ Mac10.10 ] external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.11 ] external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.10 ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Failure Timeout ]
@@ -3536,6 +3537,7 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-column-row-gap-002.html [ Failure ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Timeout ]
 crbug.com/626703 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Timeout ]
+crbug.com/626703 virtual/streams-native/external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/preload/link-header-preload.html [ Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/preload/onerror-event.html [ Timeout ]
 crbug.com/626703 external/wpt/svg/painting/reftests/paint-context-001.svg [ Failure ]
@@ -3555,6 +3557,7 @@
 crbug.com/626703 external/wpt/css/css-transforms/transform-box/view-box-mutation.html [ Failure ]
 crbug.com/626703 external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
+crbug.com/626703 virtual/streams-native/external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/domxpath/xml_xpath_runner.html [ Timeout ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-024.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-048.html [ Failure ]
@@ -3643,6 +3646,7 @@
 crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html [ Failure ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
 crbug.com/626703 external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
+crbug.com/626703 virtual/streams-native/external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-fonts/font-feature-settings-descriptor-01.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Timeout ]
 crbug.com/626703 [ Win10 ] external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Timeout ]
@@ -4460,8 +4464,9 @@
 # Importing 'fetch' tests from WPT.
 crbug.com/705490 external/wpt/fetch/api/basic/error-after-response.html [ Timeout Pass ]
 crbug.com/705490 virtual/outofblink-cors/external/wpt/fetch/api/basic/error-after-response.html [ Timeout Pass ]
+crbug.com/705490 virtual/streams-native/external/wpt/fetch/api/basic/error-after-response.html [ Timeout Pass ]
 crbug.com/820334 external/wpt/fetch/api/request/request-cache-default-conditional.html [ Timeout Pass ]
-crbug.com/820334 virtual/outofblink-cors/external/wpt/fetch/api/request/request-cache-default-conditional.html [ Timeout Pass ]
+crbug.com/820334 virtual/streams-native/external/wpt/fetch/api/request/request-cache-default-conditional.html [ Timeout Pass ]
 
 crbug.com/716320 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html [ Failure Timeout ]
 crbug.com/716320 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html [ Failure Timeout ]
@@ -5669,7 +5674,7 @@
 # Sheriff 2018-12-06
 crbug.com/912793 http/tests/devtools/sources/debugger-breakpoints/restore-locations-for-breakpoint-with-broken-source-map.js [ Pass Failure ]
 crbug.com/912793 virtual/binary-for-devtools/http/tests/devtools/sources/debugger-breakpoints/restore-locations-for-breakpoint-with-broken-source-map.js [ Pass Failure ]
-crbug.com/912793 virtual/android/fullscreen/full-screen-iframe-allowed-video.html [ Pass Failure ]
+crbug.com/912793 crbug.com/899087 virtual/android/fullscreen/full-screen-iframe-allowed-video.html [ Crash Pass Failure Timeout ]
 
 # Sheriff 2018-12-07
 crbug.com/912821 [ Mac ] virtual/threaded/http/tests/devtools/tracing/user-timing.js [ Pass Failure ]
@@ -5695,6 +5700,19 @@
 
 crbug.com/919272 external/wpt/resource-timing/resource-timing.html [ Skip ]
 
+### virtual/streams-native/http/tests/streams/transferable/
+crbug.com/902633 virtual/streams-native/http/tests/streams/transferable/writable-stream.html [ Timeout ]
+crbug.com/902633 virtual/streams-native/http/tests/streams/transferable/shared-worker.html [ Pass Failure ]
+crbug.com/902633 virtual/streams-native/http/tests/streams/transferable/worker.html [ Pass Failure ]
+
+# PipeTo() is currently disabled in the StreamsNative implementation of streams,
+# which causes these timeouts.
+### virtual/streams-native/external/wpt/fetch/api/request/
+crbug.com/902633 virtual/streams-native/external/wpt/fetch/api/request/request-keepalive-quota.html [ Timeout ]
+
+### virtual/streams-native/external/wpt/fetch/api/response/
+crbug.com/902633 virtual/streams-native/external/wpt/fetch/api/response/response-stream-with-broken-then.any.worker.html [ Timeout ]
+
 ### virtual/streams-native/external/wpt/streams/piping/
 crbug.com/902633 virtual/streams-native/external/wpt/streams/piping/abort.any.html [ Timeout ]
 crbug.com/902633 virtual/streams-native/external/wpt/streams/piping/abort.any.serviceworker.html [ Timeout ]
@@ -5719,10 +5737,6 @@
 ### virtual/streams-native/http/tests/streams/chromium/
 crbug.com/902633 virtual/streams-native/http/tests/streams/chromium/touching-global-object.html [ Timeout ]
 
-### virtual/streams-native/http/tests/streams/transferable/
-crbug.com/902633 virtual/streams-native/http/tests/streams/transferable/writable-stream.html [ Timeout ]
-crbug.com/902633 virtual/streams-native/http/tests/streams/transferable/window.html [ Timeout ]
-
 # Sheriff 2019-01-03
 crbug.com/918905 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/block-size-with-min-or-max-content-table-1b.html [ Pass Failure ]
 
@@ -6052,9 +6066,6 @@
 crbug.com/943388 [ Win ] http/tests/devtools/network/network-recording-after-reload-with-screenshots-enabled.js [ Pass Failure ]
 crbug.com/943388 [ Win ] virtual/binary-for-devtools/http/tests/devtools/network/network-recording-after-reload-with-screenshots-enabled.js [ Pass Failure ]
 
-# Trooper 2019-03-19
-crbug.com/941565 external/wpt/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-003.html [ Pass Failure ]
-
 # Sheriff 2019-03-20
 crbug.com/732103 [ Mac10.11 ] http/tests/shapedetection/shapedetection-cross-origin.html [ Timeout Pass ]
 crbug.com/943969 [ Win ] inspector-protocol/animation/animation-pause-infinite.js [ Pass Failure ]
@@ -6065,8 +6076,6 @@
 crbug.com/945085 [ Mac10.13 ] printing/composited-thead-tfoot-repeat.html [ Failure Pass ]
 
 # Sheriff 2019-03-25
-crbug.com/943940 http/tests/security/mixedContent/empty-url-plugin-in-frame.html [ Pass Failure ]
-crbug.com/943940 virtual/outofblink-cors/http/tests/security/mixedContent/empty-url-plugin-in-frame.html [ Pass Failure ]
 crbug.com/944025 http/tests/preload/meta-viewport-device-width-link-headers.html [ Pass Failure ]
 crbug.com/945665 http/tests/devtools/elements/styles-3/styles-add-new-rule-tab.js [ Pass Failure ]
 crbug.com/945665 virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/styles-add-new-rule-tab.js [ Pass Failure ]
@@ -6078,10 +6087,8 @@
 crbug.com/945665 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/style-rule-from-imported-stylesheet.js  [ Failure Pass ]
 crbug.com/945665 http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Pass Failure ]
 crbug.com/945665 virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Pass Failure ]
-crbug.com/945507 [ Win ] fast/url/standard-url.html [ Pass Failure ]
 crbug.com/945629 http/tests/devtools/network/network-filters.js [ Pass Failure Timeout ]
 crbug.com/945629 virtual/binary-for-devtools/http/tests/devtools/network/network-filters.js [ Pass Failure Timeout ]
-crbug.com/945832 http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-end-to-end.js [ Pass Failure Timeout Crash ]
 
 # Sheriff 2019-03-26
 crbug.com/945774 external/wpt/content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html [ Pass Timeout ]
@@ -6120,6 +6127,7 @@
 
 # Sheriff 2019-03-28
 crbug.com/946890 external/wpt/html/semantics/embedded-content/media-elements/location-of-the-media-resource/currentSrc.html [ Failure Pass ]
+crbug.com/946990 http/tests/devtools/application-panel/storage-view-reports-quota.js [ Pass Timeout ]
 crbug.com/946990 virtual/binary-for-devtools/http/tests/devtools/application-panel/storage-view-reports-quota.js [ Pass Timeout ]
 crbug.com/946719 http/tests/serviceworker/resolve-after-window-close.html [ Crash Pass ]
 crbug.com/946714 [ Release ] http/tests/devtools/elements/styles-4/styles-live-locations-leak.js [ Pass Timeout ]
@@ -6135,25 +6143,11 @@
 crbug.com/848799 [ Win7 ] http/tests/devtools/coverage/multiple-instances-merge.js [ Pass Timeout ]
 crbug.com/848799 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/coverage/multiple-instances-merge.js [ Pass Timeout ]
 crbug.com/947126 [ Mac10.13 ] virtual/video-surface-layer/media/video-played-ranges-1.html [ Pass Failure ]
-crbug.com/942411 [ Win7 ] http/tests/devtools/network/network-search.js [ Pass Timeout ]
-crbug.com/942411 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/network/network-search.js [ Pass Timeout ]
-
+crbug.com/942411 [ Win7 Linux ] http/tests/devtools/network/network-search.js [ Pass Timeout ]
+crbug.com/942411 [ Win7 Linux ] virtual/binary-for-devtools/http/tests/devtools/network/network-search.js [ Pass Timeout ]
+crbug.com/947383 inspector-protocol/css/reattach-after-editing-styles.js [ Pass Timeout ]
 
 ### external/wpt/fetch/sec-metadata/
-crbug.com/947023 external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html [ Pass Failure ]
 crbug.com/947023 external/wpt/fetch/sec-metadata/font.tentative.https.sub.html [ Pass Failure ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/object.tentative.https.sub.html [ Pass Failure ]
 crbug.com/947023 external/wpt/fetch/sec-metadata/report.tentative.https.sub.html [ Pass Timeout ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html [ Pass Failure ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html [ Pass Failure ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/style.tentative.https.sub.html [ Pass Failure ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/track.tentative.https.sub.html [ Pass Failure Timeout ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html [ Pass Failure ]
 crbug.com/947023 external/wpt/fetch/sec-metadata/xslt.tentative.https.sub.html [ Pass Failure ]
-
-### external/wpt/fetch/sec-metadata/redirect/
-crbug.com/947023 external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html [ Pass Failure ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html [ Pass Failure ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html [ Pass Failure ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html [ Pass Failure ]
-crbug.com/947023 external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 592a69a4..13ab974 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -185,7 +185,8 @@
   {
     "prefix": "origin-trials-runtimeflags-disabled",
     "base": "http/tests/origin_trials/webexposed",
-    "args": ["--disable-origin-trial-controlled-blink-features"]
+    "args": ["--disable-origin-trial-controlled-blink-features",
+             "--stable-release-mode"]
   },
   {
     "prefix": "stable",
@@ -1011,6 +1012,16 @@
     "args": ["--enable-blink-features=StreamsNative", "--enable-features=BlinkHeapUnifiedGarbageCollection"]
   },
   {
+    "prefix": "streams-native",
+    "base": "http/tests/fetch",
+    "args": ["--enable-blink-features=StreamsNative", "--enable-features=BlinkHeapUnifiedGarbageCollection"]
+  },
+  {
+    "prefix": "streams-native",
+    "base": "external/wpt/fetch",
+    "args": ["--enable-blink-features=StreamsNative", "--enable-features=BlinkHeapUnifiedGarbageCollection"]
+  },
+  {
     "prefix": "bidi-caret-affinity",
     "base": "editing/selection/modify_move",
     "args": ["--enable-blink-features=BidiCaretAffinity,EditingNG"]
diff --git a/third_party/blink/web_tests/animations/custom-properties/animate-high-priority.html b/third_party/blink/web_tests/animations/custom-properties/animate-high-priority.html
new file mode 100644
index 0000000..07fcc4d
--- /dev/null
+++ b/third_party/blink/web_tests/animations/custom-properties/animate-high-priority.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+  CSS.registerProperty({
+    name: '--my-font-size',
+    syntax: '<length>',
+    inherits: false,
+    initialValue: '0px'
+  });
+
+  CSS.registerProperty({
+    name: '--my-color',
+    syntax: '<color>',
+    inherits: false,
+    initialValue: 'white'
+  });
+</script>
+<style>
+@keyframes anim1 {
+  from { --my-font-size: 10px; }
+  to { --my-font-size: 20px; }
+}
+
+@keyframes anim2 {
+  from { --my-color: rgb(0, 0, 0); }
+  to { --my-color: rgb(100, 100, 100); }
+}
+
+#target1 {
+  animation: anim1 3600s steps(2, start);
+  font-size: var(--my-font-size);
+  width: 10em;
+}
+
+#target2 {
+  animation: anim2 3600s steps(2, start);
+  color: var(--my-color);
+  background-color: currentColor;
+}
+</style>
+<div id="target1"></div>
+<div id="target2"></div>
+<script>
+
+test(() => {
+  target1.offsetTop;
+  target1.classList.toggle('test');
+  let style = getComputedStyle(target1);
+  assert_equals(style.getPropertyValue('--my-font-size'), '15px');
+  assert_equals(style.getPropertyValue('font-size'), '15px');
+  assert_equals(style.getPropertyValue('width'), '150px');
+}, 'Animating var() used in font-size causes em unit to change');
+
+test(() => {
+  target2.offsetTop;
+  target2.classList.toggle('test');
+  let style = getComputedStyle(target2);
+  assert_equals(style.getPropertyValue('--my-color'), 'rgb(50, 50, 50)');
+  assert_equals(style.getPropertyValue('color'), 'rgb(50, 50, 50)');
+  assert_equals(style.getPropertyValue('background-color'), 'rgb(50, 50, 50)');
+}, 'Animating var() used in color causes currentColor to change');
+
+</script>
diff --git a/third_party/blink/web_tests/animations/custom-properties/color-type-interpolation-expected.txt b/third_party/blink/web_tests/animations/custom-properties/color-type-interpolation-expected.txt
deleted file mode 100644
index 574a02af..0000000
--- a/third_party/blink/web_tests/animations/custom-properties/color-type-interpolation-expected.txt
+++ /dev/null
@@ -1,148 +0,0 @@
-This is a testharness.js-based test.
-PASS This test uses interpolation-test.js.
-PASS CSS Transitions: property <--color> from neutral to [green] at (-0.3) is [rgb(255, 255, 0)]
-PASS CSS Transitions: property <--color> from neutral to [green] at (0) is [rgb(255, 255, 0)]
-PASS CSS Transitions: property <--color> from neutral to [green] at (0.3) is [rgb(179, 217, 0)]
-PASS CSS Transitions: property <--color> from neutral to [green] at (0.6) is [rgb(102, 179, 0)]
-PASS CSS Transitions: property <--color> from neutral to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Transitions: property <--color> from neutral to [green] at (1.5) is [rgb(0, 65, 0)]
-PASS CSS Transitions: property <--color> from [initial] to [green] at (-0.3) is [rgb(0, 0, 0)]
-PASS CSS Transitions: property <--color> from [initial] to [green] at (0) is [rgb(0, 0, 0)]
-PASS CSS Transitions: property <--color> from [initial] to [green] at (0.3) is [rgb(0, 38, 0)]
-PASS CSS Transitions: property <--color> from [initial] to [green] at (0.6) is [rgb(0, 77, 0)]
-PASS CSS Transitions: property <--color> from [initial] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Transitions: property <--color> from [initial] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Transitions: property <--color> from [inherit] to [green] at (-0.3) is [rgb(0, 0, 255)]
-PASS CSS Transitions: property <--color> from [inherit] to [green] at (0) is [rgb(0, 0, 255)]
-PASS CSS Transitions: property <--color> from [inherit] to [green] at (0.3) is [rgb(0, 38, 179)]
-PASS CSS Transitions: property <--color> from [inherit] to [green] at (0.6) is [rgb(0, 77, 102)]
-PASS CSS Transitions: property <--color> from [inherit] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Transitions: property <--color> from [inherit] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Transitions: property <--color> from [unset] to [green] at (-0.3) is [rgb(0, 0, 0)]
-PASS CSS Transitions: property <--color> from [unset] to [green] at (0) is [rgb(0, 0, 0)]
-PASS CSS Transitions: property <--color> from [unset] to [green] at (0.3) is [rgb(0, 38, 0)]
-PASS CSS Transitions: property <--color> from [unset] to [green] at (0.6) is [rgb(0, 77, 0)]
-PASS CSS Transitions: property <--color> from [unset] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Transitions: property <--color> from [unset] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Transitions: property <--color> from [black] to [orange] at (-0.3) is [rgb(0, 0, 0)]
-PASS CSS Transitions: property <--color> from [black] to [orange] at (0) is [rgb(0, 0, 0)]
-PASS CSS Transitions: property <--color> from [black] to [orange] at (0.3) is [rgb(77, 50, 0)]
-PASS CSS Transitions: property <--color> from [black] to [orange] at (0.6) is [rgb(153, 99, 0)]
-PASS CSS Transitions: property <--color> from [black] to [orange] at (1) is [rgb(255, 165, 0)]
-PASS CSS Transitions: property <--color> from [black] to [orange] at (1.5) is [rgb(255, 248, 0)]
-PASS CSS Transitions: property <--color> from [black] to [currentcolor] at (-0.3) is [rgb(0, 0, 0)]
-PASS CSS Transitions: property <--color> from [black] to [currentcolor] at (0) is [rgb(0, 0, 0)]
-FAIL CSS Transitions: property <--color> from [black] to [currentcolor] at (0.3) is [rgb(0, 0, 0)] assert_equals: expected "rgb ( 0 , 77 , 0 ) " but got "rgb ( 0 , 0 , 0 ) "
-FAIL CSS Transitions: property <--color> from [black] to [currentcolor] at (0.6) is [rgb(0, 0, 0)] assert_equals: expected "rgb ( 0 , 153 , 0 ) " but got "rgb ( 0 , 0 , 0 ) "
-FAIL CSS Transitions: property <--color> from [black] to [currentcolor] at (1) is [rgb(0, 0, 0)] assert_equals: expected "rgb ( 0 , 255 , 0 ) " but got "rgb ( 0 , 0 , 0 ) "
-FAIL CSS Transitions: property <--color> from [black] to [currentcolor] at (1.5) is [rgb(0, 0, 0)] assert_equals: expected "rgb ( 0 , 255 , 0 ) " but got "rgb ( 0 , 0 , 0 ) "
-PASS CSS Transitions: property <--color> from [-webkit-activelink] to [green] at (-0.3) is [rgb(255, 0, 0)]
-PASS CSS Transitions: property <--color> from [-webkit-activelink] to [green] at (0) is [rgb(255, 0, 0)]
-PASS CSS Transitions: property <--color> from [-webkit-activelink] to [green] at (0.3) is [rgb(179, 38, 0)]
-PASS CSS Transitions: property <--color> from [-webkit-activelink] to [green] at (0.6) is [rgb(102, 77, 0)]
-PASS CSS Transitions: property <--color> from [-webkit-activelink] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Transitions: property <--color> from [-webkit-activelink] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Transitions: property <--color> from [-webkit-link] to [green] at (-0.3) is [rgb(0, 0, 255)]
-PASS CSS Transitions: property <--color> from [-webkit-link] to [green] at (0) is [rgb(0, 0, 255)]
-PASS CSS Transitions: property <--color> from [-webkit-link] to [green] at (0.3) is [rgb(0, 38, 179)]
-PASS CSS Transitions: property <--color> from [-webkit-link] to [green] at (0.6) is [rgb(0, 77, 102)]
-PASS CSS Transitions: property <--color> from [-webkit-link] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Transitions: property <--color> from [-webkit-link] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Animations: property <--color> from neutral to [green] at (-0.3) is [rgb(255, 255, 0)]
-PASS CSS Animations: property <--color> from neutral to [green] at (0) is [rgb(255, 255, 0)]
-PASS CSS Animations: property <--color> from neutral to [green] at (0.3) is [rgb(179, 217, 0)]
-PASS CSS Animations: property <--color> from neutral to [green] at (0.6) is [rgb(102, 179, 0)]
-PASS CSS Animations: property <--color> from neutral to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Animations: property <--color> from neutral to [green] at (1.5) is [rgb(0, 65, 0)]
-PASS CSS Animations: property <--color> from [initial] to [green] at (-0.3) is [rgb(0, 0, 0)]
-PASS CSS Animations: property <--color> from [initial] to [green] at (0) is [rgb(0, 0, 0)]
-PASS CSS Animations: property <--color> from [initial] to [green] at (0.3) is [rgb(0, 38, 0)]
-PASS CSS Animations: property <--color> from [initial] to [green] at (0.6) is [rgb(0, 77, 0)]
-PASS CSS Animations: property <--color> from [initial] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Animations: property <--color> from [initial] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Animations: property <--color> from [inherit] to [green] at (-0.3) is [rgb(0, 0, 255)]
-PASS CSS Animations: property <--color> from [inherit] to [green] at (0) is [rgb(0, 0, 255)]
-PASS CSS Animations: property <--color> from [inherit] to [green] at (0.3) is [rgb(0, 38, 179)]
-PASS CSS Animations: property <--color> from [inherit] to [green] at (0.6) is [rgb(0, 77, 102)]
-PASS CSS Animations: property <--color> from [inherit] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Animations: property <--color> from [inherit] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Animations: property <--color> from [unset] to [green] at (-0.3) is [rgb(0, 0, 0)]
-PASS CSS Animations: property <--color> from [unset] to [green] at (0) is [rgb(0, 0, 0)]
-PASS CSS Animations: property <--color> from [unset] to [green] at (0.3) is [rgb(0, 38, 0)]
-PASS CSS Animations: property <--color> from [unset] to [green] at (0.6) is [rgb(0, 77, 0)]
-PASS CSS Animations: property <--color> from [unset] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Animations: property <--color> from [unset] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Animations: property <--color> from [black] to [orange] at (-0.3) is [rgb(0, 0, 0)]
-PASS CSS Animations: property <--color> from [black] to [orange] at (0) is [rgb(0, 0, 0)]
-PASS CSS Animations: property <--color> from [black] to [orange] at (0.3) is [rgb(77, 50, 0)]
-PASS CSS Animations: property <--color> from [black] to [orange] at (0.6) is [rgb(153, 99, 0)]
-PASS CSS Animations: property <--color> from [black] to [orange] at (1) is [rgb(255, 165, 0)]
-PASS CSS Animations: property <--color> from [black] to [orange] at (1.5) is [rgb(255, 248, 0)]
-PASS CSS Animations: property <--color> from [black] to [currentcolor] at (-0.3) is [rgb(0, 0, 0)]
-PASS CSS Animations: property <--color> from [black] to [currentcolor] at (0) is [rgb(0, 0, 0)]
-FAIL CSS Animations: property <--color> from [black] to [currentcolor] at (0.3) is [rgb(0, 0, 0)] assert_equals: expected "rgb ( 0 , 77 , 0 ) " but got "rgb ( 0 , 0 , 0 ) "
-FAIL CSS Animations: property <--color> from [black] to [currentcolor] at (0.6) is [rgb(0, 0, 0)] assert_equals: expected "rgb ( 0 , 153 , 0 ) " but got "rgb ( 0 , 0 , 0 ) "
-FAIL CSS Animations: property <--color> from [black] to [currentcolor] at (1) is [rgb(0, 0, 0)] assert_equals: expected "rgb ( 0 , 255 , 0 ) " but got "rgb ( 0 , 0 , 0 ) "
-FAIL CSS Animations: property <--color> from [black] to [currentcolor] at (1.5) is [rgb(0, 0, 0)] assert_equals: expected "rgb ( 0 , 255 , 0 ) " but got "rgb ( 0 , 0 , 0 ) "
-PASS CSS Animations: property <--color> from [-webkit-activelink] to [green] at (-0.3) is [rgb(255, 0, 0)]
-PASS CSS Animations: property <--color> from [-webkit-activelink] to [green] at (0) is [rgb(255, 0, 0)]
-PASS CSS Animations: property <--color> from [-webkit-activelink] to [green] at (0.3) is [rgb(179, 38, 0)]
-PASS CSS Animations: property <--color> from [-webkit-activelink] to [green] at (0.6) is [rgb(102, 77, 0)]
-PASS CSS Animations: property <--color> from [-webkit-activelink] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Animations: property <--color> from [-webkit-activelink] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS CSS Animations: property <--color> from [-webkit-link] to [green] at (-0.3) is [rgb(0, 0, 255)]
-PASS CSS Animations: property <--color> from [-webkit-link] to [green] at (0) is [rgb(0, 0, 255)]
-PASS CSS Animations: property <--color> from [-webkit-link] to [green] at (0.3) is [rgb(0, 38, 179)]
-PASS CSS Animations: property <--color> from [-webkit-link] to [green] at (0.6) is [rgb(0, 77, 102)]
-PASS CSS Animations: property <--color> from [-webkit-link] to [green] at (1) is [rgb(0, 128, 0)]
-PASS CSS Animations: property <--color> from [-webkit-link] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS Web Animations: property <--color> from neutral to [green] at (-0.3) is [rgb(255, 255, 0)]
-PASS Web Animations: property <--color> from neutral to [green] at (0) is [rgb(255, 255, 0)]
-PASS Web Animations: property <--color> from neutral to [green] at (0.3) is [rgb(179, 217, 0)]
-PASS Web Animations: property <--color> from neutral to [green] at (0.6) is [rgb(102, 179, 0)]
-PASS Web Animations: property <--color> from neutral to [green] at (1) is [rgb(0, 128, 0)]
-PASS Web Animations: property <--color> from neutral to [green] at (1.5) is [rgb(0, 65, 0)]
-PASS Web Animations: property <--color> from [initial] to [green] at (-0.3) is [rgb(0, 0, 0)]
-PASS Web Animations: property <--color> from [initial] to [green] at (0) is [rgb(0, 0, 0)]
-PASS Web Animations: property <--color> from [initial] to [green] at (0.3) is [rgb(0, 38, 0)]
-PASS Web Animations: property <--color> from [initial] to [green] at (0.6) is [rgb(0, 77, 0)]
-PASS Web Animations: property <--color> from [initial] to [green] at (1) is [rgb(0, 128, 0)]
-PASS Web Animations: property <--color> from [initial] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS Web Animations: property <--color> from [inherit] to [green] at (-0.3) is [rgb(0, 0, 255)]
-PASS Web Animations: property <--color> from [inherit] to [green] at (0) is [rgb(0, 0, 255)]
-PASS Web Animations: property <--color> from [inherit] to [green] at (0.3) is [rgb(0, 38, 179)]
-PASS Web Animations: property <--color> from [inherit] to [green] at (0.6) is [rgb(0, 77, 102)]
-PASS Web Animations: property <--color> from [inherit] to [green] at (1) is [rgb(0, 128, 0)]
-PASS Web Animations: property <--color> from [inherit] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS Web Animations: property <--color> from [unset] to [green] at (-0.3) is [rgb(0, 0, 0)]
-PASS Web Animations: property <--color> from [unset] to [green] at (0) is [rgb(0, 0, 0)]
-PASS Web Animations: property <--color> from [unset] to [green] at (0.3) is [rgb(0, 38, 0)]
-PASS Web Animations: property <--color> from [unset] to [green] at (0.6) is [rgb(0, 77, 0)]
-PASS Web Animations: property <--color> from [unset] to [green] at (1) is [rgb(0, 128, 0)]
-PASS Web Animations: property <--color> from [unset] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS Web Animations: property <--color> from [black] to [orange] at (-0.3) is [rgb(0, 0, 0)]
-PASS Web Animations: property <--color> from [black] to [orange] at (0) is [rgb(0, 0, 0)]
-PASS Web Animations: property <--color> from [black] to [orange] at (0.3) is [rgb(77, 50, 0)]
-PASS Web Animations: property <--color> from [black] to [orange] at (0.6) is [rgb(153, 99, 0)]
-PASS Web Animations: property <--color> from [black] to [orange] at (1) is [rgb(255, 165, 0)]
-PASS Web Animations: property <--color> from [black] to [orange] at (1.5) is [rgb(255, 248, 0)]
-PASS Web Animations: property <--color> from [black] to [currentcolor] at (-0.3) is [rgb(0, 0, 0)]
-PASS Web Animations: property <--color> from [black] to [currentcolor] at (0) is [rgb(0, 0, 0)]
-PASS Web Animations: property <--color> from [black] to [currentcolor] at (0.3) is [rgb(0, 77, 0)]
-PASS Web Animations: property <--color> from [black] to [currentcolor] at (0.6) is [rgb(0, 153, 0)]
-PASS Web Animations: property <--color> from [black] to [currentcolor] at (1) is [rgb(0, 255, 0)]
-PASS Web Animations: property <--color> from [black] to [currentcolor] at (1.5) is [rgb(0, 255, 0)]
-PASS Web Animations: property <--color> from [-webkit-activelink] to [green] at (-0.3) is [rgb(255, 0, 0)]
-PASS Web Animations: property <--color> from [-webkit-activelink] to [green] at (0) is [rgb(255, 0, 0)]
-PASS Web Animations: property <--color> from [-webkit-activelink] to [green] at (0.3) is [rgb(179, 38, 0)]
-PASS Web Animations: property <--color> from [-webkit-activelink] to [green] at (0.6) is [rgb(102, 77, 0)]
-PASS Web Animations: property <--color> from [-webkit-activelink] to [green] at (1) is [rgb(0, 128, 0)]
-PASS Web Animations: property <--color> from [-webkit-activelink] to [green] at (1.5) is [rgb(0, 192, 0)]
-PASS Web Animations: property <--color> from [-webkit-link] to [green] at (-0.3) is [rgb(0, 0, 255)]
-PASS Web Animations: property <--color> from [-webkit-link] to [green] at (0) is [rgb(0, 0, 255)]
-PASS Web Animations: property <--color> from [-webkit-link] to [green] at (0.3) is [rgb(0, 38, 179)]
-PASS Web Animations: property <--color> from [-webkit-link] to [green] at (0.6) is [rgb(0, 77, 102)]
-PASS Web Animations: property <--color> from [-webkit-link] to [green] at (1) is [rgb(0, 128, 0)]
-PASS Web Animations: property <--color> from [-webkit-link] to [green] at (1.5) is [rgb(0, 192, 0)]
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/animations/custom-properties/transition-em-unit.html b/third_party/blink/web_tests/animations/custom-properties/transition-em-unit.html
new file mode 100644
index 0000000..a0ff171e
--- /dev/null
+++ b/third_party/blink/web_tests/animations/custom-properties/transition-em-unit.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+  CSS.registerProperty({
+    name: '--x',
+    syntax: '<length>',
+    inherits: false,
+    initialValue: '0px'
+  });
+  CSS.registerProperty({
+    name: '--y',
+    syntax: '<integer>',
+    inherits: false,
+    initialValue: '0'
+  });
+</script>
+<style>
+#target1 {
+  font-size: 10px;
+  --x: 10em;
+  transition: --x 3600s steps(2, start);
+}
+#target1.test {
+  font-size: 20px;
+}
+#target2 {
+  font-size: 10px;
+  --x: 100px;
+  --y: 0;
+  transition: --x 0.1s, --y 0.1s;
+}
+#target2.test {
+  --x: 10em;
+  --y: 10;
+}
+</style>
+<div id="target1"></div>
+<div id="target2"></div>
+<script>
+
+test(() => {
+  target1.offsetTop;
+  target1.classList.toggle('test');
+  let s = getComputedStyle(target1);
+  assert_equals(s.getPropertyValue('--x'), '150px');
+}, 'Transition starts when computed value changes via em unit');
+
+promise_test(async () => {
+  target2.offsetTop;
+
+  // Collect all transitionstart events.
+  let start_events = [];
+  target2.addEventListener('transitionstart', (e) => start_events.push(e));
+
+  // Wait for any transitionend.
+  await new Promise((resolve, reject) => {
+    target2.addEventListener('transitionend', resolve);
+    target2.classList.toggle('test');
+  });
+
+  // --y should transition, but --x should not.
+  assert_equals(start_events.length, 1);
+}, 'No transition when computed value does not change');
+
+</script>
diff --git a/third_party/blink/web_tests/animations/custom-properties/transition-high-priority.html b/third_party/blink/web_tests/animations/custom-properties/transition-high-priority.html
new file mode 100644
index 0000000..ac8d8153
--- /dev/null
+++ b/third_party/blink/web_tests/animations/custom-properties/transition-high-priority.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+  CSS.registerProperty({
+    name: '--my-font-size',
+    syntax: '<length>',
+    inherits: false,
+    initialValue: '0px'
+  });
+
+  CSS.registerProperty({
+    name: '--my-color',
+    syntax: '<color>',
+    inherits: false,
+    initialValue: 'white'
+  });
+</script>
+<style>
+#target1 {
+  --my-font-size: 10px;
+  font-size: var(--my-font-size);
+  width: 10em;
+  transition: --my-font-size 3600s steps(2, start);
+}
+#target1.test {
+  --my-font-size: 20px;
+}
+
+#target2 {
+  --my-color: rgb(0, 0, 0);
+  transition: --my-color 3600s steps(2, start);
+  color: var(--my-color);
+  background-color: currentColor;
+}
+#target2.test {
+  --my-color: rgb(100, 100, 100);
+}
+</style>
+<div id="target1"></div>
+<div id="target2"></div>
+<script>
+
+test(() => {
+  target1.offsetTop;
+  target1.classList.toggle('test');
+  let style = getComputedStyle(target1);
+  assert_equals(style.getPropertyValue('--my-font-size'), '15px');
+  assert_equals(style.getPropertyValue('font-size'), '15px');
+  assert_equals(style.getPropertyValue('width'), '150px');
+}, 'Transitioning var() used in font-size causes em unit to change');
+
+test(() => {
+  target2.offsetTop;
+  target2.classList.toggle('test');
+  let style = getComputedStyle(target2);
+  assert_equals(style.getPropertyValue('--my-color'), 'rgb(50, 50, 50)');
+  assert_equals(style.getPropertyValue('color'), 'rgb(50, 50, 50)');
+  assert_equals(style.getPropertyValue('background-color'), 'rgb(50, 50, 50)');
+}, 'Transitioning var() used in color causes currentColor to change');
+
+</script>
diff --git a/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-expected.txt b/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-expected.txt
deleted file mode 100644
index cb6b711..0000000
--- a/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This test starts an animation of the 'left' property and then does elementFromPoint calls at the shown yellow dots to see if hit testing works
-PASS - 150px was outside as it should be
-PASS - 300px was inside as it should be
-PASS - 450px was outside as it should be
-
diff --git a/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-transform-expected.txt b/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-transform-expected.txt
deleted file mode 100644
index efbf5d11..0000000
--- a/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-transform-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This test starts an animation of the 'transform' property and then does elementFromPoint calls at the shown yellow dots to see if hit testing works
-PASS - 150px was outside as it should be
-PASS - 300px was inside as it should be
-PASS - 450px was outside as it should be
-
diff --git a/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-transform.html b/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-transform.html
index 9a40512..97b97e24 100644
--- a/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-transform.html
+++ b/third_party/blink/web_tests/animations/hit-testing/animation-hit-test-transform.html
@@ -19,7 +19,7 @@
         from { transform: translate(100px); }
         to { transform: translate(300px); }
     }
-    
+
     .dot {
         width: 10px;
         height: 10px;
@@ -29,61 +29,52 @@
     }
    </style>
 
+   <script src="../../resources/testharness.js"></script>
+   <script src="../../resources/testharnessreport.js"></script>
    <script type="text/javascript" charset="utf-8">
+        var test = async_test("This test starts an animation of the 'transform' property and then does elementFromPoint calls at the shown yellow dots to see if hit testing works");
+
         function checkResult(pos, isIn)
         {
             var elt = document.elementFromPoint(pos, 150);
             var good = isIn ? "inside" : "outside";
             var bad = isIn ? "outside" : "inside";
-            return (isIn == (elt.id == "target")) ?
-                "<span style='color:green'>PASS</span> - " + pos + "px was " + good + " as it should be" + "<br>" :
-                "<span style='color:red'>FAIL</span> - " + pos + "px was " + bad + " and should have been " + good + "<br>";
+            var result = (elt.id == "target");
+            assert_equals(isIn, result, pos + "px should be " + good + ", not " + bad);
         }
-        
+
         function checkResults()
         {
             // Test before (150), in (300) and after (450)
-            var result = "";
-            result += checkResult(150, false);
-            result += checkResult(300, true);
-            result += checkResult(450, false);
-            document.getElementById('result').innerHTML = result;
+            checkResult(150, false);
+            checkResult(300, true);
+            checkResult(450, false);
         }
-     
+
         function doTest()
         {
             if (window.testRunner) {
                 internals.pauseAnimations(2);
-        
+
                 checkResults();
-                testRunner.notifyDone();
+                test.done();
             }
             else {
-                window.setTimeout("checkResults()", 2000);
+                test.step_timeout(test.step_func_done(checkResults), 2000);
             }
         }
-    
+
         function startTest()
         {
-            if (window.testRunner) {
-                testRunner.dumpAsText();
-                testRunner.waitUntilDone();
-            }
-      
             document.getElementById("target").style.animationName = "anim";
-            document.addEventListener('animationstart', doTest);
+            document.addEventListener('animationstart', test.step_func(doTest));
         }
    </script>
 </head>
 <body onload="startTest()">
-    <div>
-        This test starts an animation of the 'transform' property and then does elementFromPoint calls
-        at the shown yellow dots to see if hit testing works
-    </div>
     <div id="target"></div>
     <div class="dot" style="left:150px"></div>
     <div class="dot" style="left:300px"></div>
     <div class="dot" style="left:450px"></div>
-    <div id="result" style="position:absolute; top:250px"></div>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/animations/hit-testing/animation-hit-test.html b/third_party/blink/web_tests/animations/hit-testing/animation-hit-test.html
index b7cd3f2..5efa71c 100644
--- a/third_party/blink/web_tests/animations/hit-testing/animation-hit-test.html
+++ b/third_party/blink/web_tests/animations/hit-testing/animation-hit-test.html
@@ -19,7 +19,7 @@
         from { left: 100px; }
         to { left: 300px; }
     }
-    
+
     .dot {
         width: 10px;
         height: 10px;
@@ -29,61 +29,51 @@
     }
     </style>
 
+   <script src="../../resources/testharness.js"></script>
+   <script src="../../resources/testharnessreport.js"></script>
    <script type="text/javascript" charset="utf-8">
+        var test = async_test("This test starts an animation of the 'left' property and then does elementFromPoint calls at the shown yellow dots to see if hit testing works");
+
         function checkResult(pos, isIn)
         {
             var elt = document.elementFromPoint(pos, 150);
             var good = isIn ? "inside" : "outside";
             var bad = isIn ? "outside" : "inside";
-            return (isIn == (elt.id == "target")) ?
-                "<span style='color:green'>PASS</span> - " + pos + "px was " + good + " as it should be" + "<br>" :
-                "<span style='color:red'>FAIL</span> - " + pos + "px was " + bad + " and should have been " + good + "<br>";
+            var result = (elt.id == "target");
+            assert_equals(isIn, result, pos + "px should be " + good + ", not " + bad);
         }
-        
+
         function checkResults()
         {
             // Test before (150), in (300) and after (450)
-            var result = "";
-            result += checkResult(150, false);
-            result += checkResult(300, true);
-            result += checkResult(450, false);
-            document.getElementById('result').innerHTML = result;
+            checkResult(150, false);
+            checkResult(300, true);
+            checkResult(450, false);
         }
-     
+
         function doTest()
         {
             if (window.testRunner) {
                 internals.pauseAnimations(2);
-        
                 checkResults();
-                testRunner.notifyDone();
+                test.done();
             }
             else {
-                window.setTimeout("checkResults()", 2000);
+                test.step_timeout(test.step_func_done(checkResults), 2000);
             }
         }
-    
+
         function startTest()
         {
-            if (window.testRunner) {
-                testRunner.dumpAsText();
-                testRunner.waitUntilDone();
-            }
-      
             document.getElementById("target").style.animationName = "anim";
-            document.addEventListener('animationstart', doTest);
+            document.addEventListener('animationstart', test.step_func(doTest));
         }
    </script>
 </head>
 <body onload="startTest()">
-    <div>
-        This test starts an animation of the 'left' property and then does elementFromPoint calls
-        at the shown yellow dots to see if hit testing works
-    </div>
     <div id="target"></div>
     <div class="dot" style="left:150px"></div>
     <div class="dot" style="left:300px"></div>
     <div class="dot" style="left:450px"></div>
-    <div id="result" style="position:absolute; top:250px"></div>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/animations/hit-testing/inline-element-animation-end-hit-test-expected.txt b/third_party/blink/web_tests/animations/hit-testing/inline-element-animation-end-hit-test-expected.txt
deleted file mode 100644
index 2772fc40..0000000
--- a/third_party/blink/web_tests/animations/hit-testing/inline-element-animation-end-hit-test-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that when a LayoutObject loses its PaintLayer due to completion of an animation of an inline statically positioned element, we correctly update the locations of descendent layers.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS document.elementFromPoint(150, 150) === box is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/animations/hit-testing/inline-element-animation-end-hit-test.html b/third_party/blink/web_tests/animations/hit-testing/inline-element-animation-end-hit-test.html
index d9e13c02..fdd1321a 100644
--- a/third_party/blink/web_tests/animations/hit-testing/inline-element-animation-end-hit-test.html
+++ b/third_party/blink/web_tests/animations/hit-testing/inline-element-animation-end-hit-test.html
@@ -16,26 +16,19 @@
 }
 
 </style>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div class="margin">
   <span class="grow">
     <div id="box"></div>
   </span>
 </div>
-<p id="description"></p>
-<div id="console"></div>
 <script>
-
-jsTestIsAsync = true;
-
-description("Tests that when a LayoutObject loses its PaintLayer " +
-    "due to completion of an animation of an inline statically positioned " +
-    "element, we correctly update the locations of descendent layers.");
+var test = async_test("Tests that when a LayoutObject loses its PaintLayer due to completion of an animation of an inline statically positioned element, we correctly update the locations of descendent layers");
 
 var box = document.querySelector("#box");
-box.parentNode.addEventListener("animationend", function() {
-  shouldBeTrue("document.elementFromPoint(150, 150) === box");
-  finishJSTest();
-});
+box.parentNode.addEventListener("animationend", test.step_func_done(() => {
+  assert_equals(document.elementFromPoint(150, 150), box);
+}));
 
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/animation-add-events-in-handler-expected.txt b/third_party/blink/web_tests/animations/stability/animation-add-events-in-handler-expected.txt
deleted file mode 100644
index 1dd9c0b..0000000
--- a/third_party/blink/web_tests/animations/stability/animation-add-events-in-handler-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-PASS: Adding animation events in the handler did not crash.
diff --git a/third_party/blink/web_tests/animations/stability/animation-add-events-in-handler.html b/third_party/blink/web_tests/animations/stability/animation-add-events-in-handler.html
index bc9ed3b8..24ddbb9 100644
--- a/third_party/blink/web_tests/animations/stability/animation-add-events-in-handler.html
+++ b/third_party/blink/web_tests/animations/stability/animation-add-events-in-handler.html
@@ -1,27 +1,24 @@
 <!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
+var test = async_test("Ensure that adding animation events in the handler does not crash");
 
 function touchElement(evt) {
     getComputedStyle(evt.srcElement.firstElementChild)['-webkit-animation-duration'];
     evt.srcElement.firstElementChild.style.display = 'block';
     total++;
     if (total == 500) {
-        document.getElementById("results").innerHTML = "PASS: Adding animation events in the handler did not crash.";
-        if (window.testRunner)
-          testRunner.notifyDone();
+        test.done();
     }
 }
 
-window.onload = function() {
+window.onload = test.step_func(() => {
     total = 0;
     var padding = document.getElementsByClassName("padding");
     for (var i = 0; i < padding.length; i++)
-        padding[i].addEventListener('webkitAnimationIteration', touchElement, false, false);
-};
+        padding[i].addEventListener('webkitAnimationIteration', test.step_func(touchElement), false, false);
+});
 </script>
 <style>
 @-webkit-keyframes keyframes {
@@ -38,7 +35,6 @@
     -webkit-animation-duration: 0.001s;
 }
 </style>
-<div id="results">
 <div class="padding">
 <div class="padding">
 <div class="padding">
diff --git a/third_party/blink/web_tests/animations/stability/animation-end-crash-expected.txt b/third_party/blink/web_tests/animations/stability/animation-end-crash-expected.txt
deleted file mode 100644
index e12c81d..0000000
--- a/third_party/blink/web_tests/animations/stability/animation-end-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This tests waiting for a composited animation to end. It passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/animation-end-crash.html b/third_party/blink/web_tests/animations/stability/animation-end-crash.html
index 551f823..3c5d4635 100644
--- a/third_party/blink/web_tests/animations/stability/animation-end-crash.html
+++ b/third_party/blink/web_tests/animations/stability/animation-end-crash.html
@@ -1,4 +1,6 @@
 <!doctype html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
   @keyframes animation-a {
     0% {
@@ -15,14 +17,7 @@
 <div style="animation: animation-a .01s .01s 1 linear forwards;">
   <div id="target" style="animation: animation-b .1s 0.1s 1 linear forwards;"></div>
 </div>
-<div id="test">This tests waiting for a composited animation to end. It passes if it does not crash.</div>
 <script>
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-target.addEventListener('animationend', function() {
-  if (window.testRunner)
-    testRunner.notifyDone();
-});
+var test = async_test("This tests waiting for a composited animation to end. It passes if it does not crash");
+target.addEventListener('animationend', test.step_func_done(() => {}));
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/animation-end-event-destroy-renderer-expected.txt b/third_party/blink/web_tests/animations/stability/animation-end-event-destroy-renderer-expected.txt
deleted file mode 100644
index 396fe15..0000000
--- a/third_party/blink/web_tests/animations/stability/animation-end-event-destroy-renderer-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests element removal and hiding within the animationend event handler. Should not crash.
-
-Did not crash, so PASSED
diff --git a/third_party/blink/web_tests/animations/stability/animation-end-event-destroy-renderer.html b/third_party/blink/web_tests/animations/stability/animation-end-event-destroy-renderer.html
index 650c68d6..268b979 100644
--- a/third_party/blink/web_tests/animations/stability/animation-end-event-destroy-renderer.html
+++ b/third_party/blink/web_tests/animations/stability/animation-end-event-destroy-renderer.html
@@ -1,4 +1,3 @@
-<html>
 <head>
   <title>Destroy and Hide Element in Animation End Event</title>
   <style type="text/css" media="screen">
@@ -9,18 +8,16 @@
       background-color: blue;
       animation-duration: 0.2s;
     }
-    
+
     @keyframes move {
       from { transform: translate(0px, 0px); }
       to { transform: translate(100px, 0px); }
     }
   </style>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
   <script type="text/javascript" charset="utf-8">
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-
+    var test = async_test("Tests element removal and hiding within the animationend event handler. Should not crash");
     var numDone = 0;
     function animationEnded()
     {
@@ -29,10 +26,7 @@
         if (window.GCController)
           GCController.collect();
 
-        document.getElementById('results').innerHTML = 'Did not crash, so PASSED';
-
-        if (window.testRunner)
-          testRunner.notifyDone();
+        test.done();
       }
     }
 
@@ -52,18 +46,11 @@
       }, false);
       box2.style.animationName = 'move';
     }
-    
-    window.addEventListener('load', startTest, false);
+
+    window.addEventListener('load', test.step_func(startTest), false);
   </script>
 </head>
-<body>
-
-<p>Tests element removal and hiding within the animationend event handler. Should not crash.</p>
-
 <div id="container">
   <div id="box1" class="box"></div>
   <div id="box2" class="box"></div>
 </div>
-<div id="results"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/stability/animation-iteration-event-destroy-renderer-expected.txt b/third_party/blink/web_tests/animations/stability/animation-iteration-event-destroy-renderer-expected.txt
deleted file mode 100644
index 82407d1..0000000
--- a/third_party/blink/web_tests/animations/stability/animation-iteration-event-destroy-renderer-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests element removal and hiding within the webkitAnimationIteration event handler. Should not crash.
-
-Did not crash, so PASSED
diff --git a/third_party/blink/web_tests/animations/stability/animation-iteration-event-destroy-renderer.html b/third_party/blink/web_tests/animations/stability/animation-iteration-event-destroy-renderer.html
index 089e539..0972521 100644
--- a/third_party/blink/web_tests/animations/stability/animation-iteration-event-destroy-renderer.html
+++ b/third_party/blink/web_tests/animations/stability/animation-iteration-event-destroy-renderer.html
@@ -1,4 +1,3 @@
-<html>
 <head>
   <title>Destroy and Hide Element in Animation End Event</title>
   <style type="text/css" media="screen">
@@ -16,11 +15,10 @@
       to { transform: translate(100px, 0px); }
     }
   </style>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
   <script type="text/javascript" charset="utf-8">
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
+    var test = async_test("Tests element removal and hiding within the webkitAnimationIteration event handler. Should not crash");
 
     var numDone = 0;
     function animationIterated()
@@ -30,10 +28,7 @@
         if (window.GCController)
           GCController.collect();
 
-        document.getElementById('results').innerHTML = 'Did not crash, so PASSED';
-
-        if (window.testRunner)
-          testRunner.notifyDone();
+        test.done();
       }
     }
 
@@ -53,18 +48,11 @@
       }, false);
       box2.style.webkitAnimationName = 'move';
     }
-    
-    window.addEventListener('load', startTest, false);
+
+    window.addEventListener('load', test.step_func(startTest), false);
   </script>
 </head>
-<body>
-
-<p>Tests element removal and hiding within the webkitAnimationIteration event handler. Should not crash.</p>
-
 <div id="container">
   <div id="box1" class="box"></div>
   <div id="box2" class="box"></div>
 </div>
-<div id="results"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/stability/animation-name-none-expected.txt b/third_party/blink/web_tests/animations/stability/animation-name-none-expected.txt
deleted file mode 100644
index 026d078..0000000
--- a/third_party/blink/web_tests/animations/stability/animation-name-none-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This tests setting animation-name to none, it passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/animation-name-none.html b/third_party/blink/web_tests/animations/stability/animation-name-none.html
index 9a3d87ed..027c79eb 100644
--- a/third_party/blink/web_tests/animations/stability/animation-name-none.html
+++ b/third_party/blink/web_tests/animations/stability/animation-name-none.html
@@ -8,15 +8,11 @@
       animation-name: test;
     }
   </style>
-  <script>
-    if (window.testRunner)
-        testRunner.dumpAsText();
-  </script>
 </head>
-<body>
-<div id="test">This tests setting animation-name to none, it passes if it does not crash.</div>
+<div id="test"></div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-  document.querySelector('#test').style.animationName = 'none'
+  document.querySelector('#test').style.animationName = 'none';
+  done();
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/stability/animation-on-inline-crash-expected.txt b/third_party/blink/web_tests/animations/stability/animation-on-inline-crash-expected.txt
deleted file mode 100644
index b6660ecf..0000000
--- a/third_party/blink/web_tests/animations/stability/animation-on-inline-crash-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Test passes if it does not crash.
-
-Hello world
diff --git a/third_party/blink/web_tests/animations/stability/animation-on-inline-crash.html b/third_party/blink/web_tests/animations/stability/animation-on-inline-crash.html
index 62d3d909..2311212 100644
--- a/third_party/blink/web_tests/animations/stability/animation-on-inline-crash.html
+++ b/third_party/blink/web_tests/animations/stability/animation-on-inline-crash.html
@@ -1,6 +1,6 @@
 <style>
     .box {
-      position: relative; 
+      position: relative;
       animation-delay: 5ms;
       animation-name: anim;
     }
@@ -8,20 +8,15 @@
       from { transform: translateX(10px); }
     }
 </style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script type="text/javascript" charset="utf-8">
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-    
+    var test = async_test("Test passes if it does not crash when inline node has animation");
+
     function waitForAnimation()
     {
-        window.setTimeout(function() {
-            if (window.testRunner)
-                testRunner.notifyDone();
-        }, 50);
+        test.step_timeout(test.step_func_done(() => {}), 50);
     }
-    window.addEventListener('load', waitForAnimation, false);
+    window.addEventListener('load', test.step_func(waitForAnimation), false);
 </script>
-<p>Test passes if it does not crash.</p>
 <span class="box">Hello world</span>
diff --git a/third_party/blink/web_tests/animations/stability/animation-start-event-destroy-renderer-expected.txt b/third_party/blink/web_tests/animations/stability/animation-start-event-destroy-renderer-expected.txt
deleted file mode 100644
index 16a6835a..0000000
--- a/third_party/blink/web_tests/animations/stability/animation-start-event-destroy-renderer-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests element removal and hiding within the animationstart event handler. Should not crash.
-
-Did not crash, so PASSED
diff --git a/third_party/blink/web_tests/animations/stability/animation-start-event-destroy-renderer.html b/third_party/blink/web_tests/animations/stability/animation-start-event-destroy-renderer.html
index b914d32..a1075fef 100644
--- a/third_party/blink/web_tests/animations/stability/animation-start-event-destroy-renderer.html
+++ b/third_party/blink/web_tests/animations/stability/animation-start-event-destroy-renderer.html
@@ -1,4 +1,3 @@
-<html>
 <head>
   <title>Destroy and Hide Element in Animation End Event</title>
   <style type="text/css" media="screen">
@@ -9,17 +8,16 @@
       background-color: blue;
       animation-duration: 0.2s;
     }
-    
+
     @keyframes move {
       from { transform: translate(0px, 0px); }
       to { transform: translate(100px, 0px); }
     }
   </style>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
   <script type="text/javascript" charset="utf-8">
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
+    var test = async_test("Tests element removal and hiding within the animationstart event handler. Should not crash");
 
     var numDone = 0;
     function animationStarted()
@@ -29,10 +27,7 @@
         if (window.GCController)
           GCController.collect();
 
-        document.getElementById('results').innerHTML = 'Did not crash, so PASSED';
-
-        if (window.testRunner)
-          testRunner.notifyDone();
+        test.done();
       }
     }
 
@@ -52,18 +47,12 @@
       }, false);
       box2.style.animationName = 'move';
     }
-    
-    window.addEventListener('load', startTest, false);
+
+    window.addEventListener('load', test.step_func(startTest), false);
   </script>
 </head>
-<body>
-
-<p>Tests element removal and hiding within the animationstart event handler. Should not crash.</p>
-
 <div id="container">
   <div id="box1" class="box"></div>
   <div id="box2" class="box"></div>
 </div>
 <div id="results"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/stability/background-shorthand-crash-expected.txt b/third_party/blink/web_tests/animations/stability/background-shorthand-crash-expected.txt
deleted file mode 100644
index 654ddf7f..0000000
--- a/third_party/blink/web_tests/animations/stability/background-shorthand-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/background-shorthand-crash.html b/third_party/blink/web_tests/animations/stability/background-shorthand-crash.html
index 3d01c87..cda7aaf 100644
--- a/third_party/blink/web_tests/animations/stability/background-shorthand-crash.html
+++ b/third_party/blink/web_tests/animations/stability/background-shorthand-crash.html
@@ -9,13 +9,9 @@
     to { background: url('a'), url('b'); }
 }
 </style>
-<pre>This test passes if it does not crash.</pre>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-    requestAnimationFrame(function () {
-        testRunner.notifyDone();
-    });
-}
+var test = async_test("Test passes if it does not crash with background shorthand");
+requestAnimationFrame(test.step_func_done(() => {}));
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/base-render-style-body-crash-expected.txt b/third_party/blink/web_tests/animations/stability/base-render-style-body-crash-expected.txt
deleted file mode 100644
index 36ef5be8..0000000
--- a/third_party/blink/web_tests/animations/stability/base-render-style-body-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-Pass if no crash or assert
diff --git a/third_party/blink/web_tests/animations/stability/base-render-style-body-crash.html b/third_party/blink/web_tests/animations/stability/base-render-style-body-crash.html
index bbd66a10..e248731c 100644
--- a/third_party/blink/web_tests/animations/stability/base-render-style-body-crash.html
+++ b/third_party/blink/web_tests/animations/stability/base-render-style-body-crash.html
@@ -4,24 +4,20 @@
 .green { background-color: green }
 </style>
 <style id="sheet"></style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner) {
-    testRunner.waitUntilDone();
-    testRunner.dumpAsText();
-}
+var test = async_test("Test passes if it does not crash");
 
-onload = function(){
+onload = test.step_func(() => {
     document.body.className = "green";
     // Needs these frames to establish a baseComputedStyle.
-    requestAnimationFrame(function(){
-        requestAnimationFrame(function(){
-            requestAnimationFrame(function(){
+    requestAnimationFrame(test.step_func(() => {
+        requestAnimationFrame(test.step_func(() => {
+            requestAnimationFrame(test.step_func_done(() => {
                 sheet.innerText = "@font-face { font-family: notfound; src: url(notfound.ttf) }";
-                if (window.testRunner)
-                    testRunner.notifyDone();
-            });
-        });
-    });
-};
+            }));
+        }));
+    }));
+});
 </script>
-<p>Pass if no crash or assert</p>
diff --git a/third_party/blink/web_tests/animations/stability/body-removal-crash-expected.txt b/third_party/blink/web_tests/animations/stability/body-removal-crash-expected.txt
deleted file mode 100644
index 3bd76f7..0000000
--- a/third_party/blink/web_tests/animations/stability/body-removal-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This should not crash
diff --git a/third_party/blink/web_tests/animations/stability/body-removal-crash.html b/third_party/blink/web_tests/animations/stability/body-removal-crash.html
index f628ecab..0784e277 100644
--- a/third_party/blink/web_tests/animations/stability/body-removal-crash.html
+++ b/third_party/blink/web_tests/animations/stability/body-removal-crash.html
@@ -22,7 +22,10 @@
 </body>
 </html>
 
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
+var test = async_test("Tests if there is no crash when body is removed and added to a different location.");
 
 var element;
 
@@ -33,19 +36,11 @@
     element = document.body;
     element.parentNode.removeChild(element);
     document.getElementById("a").parentNode.insertBefore(element, document.getElementById("a").nextSibling);
-    setTimeout(cleanup, 0);
+    test.step_timeout(test.step_func_done(cleanup), 0);
 }
 
 function cleanup() {
   document.getElementById("b").parentNode.insertBefore(element, document.getElementById("b").nextSibling);
-  
-  if (window.testRunner)
-      testRunner.notifyDone();
-}
-
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
 }
 
 crash();
diff --git a/third_party/blink/web_tests/animations/stability/deleted-image-set-transition-crash-expected.txt b/third_party/blink/web_tests/animations/stability/deleted-image-set-transition-crash-expected.txt
deleted file mode 100644
index 654ddf7f..0000000
--- a/third_party/blink/web_tests/animations/stability/deleted-image-set-transition-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/deleted-image-set-transition-crash.html b/third_party/blink/web_tests/animations/stability/deleted-image-set-transition-crash.html
index 6b5982c..12324e7 100644
--- a/third_party/blink/web_tests/animations/stability/deleted-image-set-transition-crash.html
+++ b/third_party/blink/web_tests/animations/stability/deleted-image-set-transition-crash.html
@@ -4,15 +4,12 @@
 div { background: -webkit-image-set(url(#) 1x); }
 </style>
 <div style="transition: 1s">This test passes if it does not crash.</div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-window.addEventListener('load', function() {
+var test = async_test("Test if it does not crash when it deletes image-set");
+
+window.addEventListener('load', test.step_func_done(() => {
   document.styleSheets[0].deleteRule(1);
-  if (window.testRunner) {
-    testRunner.notifyDone();
-  }
-});
-</script>
\ No newline at end of file
+}));
+</script>
diff --git a/third_party/blink/web_tests/animations/stability/element-animate-float-crash-expected.txt b/third_party/blink/web_tests/animations/stability/element-animate-float-crash-expected.txt
deleted file mode 100644
index 654ddf7f..0000000
--- a/third_party/blink/web_tests/animations/stability/element-animate-float-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/element-animate-float-crash.html b/third_party/blink/web_tests/animations/stability/element-animate-float-crash.html
index 336430d..5bdd790 100644
--- a/third_party/blink/web_tests/animations/stability/element-animate-float-crash.html
+++ b/third_party/blink/web_tests/animations/stability/element-animate-float-crash.html
@@ -3,16 +3,14 @@
 <textarea></textarea>
 <ul></ul>
 <embed>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
+var test = async_test("Test if it does not crash when element is animated with float");
+
 $ = document.querySelector.bind(document);
 $('embed').animate([], 0);
 $('ul').remove();
 $('textarea').animate([{float: 'left'}, {float: 'left'}], {duration: 1, fill: 'forwards'});
-if (window.testRunner) {
-  testRunner.waitUntilDone();
-  testRunner.dumpAsText();
-  requestAnimationFrame(function() {
-    testRunner.notifyDone();
-  });
-}
+requestAnimationFrame(test.step_func_done(() => {}));
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/element-animate-font-style-crash-expected.txt b/third_party/blink/web_tests/animations/stability/element-animate-font-style-crash-expected.txt
deleted file mode 100644
index 654ddf7f..0000000
--- a/third_party/blink/web_tests/animations/stability/element-animate-font-style-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/element-animate-font-style-crash.html b/third_party/blink/web_tests/animations/stability/element-animate-font-style-crash.html
index 3db74bd4..df7e542 100644
--- a/third_party/blink/web_tests/animations/stability/element-animate-font-style-crash.html
+++ b/third_party/blink/web_tests/animations/stability/element-animate-font-style-crash.html
@@ -1,11 +1,9 @@
 <div id="target">This test passes if it does not crash.</div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
+var test = async_test("Test if it does not crash when element is animated with fontStyle");
+
 target.animate([{fontStyle: "oblique"}, {fontStyle: "oblique"}], 1000);
-if (window.testRunner) {
-  testRunner.waitUntilDone();
-  testRunner.dumpAsText();
-  requestAnimationFrame(function() {
-    testRunner.notifyDone();
-  });
-}
+requestAnimationFrame(test.step_func_done(() => {}));
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/element-animate-position-crash-expected.txt b/third_party/blink/web_tests/animations/stability/element-animate-position-crash-expected.txt
deleted file mode 100644
index 7ef22e9..0000000
--- a/third_party/blink/web_tests/animations/stability/element-animate-position-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-PASS
diff --git a/third_party/blink/web_tests/animations/stability/element-animate-position-crash.html b/third_party/blink/web_tests/animations/stability/element-animate-position-crash.html
index be5fc2a..a717696 100644
--- a/third_party/blink/web_tests/animations/stability/element-animate-position-crash.html
+++ b/third_party/blink/web_tests/animations/stability/element-animate-position-crash.html
@@ -4,16 +4,13 @@
 <div id="div2"></div>
 <div id="div3"></div>
 <embed id="embed"></embed>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
+var test = async_test("Test if it does not crash when element is animated with position");
+
 try{embed.appendChild(null);}catch(e){}
 iframe.animate([{"position":"fixed"}, {"position":"static"}], {duration: 1, fill: 'forwards'});
 div3.appendChild(div1);
-if (window.testRunner) {
-  testRunner.waitUntilDone();
-  testRunner.dumpAsText();
-  requestAnimationFrame(function() {
-    document.documentElement.textContent = 'PASS';
-    testRunner.notifyDone();
-  });
-}
+requestAnimationFrame(test.step_func_done(() => {}));
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/empty-keyframe-animation-composited-expected.txt b/third_party/blink/web_tests/animations/stability/empty-keyframe-animation-composited-expected.txt
deleted file mode 100644
index 00f0936..0000000
--- a/third_party/blink/web_tests/animations/stability/empty-keyframe-animation-composited-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests an animation with no keyframes, applied to an element which is composited.
-
-This test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/animations/stability/empty-keyframe-animation-composited.html b/third_party/blink/web_tests/animations/stability/empty-keyframe-animation-composited.html
index ed10046e..1a567b41 100644
--- a/third_party/blink/web_tests/animations/stability/empty-keyframe-animation-composited.html
+++ b/third_party/blink/web_tests/animations/stability/empty-keyframe-animation-composited.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 
+<title>Tests an animation with no keyframes, applied to an element which is composited</title>
 <style>
 p {
   transform: rotateX(0deg);
@@ -9,10 +10,8 @@
 }
 </style>
 
-<p>Tests an animation with no keyframes, applied to an element which is composited.
-<p>This test passes if it doesn't crash.
-
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
-</script>
\ No newline at end of file
+done();
+</script>
diff --git a/third_party/blink/web_tests/animations/stability/empty-keyframes-composited-expected.txt b/third_party/blink/web_tests/animations/stability/empty-keyframes-composited-expected.txt
deleted file mode 100644
index e313c54..0000000
--- a/third_party/blink/web_tests/animations/stability/empty-keyframes-composited-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests an animation where all keyframes are empty, applied to an element which is composited.
-
-This test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/animations/stability/empty-keyframes-composited.html b/third_party/blink/web_tests/animations/stability/empty-keyframes-composited.html
index 3857f85..b8fcb0c 100644
--- a/third_party/blink/web_tests/animations/stability/empty-keyframes-composited.html
+++ b/third_party/blink/web_tests/animations/stability/empty-keyframes-composited.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-
+<title>Tests an animation where all keyframes are empty, applied to an element which is composited</title>
 <style>
 p {
   transform: rotateX(0deg);
@@ -11,10 +11,8 @@
 }
 </style>
 
-<p>Tests an animation where all keyframes are empty, applied to an element which is composited.
-<p>This test passes if it doesn't crash.
-
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+done();
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/empty-keyframes-expected.txt b/third_party/blink/web_tests/animations/stability/empty-keyframes-expected.txt
deleted file mode 100644
index 7a1435c..0000000
--- a/third_party/blink/web_tests/animations/stability/empty-keyframes-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test for empty keyframes rule. Should not crash
diff --git a/third_party/blink/web_tests/animations/stability/empty-keyframes.html b/third_party/blink/web_tests/animations/stability/empty-keyframes.html
index 492481bd..f262652 100644
--- a/third_party/blink/web_tests/animations/stability/empty-keyframes.html
+++ b/third_party/blink/web_tests/animations/stability/empty-keyframes.html
@@ -4,7 +4,7 @@
 <html lang="en">
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-  <title>Empty keyframes</title>
+  <title>Test for empty keyframes rule. Should not crash</title>
   <style type="text/css" media="screen">
     #box {
       animation-name: test, test-one;
@@ -17,14 +17,12 @@
       0% {}
     }
   </style>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
   <script type="text/javascript" charset="utf-8">
-    if (window.testRunner)
-        testRunner.dumpAsText();
+    done();
   </script>
 </head>
-<body>
-  <p>Test for empty keyframes rule. Should not crash</p>
 <div id="box">
 </div>
-</body>
 </html>
diff --git a/third_party/blink/web_tests/animations/stability/font-builder-crash-expected.txt b/third_party/blink/web_tests/animations/stability/font-builder-crash-expected.txt
deleted file mode 100644
index 654ddf7f..0000000
--- a/third_party/blink/web_tests/animations/stability/font-builder-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/font-builder-crash.html b/third_party/blink/web_tests/animations/stability/font-builder-crash.html
index 77c7d25..2c5fb57 100644
--- a/third_party/blink/web_tests/animations/stability/font-builder-crash.html
+++ b/third_party/blink/web_tests/animations/stability/font-builder-crash.html
@@ -1,17 +1,12 @@
 <!DOCTYPE html>
 <div id="target">This test passes if it does not crash.</div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
+var test = async_test("Test if it does not crash when element is animated with fontSize and fontWeight");
 target.animate([
   {fontSize: 'large', fontWeight: 'normal'},
   {fontSize: 'small', fontWeight: 'bold'},
 ], 1);
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-requestAnimationFrame(function() {
-    if (window.testRunner) {
-        testRunner.notifyDone();
-    }
-});
+requestAnimationFrame(test.step_func_done(() => {}));
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/import-crash-expected.txt b/third_party/blink/web_tests/animations/stability/import-crash-expected.txt
deleted file mode 100644
index adaa301..0000000
--- a/third_party/blink/web_tests/animations/stability/import-crash-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This test simply loads a sheet using @import that contains keyframes, to see if https://bugs.webkit.org/show_bug.cgi?id=20855 is fixed.
-
-It passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/import-crash.html b/third_party/blink/web_tests/animations/stability/import-crash.html
index 317a86c..064d8b3 100644
--- a/third_party/blink/web_tests/animations/stability/import-crash.html
+++ b/third_party/blink/web_tests/animations/stability/import-crash.html
@@ -19,14 +19,14 @@
         animation-name: anim;
     }
     </style>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
     <script type="text/javascript" charset="utf-8">
-    if (window.testRunner)
-        testRunner.dumpAsText();
+    done();
   </script>
 </head>
 <body>
   <p>This test simply loads a sheet using @import that contains keyframes, to see if https://bugs.webkit.org/show_bug.cgi?id=20855
 is fixed.
-  <p>It passes if it does not crash.
 </body>
 </html>
diff --git a/third_party/blink/web_tests/animations/stability/inherit-crash-expected.txt b/third_party/blink/web_tests/animations/stability/inherit-crash-expected.txt
deleted file mode 100644
index 654ddf7f..0000000
--- a/third_party/blink/web_tests/animations/stability/inherit-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/inherit-crash.html b/third_party/blink/web_tests/animations/stability/inherit-crash.html
index 1a3a670..57408aa 100644
--- a/third_party/blink/web_tests/animations/stability/inherit-crash.html
+++ b/third_party/blink/web_tests/animations/stability/inherit-crash.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<title>Test if it doesn't crash when keyframes has 'background-color:inherit'</title>
 <style>
 @keyframes test {
     to { background-color: inherit; }
@@ -7,8 +8,8 @@
     animation: test 1s;
 }
 </style>
-<pre>This test passes if it does not crash.</pre>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+done();
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/keyframe-timing-function-unset-crash-expected.txt b/third_party/blink/web_tests/animations/stability/keyframe-timing-function-unset-crash-expected.txt
deleted file mode 100644
index 29853939..0000000
--- a/third_party/blink/web_tests/animations/stability/keyframe-timing-function-unset-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it doesn't crash
diff --git a/third_party/blink/web_tests/animations/stability/keyframe-timing-function-unset-crash.html b/third_party/blink/web_tests/animations/stability/keyframe-timing-function-unset-crash.html
index ce5e7f7..338408e 100644
--- a/third_party/blink/web_tests/animations/stability/keyframe-timing-function-unset-crash.html
+++ b/third_party/blink/web_tests/animations/stability/keyframe-timing-function-unset-crash.html
@@ -1,5 +1,5 @@
 <!doctype html>
-
+<title>Test if it doesn't crash when keyframes has 'animation-timing-function:unset'</title>
 <style>
 @keyframes anim {
     from { animation-timing-function: unset; }
@@ -10,7 +10,8 @@
 
 <div style="animation: anim 10s">This test passes if it doesn't crash</div>
 
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-  testRunner.dumpAsText();
+done();
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/keyframeeffect-no-target-crash-expected.txt b/third_party/blink/web_tests/animations/stability/keyframeeffect-no-target-crash-expected.txt
deleted file mode 100644
index 654ddf7f..0000000
--- a/third_party/blink/web_tests/animations/stability/keyframeeffect-no-target-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/keyframeeffect-no-target-crash.html b/third_party/blink/web_tests/animations/stability/keyframeeffect-no-target-crash.html
index e411077..3a87cb49 100644
--- a/third_party/blink/web_tests/animations/stability/keyframeeffect-no-target-crash.html
+++ b/third_party/blink/web_tests/animations/stability/keyframeeffect-no-target-crash.html
@@ -1,15 +1,13 @@
 <div id="target">This test passes if it does not crash.</div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
+  var test = async_test("Test if it does not crash when KeyframeEffect has no target");
+
   let effect = new KeyframeEffect(null, null, {duration: 1000});
   let animation = new Animation(effect);
 
-  if (window.testRunner) {
-    testRunner.waitUntilDone();
-    testRunner.dumpAsText();
-    requestAnimationFrame(function() {
-      testRunner.notifyDone();
-    });
-  }
+  requestAnimationFrame(test.step_func_done(() => {}));
 </script>
 <style>
 @keyframes frame { }
diff --git a/third_party/blink/web_tests/animations/stability/option-element-crash-expected.txt b/third_party/blink/web_tests/animations/stability/option-element-crash-expected.txt
deleted file mode 100644
index 80dd71a..0000000
--- a/third_party/blink/web_tests/animations/stability/option-element-crash-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-CONSOLE WARNING: line 24: Invalid keyframe value for property outlineColor: invert
-This test passes if it does not crash.
- 
diff --git a/third_party/blink/web_tests/animations/stability/option-element-crash.html b/third_party/blink/web_tests/animations/stability/option-element-crash.html
index aa9f04b..3c22769 100644
--- a/third_party/blink/web_tests/animations/stability/option-element-crash.html
+++ b/third_party/blink/web_tests/animations/stability/option-element-crash.html
@@ -1,5 +1,4 @@
-This test passes if it does not crash.
-
+<title>Test if it doesn't crash when option is animated</title>
 <object>
   <div>
     <option id="testA"></option>
@@ -16,10 +15,13 @@
   </object>
 </video>
 
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-  testRunner.dumpAsText();
 testA.animate([{fontSize: 'large'}, {fontSize: '24px'}], 1000);
 testB.animate([{fontSize: '6rem'}, {fontSize: 'x-large'}], 1000);
-testC.animate([{outlineColor: 'invert'}, {outlineColor: 'inherit'}], 1000);
-</script>
\ No newline at end of file
+try {
+  testC.animate([{outlineColor: 'invert'}, {outlineColor: 'inherit'}], 1000);
+} catch (e) {}
+done();
+</script>
diff --git a/third_party/blink/web_tests/animations/stability/pause-crash-expected.txt b/third_party/blink/web_tests/animations/stability/pause-crash-expected.txt
deleted file mode 100644
index c02ad594..0000000
--- a/third_party/blink/web_tests/animations/stability/pause-crash-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests pause and resume animation. Should not crash. (https://bugs.webkit.org/show_bug.cgi?id=67510)
-
-Did not crash, so PASSED
diff --git a/third_party/blink/web_tests/animations/stability/pause-crash.html b/third_party/blink/web_tests/animations/stability/pause-crash.html
index 44d227f..e102ca9 100644
--- a/third_party/blink/web_tests/animations/stability/pause-crash.html
+++ b/third_party/blink/web_tests/animations/stability/pause-crash.html
@@ -1,4 +1,3 @@
-<html>
 <head>
   <title>Pause and resume animation should not crash</title>
   <style type="text/css" media="screen">
@@ -11,49 +10,36 @@
       animation-direction: alternate;
       animation-iteration-count: infinite;
     }
-    
+
     @keyframes anim {
         from { transform: matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); }
         to   { transform: matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, 400,0,0,1); }
     }
   </style>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
   <script type="text/javascript" charset="utf-8">
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-
+    var test = async_test("Tests pause and resume animation. Should not crash. (https://bugs.webkit.org/show_bug.cgi?id=67510)");
     function animationStarted()
     {
-        setTimeout(function() {
+        test.step_timeout(test.step_func(() => {
             document.getElementById('box1').style.animationPlayState = "paused";
-            setTimeout(function() {
+            test.step_timeout(test.step_func(() => {
                 document.getElementById('box1').style.animationPlayState = "running";
-                setTimeout(function() {
-                    document.getElementById('results').innerHTML = 'Did not crash, so PASSED';
-                    if (window.testRunner)
-                        testRunner.notifyDone();
-                }, 50);
-            }, 50);
-        }, 50);
+                test.step_timeout(test.step_func_done(() => {}, 50));
+            }, 50));
+        }, 50));
     }
-    
+
     function startTest()
     {
         document.getElementById('box1').addEventListener('animationstart', animationStarted);
         document.getElementById('box1').style.animationName = "anim";
     }
 
-    window.addEventListener('load', startTest, false);
+    window.addEventListener('load', test.step_func(startTest), false);
   </script>
 </head>
-<body>
-
-<p>Tests pause and resume animation. Should not crash. (https://bugs.webkit.org/show_bug.cgi?id=67510)</p>
-
 <div id="container">
   <div id="box1" class="box"></div>
 </div>
-<div id="results"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-color-crash-expected.txt b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-color-crash-expected.txt
deleted file mode 100644
index d136637..0000000
--- a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-color-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-color-crash.html b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-color-crash.html
index ce81c838..8c9bd0a2 100644
--- a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-color-crash.html
+++ b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-color-crash.html
@@ -1,11 +1,12 @@
+<title>Test if it doesn't crash when pseudo element has animation with color</title>
 <style>
 @keyframes A { 0% { color: red; } }
 a:before, b:before { animation-name: A; }
 </style>
 <a href="#"><b></b></a>
 
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+done();
 </script>
-Test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-marker-crash-expected.txt b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-marker-crash-expected.txt
deleted file mode 100644
index d136637..0000000
--- a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-marker-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-marker-crash.html b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-marker-crash.html
index 4b673631..7f8aeb7 100644
--- a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-marker-crash.html
+++ b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-marker-crash.html
@@ -1,9 +1,10 @@
+<title>Test if it doesn't crash when pseudo element has animation with marker</title>
 <style>
 @keyframes test { 0% { marker: url("crash"); } }
 body:before { animation-name: test; }
 </style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+done();
 </script>
-Test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-rems-expected.txt b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-rems-expected.txt
deleted file mode 100644
index 654ddf7f..0000000
--- a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-rems-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash.
diff --git a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-rems.html b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-rems.html
index e2644a4..b2b9d1af 100644
--- a/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-rems.html
+++ b/third_party/blink/web_tests/animations/stability/pseudo-element-animation-with-rems.html
@@ -1,9 +1,9 @@
-<html>
 <head>
+  <title>Test if it doesn't crash when pseudo element has animation with rems unit</title>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
   <script>
-  if (window.testRunner) {
-    testRunner.dumpAsText();
-  }
+  done();
   </script>
   <style>
   @-webkit-keyframes anim {
@@ -16,7 +16,3 @@
   }
   </style>
 </head>
-<body>
-This test passes if it does not crash.
-</body>
-</html>
diff --git a/third_party/blink/web_tests/animations/stability/resource-loading-expected.txt b/third_party/blink/web_tests/animations/stability/resource-loading-expected.txt
deleted file mode 100644
index 4788690..0000000
--- a/third_party/blink/web_tests/animations/stability/resource-loading-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes if it does not crash. Newly referenced resources in the Web Animations api should be resolved in the style building stage.
diff --git a/third_party/blink/web_tests/animations/stability/resource-loading.html b/third_party/blink/web_tests/animations/stability/resource-loading.html
index 56f5d13..c3547d43 100644
--- a/third_party/blink/web_tests/animations/stability/resource-loading.html
+++ b/third_party/blink/web_tests/animations/stability/resource-loading.html
@@ -6,19 +6,13 @@
 }
 </style>
 <div id='target'></div>
-This test passes if it does not crash. Newly referenced resources in the Web Animations api should be resolved in the style building stage.
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
+var test = async_test("This test passes if it does not crash. Newly referenced resources in the Web Animations api should be resolved in the style building stage");
 target.animate([
     {backgroundImage: 'url(../../animations/resources/blue-100.png)', color: 'blue'},
     {backgroundImage: 'url(../../animations/resources/green-100.png)', color: 'green'},
   ], {duration: 1, fill: 'forwards'});
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-requestAnimationFrame(function() {
-    if (window.testRunner) {
-        testRunner.notifyDone();
-    }
-});
+requestAnimationFrame(test.step_func_done(() => {}));
 </script>
diff --git a/third_party/blink/web_tests/animations/stability/zero-duration-infinite-iterations-expected.txt b/third_party/blink/web_tests/animations/stability/zero-duration-infinite-iterations-expected.txt
deleted file mode 100644
index 4708acc..0000000
--- a/third_party/blink/web_tests/animations/stability/zero-duration-infinite-iterations-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This tests an animation with zero duration and infinite iterations. See http:://crbug.com/322575.
-
-This test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/animations/stability/zero-duration-infinite-iterations.html b/third_party/blink/web_tests/animations/stability/zero-duration-infinite-iterations.html
index b1ca038..8c522a3 100644
--- a/third_party/blink/web_tests/animations/stability/zero-duration-infinite-iterations.html
+++ b/third_party/blink/web_tests/animations/stability/zero-duration-infinite-iterations.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<title>This tests an animation with zero duration and infinite iterations. See http:://crbug.com/322575</title>
 <style>
 p {
   animation: test infinite;
@@ -8,11 +9,8 @@
   }
 }
 </style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-  if (window.testRunner)
-    testRunner.dumpAsText();
+done();
 </script>
-<body>
-<p>This tests an animation with zero duration and infinite iterations. See http:://crbug.com/322575.
-<p>This test passes if it doesn't crash.
-<body
\ No newline at end of file
diff --git a/third_party/blink/web_tests/animations/stability/zero-duration-large-start-delay-expected.txt b/third_party/blink/web_tests/animations/stability/zero-duration-large-start-delay-expected.txt
deleted file mode 100644
index 99e3d96..0000000
--- a/third_party/blink/web_tests/animations/stability/zero-duration-large-start-delay-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This tests an animation with zero duration and a very large start delay. See http:://crbug.com/324323.
-
-This test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/animations/stability/zero-duration-large-start-delay.html b/third_party/blink/web_tests/animations/stability/zero-duration-large-start-delay.html
index 050d0e3..a045f655 100644
--- a/third_party/blink/web_tests/animations/stability/zero-duration-large-start-delay.html
+++ b/third_party/blink/web_tests/animations/stability/zero-duration-large-start-delay.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<title>This tests an animation with zero duration and a very large start delay. See http:://crbug.com/324323</title>
 <style>
 p {
   animation-name: test;
@@ -11,11 +12,8 @@
   }
 }
 </style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-  if (window.testRunner)
-    testRunner.dumpAsText();
+done();
 </script>
-<body>
-<p>This tests an animation with zero duration and a very large start delay. See http:://crbug.com/324323.
-<p>This test passes if it doesn't crash.
-<body
\ No newline at end of file
diff --git a/third_party/blink/web_tests/animations/stability/zoomed-length-crash-expected.txt b/third_party/blink/web_tests/animations/stability/zoomed-length-crash-expected.txt
deleted file mode 100644
index c2541f4..0000000
--- a/third_party/blink/web_tests/animations/stability/zoomed-length-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-PASS if no crash.
diff --git a/third_party/blink/web_tests/animations/stability/zoomed-length-crash.html b/third_party/blink/web_tests/animations/stability/zoomed-length-crash.html
index a10f7d366..3e58a79 100644
--- a/third_party/blink/web_tests/animations/stability/zoomed-length-crash.html
+++ b/third_party/blink/web_tests/animations/stability/zoomed-length-crash.html
@@ -9,16 +9,12 @@
 }
 * { zoom: 6318030279180000000; }
 </style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id=target></div>
-<p>PASS if no crash.</p>
 <script>
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-target.addEventListener('animationstart', function() {
+var test = async_test("Test if it does not crash when it has zoom");
+target.addEventListener('animationstart', test.step_func_done(() => {
   getComputedStyle(target).left;
-  if (window.testRunner)
-    testRunner.notifyDone();
-});
+}));
 </script>
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 33b8844..8687dd9 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
@@ -5893,36 +5893,6 @@
      {}
     ]
    ],
-   "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html": [
-    [
-     "/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html": [
-    [
-     "/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html": [
-    [
-     "/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html": [
-    [
-     "/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html": [
-    [
-     "/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html",
-     {}
-    ]
-   ],
    "pointerevents/pointerevent_touch-action-keyboard-manual.html": [
     [
      "/pointerevents/pointerevent_touch-action-keyboard-manual.html",
@@ -60689,6 +60659,18 @@
      {}
     ]
    ],
+   "css/css-tables/toggle-row-display-property-001.html": [
+    [
+     "/css/css-tables/toggle-row-display-property-001.html",
+     [
+      [
+       "/css/css-tables/toggle-row-display-property-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-tables/visibility-collapse-colspan-003.html": [
     [
      "/css/css-tables/visibility-collapse-colspan-003.html",
@@ -119087,6 +119069,11 @@
      {}
     ]
    ],
+   "common/echo.py": [
+    [
+     {}
+    ]
+   ],
    "common/entities.json": [
     [
      {}
@@ -144687,6 +144674,11 @@
      {}
     ]
    ],
+   "css/css-tables/toggle-row-display-property-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-tables/tools/markup-generator.html": [
     [
      {}
@@ -162282,11 +162274,6 @@
      {}
     ]
    ],
-   "feature-policy/reporting/legacy-image-formats-reporting.html.headers": [
-    [
-     {}
-    ]
-   ],
    "feature-policy/reporting/microphone-report-only.https.html.headers": [
     [
      {}
@@ -166187,6 +166174,11 @@
      {}
     ]
    ],
+   "html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/named-access-on-the-window-object/test.html": [
     [
      {}
@@ -245449,12 +245441,6 @@
      {}
     ]
    ],
-   "feature-policy/reporting/legacy-image-formats-reporting.html": [
-    [
-     "/feature-policy/reporting/legacy-image-formats-reporting.html",
-     {}
-    ]
-   ],
    "feature-policy/reporting/microphone-report-only.https.html": [
     [
      "/feature-policy/reporting/microphone-report-only.https.html",
@@ -249377,6 +249363,12 @@
      {}
     ]
    ],
+   "html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window.js": [
+    [
+     "/html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window.html",
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html": [
     [
      "/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html",
@@ -277150,6 +277142,38 @@
      {}
     ]
    ],
+   "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html": [
+    [
+     "/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/pointerevent_touch-action-inherit_child-none_touch.html": [
+    [
+     "/pointerevents/pointerevent_touch-action-inherit_child-none_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html": [
+    [
+     "/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html": [
+    [
+     "/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html": [
     [
      "/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html",
@@ -277158,6 +277182,14 @@
      }
     ]
    ],
+   "pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html": [
+    [
+     "/pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "pointerevents/pointerevent_touch-action-pan-x-pan-y_touch.html": [
     [
      "/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch.html",
@@ -322742,6 +322774,10 @@
    "4a60c3035fcc3617de38a514159a281e2422b067",
    "support"
   ],
+  "common/echo.py": [
+   "2ee403645b1bb27cdb27bcea716e166729b81af8",
+   "support"
+  ],
   "common/entities.json": [
    "8a1f590a6abe4872d3b8b4c665d9b165d7dce84d",
    "support"
@@ -325227,7 +325263,7 @@
    "support"
   ],
   "content-security-policy/securitypolicyviolation/idlharness.window.js": [
-   "fc5e65d6cfdc59fb8bd3c10e3ed358d5b7f8074d",
+   "25efd0d4e1f5224cda5a74457e801d84777bbcb0",
    "testharness"
   ],
   "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html": [
@@ -372502,6 +372538,14 @@
    "13af8b9db4e70af3b1b9a3fa80ff8770cb5ba7c7",
    "testharness"
   ],
+  "css/css-tables/toggle-row-display-property-001-ref.html": [
+   "a99f69eb4498ae55312122d51ea518327cdf9e12",
+   "support"
+  ],
+  "css/css-tables/toggle-row-display-property-001.html": [
+   "08e6635e12c42a4201ca955722227010834883e8",
+   "reftest"
+  ],
   "css/css-tables/tools/markup-generator.html": [
    "3b37e6c5feee6453ca344e86d456fc0bd2a12343",
    "support"
@@ -412062,14 +412106,6 @@
    "c059b96d97fc3701ce4325165b79948f69189135",
    "support"
   ],
-  "feature-policy/reporting/legacy-image-formats-reporting.html": [
-   "6cd2e752eb915b984adc0552a8f792143d8e448b",
-   "testharness"
-  ],
-  "feature-policy/reporting/legacy-image-formats-reporting.html.headers": [
-   "1003c32a445d7f3dafb233e8b49839d9fa336416",
-   "support"
-  ],
   "feature-policy/reporting/microphone-report-only.https.html": [
    "539994cd70a2b5a8d598577a0d493c13346755b8",
    "testharness"
@@ -417802,6 +417838,14 @@
    "d5b1789d59455603d1f5929a7a7f05d8a7218d52",
    "testharness"
   ],
+  "html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window-expected.txt": [
+   "e08395a89affb9f921c9cae368f32c7c5444970b",
+   "support"
+  ],
+  "html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window.js": [
+   "59d94efc994e365301c20dbc5ff1b14409dfcaab",
+   "testharness"
+  ],
   "html/browsers/the-window-object/named-access-on-the-window-object/test.html": [
    "c3b3cc185255d159b0f9ff9fd97aae71170d0af6",
    "support"
@@ -435943,7 +435987,7 @@
    "support"
   ],
   "interfaces/css-font-loading.idl": [
-   "c2ef551b4ed46bd2aa172548d684034f69290aff",
+   "2bbc35a25912256fb1d56ada3372d35e59ca69e5",
    "support"
   ],
   "interfaces/css-fonts.idl": [
@@ -449007,7 +449051,7 @@
    "testharness"
   ],
   "payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html": [
-   "28dfe1e448baea444698f38a20c70ff38e9d312a",
+   "243250080bd86cab7706e34af1703877830855c5",
    "manual"
   ],
   "payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html": [
@@ -449823,7 +449867,7 @@
    "support"
   ],
   "pointerevents/pointerevent_support.js": [
-   "e8c847b12a880a557d8d3cd69bc0bc77cf3378af",
+   "dc35ea24eebc65dd3b0fe52dd54042c78959bd1d",
    "support"
   ],
   "pointerevents/pointerevent_suppress_compat_events_on_click.html": [
@@ -449846,29 +449890,29 @@
    "5fe6179840eeda9a025e951f8ff28b211da9fafe",
    "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html": [
-   "dcea2837502b82b3fc873ddf3a4b044e38165c02",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html": [
+   "ae2373c3f532fdada27c941617f8d05d0d2a7da3",
+   "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html": [
-   "16e42954e51abc58c89e608c0edfa29d9a44b63b",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_child-none_touch.html": [
+   "81f0ea6050a4b060708bcebc1eeb65d7ee904c70",
+   "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html": [
-   "c75d067e447f7382005542df6ed267850ef6aa0a",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html": [
+   "775708d4a7741d053ea20472d94bf4f936175804",
+   "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html": [
-   "d420cc56c77b6910ee96d875ee24eb0b9b0a4c71",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html": [
+   "592cfd6ae5367d2830ce3343aae7cae0e1d737a0",
+   "testharness"
   ],
   "pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html": [
    "a1fefe16982316546b2cb0a7bf14362fe21f7145",
    "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html": [
-   "5e674a14da550fb63bfe53859a8e4db529f559e8",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html": [
+   "45ea1432b4e4ad5de824bf1d1798e458a939dbc7",
+   "testharness"
   ],
   "pointerevents/pointerevent_touch-action-keyboard-manual.html": [
    "a41d7078f2ee87a8a5686379536aaf1e0de915df",
@@ -474855,7 +474899,7 @@
    "manual"
   ],
   "visual-viewport/viewport-scrollbars-cause-resize.html": [
-   "d0158c6f6259dd4181c0e8d921ebe3ecc9fa9d73",
+   "2767fcc48a3728218c5d73ad3ef60cafa7376a45",
    "testharness"
   ],
   "visual-viewport/viewport-type.html": [
@@ -479247,7 +479291,7 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-transceivers.https.html": [
-   "9b3a9a85413e2dcfdbcbbefe2b8b05a0ffd05ca0",
+   "73668e7be6ed8d98630d857657fcace9072b9aee",
    "testharness"
   ],
   "webrtc/RTCPeerConnectionIceEvent-constructor-expected.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/common/echo.py b/third_party/blink/web_tests/external/wpt/common/echo.py
new file mode 100644
index 0000000..2ee40364
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/common/echo.py
@@ -0,0 +1,6 @@
+def main(request, response):
+    # Without X-XSS-Protection to disable non-standard XSS protection the functionality this
+    # resource offers is useless
+    response.headers.set("X-XSS-Protection", "0")
+    response.headers.set("Content-Type", "text/html")
+    response.content = request.GET.first("content")
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/idlharness.window.js b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/idlharness.window.js
index fc5e65d6c..25efd0d4 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/idlharness.window.js
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/idlharness.window.js
@@ -7,7 +7,7 @@
 
 idl_test(
   ['CSP'],
-  ['dom'],
+  ['dom', 'reporting'],
   idl_array => {
     idl_array.add_objects({
       SecurityPolicyViolationEvent: [
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/legacy-image-formats-reporting.html b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/legacy-image-formats-reporting.html
deleted file mode 100644
index 6cd2e752..0000000
--- a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/legacy-image-formats-reporting.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <script src='/resources/testharness.js'></script>
-  <script src='/resources/testharnessreport.js'></script>
-</head>
-<body>
-  <img src="image.bmp">
-  <script>
-    var check_report_format = (reports, observer) => {
-      let report = reports[0];
-      assert_equals(report.type, "feature-policy-violation");
-      assert_equals(report.url, document.location.href);
-      assert_equals(report.body.featureId, "legacy-image-formats");
-      assert_equals(report.body.disposition, "enforce");
-    };
-
-    async_test(t => {
-      new ReportingObserver(t.step_func_done(check_report_format),
-        {types: ['feature-policy-violation'], buffered: true}).observe();
-    }, "Unsized-media Report Format");
-  </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/legacy-image-formats-reporting.html.headers b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/legacy-image-formats-reporting.html.headers
deleted file mode 100644
index 1003c32a..0000000
--- a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/legacy-image-formats-reporting.html.headers
+++ /dev/null
@@ -1 +0,0 @@
-Feature-Policy: legacy-image-formats 'none'
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html
index 6f0c439..b97de9e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/embed.tentative.https.sub.html
@@ -4,11 +4,14 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body>
 <script>
+  let nonce = token();
+
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "embed-same-origin";
+      let key = "embed-same-origin" + nonce;
 
       let e = document.createElement('embed');
       e.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -27,7 +30,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "embed-same-site";
+      let key = "embed-same-site" + nonce;
 
       let e = document.createElement('embed');
       e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -46,7 +49,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "embed-cross-site";
+      let key = "embed-cross-site" + nonce;
 
       let e = document.createElement('embed');
       e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/object.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/object.tentative.https.sub.html
index 2a0e8de..4749629 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/object.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/object.tentative.https.sub.html
@@ -4,11 +4,14 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body>
 <script>
+  let nonce = token();
+
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "object-same-origin";
+      let key = "object-same-origin" + nonce;
 
       let e = document.createElement('object');
       e.data = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -27,7 +30,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "object-same-site";
+      let key = "object-same-site" + nonce;
 
       let e = document.createElement('object');
       e.data = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -46,7 +49,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "object-cross-site";
+      let key = "object-cross-site" + nonce;
 
       let e = document.createElement('object');
       e.data = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
index f88cf14..1634a29 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
@@ -4,11 +4,14 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body></body>
 <script>
-promise_test(t => {
+  let nonce = token();
+
+  promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-cross-site-same-origin";
+      let key = "redirect-cross-site-same-origin" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -34,7 +37,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-cross-site-same-site";
+      let key = "redirect-cross-site-same-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -60,7 +63,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-cross-site-cross-site";
+      let key = "redirect-cross-site-cross-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
index 688c697..7647a5b1 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
@@ -4,11 +4,14 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body></body>
 <script>
-promise_test(t => {
+  let nonce = token();
+
+  promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-multiple-cross-site";
+      let key = "redirect-multiple-cross-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
index bc79f78..e83d6fd9 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
@@ -4,11 +4,14 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body></body>
 <script>
-promise_test(t => {
+  let nonce = token();
+
+  promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-multiple-same-site";
+      let key = "redirect-multiple-same-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
index a532392..2033eab 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
@@ -4,11 +4,14 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body></body>
 <script>
-promise_test(t => {
+  let nonce = token();
+
+  promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-same-origin-same-origin";
+      let key = "redirect-same-origin-same-origin" + nonce;
 
       let e = document.createElement('img');
       e.src = "/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -35,7 +38,7 @@
 
 promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-same-origin-same-site";
+      let key = "redirect-same-origin-same-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -62,7 +65,7 @@
 
 promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-same-origin-cross-site";
+      let key = "redirect-same-origin-cross-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
index 92749ae..c5b6830 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
@@ -4,11 +4,14 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body></body>
 <script>
-promise_test(t => {
+  let nonce = token();
+
+  promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-same-site-same-origin";
+      let key = "redirect-same-site-same-origin" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -35,7 +38,7 @@
 
 promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-same-site-same-site";
+      let key = "redirect-same-site-same-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
@@ -62,7 +65,7 @@
 
 promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "redirect-same-site-cross-site";
+      let key = "redirect-same-site-cross-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html
index 5b7ee77..590a6c3 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html
@@ -4,11 +4,15 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body>
   <script>
+      let nonce = token();
+      let key = "serviceworker-same-origin" + nonce;
+
       if ('serviceWorker' in navigator) {
         window.addEventListener('load', function() {
-          navigator.serviceWorker.register('https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=serviceworker-same-origin').then(function(registration) {
+          navigator.serviceWorker.register('https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=' + key).then(function(registration) {
             test_same_origin();
 
             // uninstall the serviceworker after the test
@@ -34,7 +38,6 @@
   function test_same_origin(){
     promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "serviceworker-same-origin";
       let expected = {"dest":"serviceworker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
       fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
         .then(response => response.text())
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html
index cfeadd8d..a1c558a 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html
@@ -4,13 +4,16 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <script>
+  let nonce = token();
+  let key = "sharedworker-same-origin" + nonce;
 
   // TESTS //
   if (window.Worker) {
 
       //  Same-Origin test
-      var sharedWorker = new SharedWorker('/fetch/sec-metadata/resources/record-header.py?file=sharedworker-same-origin');
+      var sharedWorker = new SharedWorker('/fetch/sec-metadata/resources/record-header.py?file=' + key);
       sharedWorker.port.start();
 
       sharedWorker.onerror = function(){
@@ -25,7 +28,6 @@
   function test_same_origin(){
     promise_test(t => {
       return new Promise((resolve, reject) => {
-        let key = "sharedworker-same-origin";
         let expected = {"dest":"sharedworker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
 
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/style.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/style.tentative.https.sub.html
index 4ae1266..46f64f4 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/style.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/style.tentative.https.sub.html
@@ -4,11 +4,14 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body></body>
 <script>
+  let nonce = token();
+
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "style-same-origin";
+      let key = "style-same-origin" + nonce;
 
       let e = document.createElement('link');
       e.rel = "stylesheet";
@@ -28,7 +31,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "style-same-site";
+      let key = "style-same-site" + nonce;
 
       let e = document.createElement('link');
       e.rel = "stylesheet";
@@ -48,7 +51,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "style-cross-site";
+      let key = "style-cross-site" + nonce;
 
       let e = document.createElement('link');
       e.rel = "stylesheet";
@@ -68,7 +71,7 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "style-same-origin";
+      let key = "style-same-origin-cors" + nonce;
 
       let e = document.createElement('link');
       e.rel = "stylesheet";
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/track.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/track.tentative.https.sub.html
index 89933f2..817e4845 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/track.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/track.tentative.https.sub.html
@@ -4,9 +4,12 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body>
 </body>
 <script>
+  let nonce = token();
+
   function createVideoElement() {
     let el = document.createElement('video');
     el.src = "/media/movie_5.mp4";
@@ -25,9 +28,10 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
+      let key = "track-same-origin" + nonce;
       let video = createVideoElement();
       let el = createTrack();
-      el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-same-origin";
+      el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       el.onload = t.step_func(_ => {
         expected = {
           "dest": "track",
@@ -35,7 +39,7 @@
           "user": "?F",
           "mode": "cors" // Because the `video` element has `crossorigin`
         };
-        fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-same-origin")
+        fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
             .then(_ => resolve());
@@ -47,9 +51,10 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
+      let key = "track-same-site" + nonce;
       let video = createVideoElement();
       let el = createTrack();
-      el.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-same-site";
+      el.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       el.onload = t.step_func(_ => {
         expected = {
           "dest": "track",
@@ -57,7 +62,7 @@
           "user": "?F",
           "mode": "cors" // Because the `video` element has `crossorigin`
         };
-        fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-same-site")
+        fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
             .then(resolve)
@@ -71,9 +76,10 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
+      let key = "track-cross-site" + nonce;
       let video = createVideoElement();
       let el = createTrack();
-      el.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-cross-site";
+      el.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       el.onload = t.step_func(_ => {
         expected = {
           "dest": "track",
@@ -81,7 +87,7 @@
           "user": "?F",
           "mode": "cors" // Because the `video` element has `crossorigin`
         };
-        fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-cross-site")
+        fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
             .then(resolve)
@@ -94,13 +100,14 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
+      let key = "track-same-origin-cors" + nonce;
       let video = createVideoElement();
 
       // Unset `crossorigin` to change the CORS mode:
       video.crossOrigin = undefined;
 
       let el = createTrack();
-      el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-same-origin";
+      el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       el.onload = t.step_func(_ => {
         expected = {
           "dest":"track",
@@ -108,7 +115,7 @@
           "user":"?F",
           "mode": "same-origin"
         };
-        fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-same-origin")
+        fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
             .then(_ => resolve());
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html
index 89be6f0b..dc21d032 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/worker.tentative.https.sub.html
@@ -4,10 +4,13 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <script>
+  let nonce = token();
+
   promise_test(t => {
     return new Promise((resolve, reject) => {
-      let key = "worker-same-origin";
+      let key = "worker-same-origin" + nonce;
       let w = new Worker("/fetch/sec-metadata/resources/record-header.py?file=" + key);
       w.onmessage = e => {
         let expected = {"dest":"worker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window-expected.txt
new file mode 100644
index 0000000..e08395a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+FAIL Window's associated Document object is used for finding named objects (<div> via srcdoc <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<object> via srcdoc <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<iframe> via srcdoc <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<object> with browsing ccontext via srcdoc <iframe)> abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<div> via same-origin <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<object> via same-origin <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<iframe> via same-origin <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<object> with browsing ccontext via same-origin <iframe)> abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<div> via cross-site <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<object> via cross-site <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<iframe> via cross-site <iframe>) abc is not defined
+FAIL Window's associated Document object is used for finding named objects (<object> with browsing ccontext via cross-site <iframe)> abc is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window.js
new file mode 100644
index 0000000..59d94ef
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/navigated-named-objects.window.js
@@ -0,0 +1,67 @@
+// META: script=/common/get-host-info.sub.js
+
+function echoURL(content) {
+  return `/common/echo.py?content=${encodeURIComponent(content)}`;
+}
+
+function setSrc(frame, type, content) {
+  if (type === "same-origin") {
+    frame.src = echoURL(content);
+  } else if (type === "cross-site") {
+    frame.src = `${get_host_info().HTTP_NOTSAMESITE_ORIGIN}${echoURL(content)}`;
+  } else {
+    frame.srcdoc = content;
+  }
+}
+
+["srcdoc", "same-origin", "cross-site"].forEach(type => {
+  const initialType = type === "srcdoc" ? type : "same-origin";
+
+  [
+    {
+      "namedObject": "<div id=abc></div>",
+      "namedObjectLocalName": "div"
+    },
+    {
+      "namedObject": "<object name=abc></object>",
+      "namedObjectLocalName": "object"
+    },
+    {
+      "namedObject": "<iframe id=abc></iframe>",
+      "namedObjectLocalName": "iframe"
+    }
+  ].forEach(testData => {
+    async_test(t => {
+      const frame = document.createElement("iframe");
+      t.add_cleanup(() => frame.remove());
+      setSrc(frame, initialType, `<script>function f() { return abc }</script>${testData.namedObject}`);
+      frame.onload = t.step_func(() => {
+        const f = frame.contentWindow.f,
+              associatedAbc = f();
+        frame.onload = t.step_func_done(() => {
+          assert_equals(f(), associatedAbc);
+          assert_equals(associatedAbc.localName, testData.namedObjectLocalName);
+        });
+        setSrc(frame, type, "<span id=abc></span>");
+      });
+      document.body.append(frame);
+    }, `Window's associated Document object is used for finding named objects (<${testData.namedObjectLocalName}> via ${type} <iframe>)`);
+  });
+
+  async_test(t => {
+    const frame = document.createElement("iframe");
+    t.add_cleanup(() => frame.remove());
+    setSrc(frame, initialType, "<script>function f() { return abc }</script><object name=abc data='about:blank'></object>");
+    frame.onload = t.step_func(() => {
+      const f = frame.contentWindow.f,
+            associatedAbc = f(),
+            associatedAbcContainer = associatedAbc.frameElement;
+      frame.onload = t.step_func_done(() => {
+        assert_equals(f(), associatedAbcContainer);
+        assert_equals(associatedAbcContainer.contentWindow, null);
+      });
+      setSrc(frame, type, "<span id=abc></span>");
+    });
+    document.body.append(frame);
+  }, `Window's associated Document object is used for finding named objects (<object> with browsing ccontext via ${type} <iframe)>`);
+});
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/css-font-loading.idl b/third_party/blink/web_tests/external/wpt/interfaces/css-font-loading.idl
index c2ef551..2bbc35a 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/css-font-loading.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/css-font-loading.idl
@@ -81,11 +81,9 @@
   readonly attribute FontFaceSetLoadStatus status;
 };
 
-[Exposed=(Window,Worker),
- NoInterfaceObject]
-interface FontFaceSource {
+interface mixin FontFaceSource {
   readonly attribute FontFaceSet fonts;
 };
 
-Document implements FontFaceSource;
-WorkerGlobalScope implements FontFaceSource;
+Document includes FontFaceSource;
+WorkerGlobalScope includes FontFaceSource;
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html
index 28dfe1e4..2432500 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html
@@ -55,26 +55,29 @@
     const eventPromise = new Promise((resolve, reject) => {
       request.addEventListener(
         "shippingaddresschange",
-        async ev => {
-          // spin the event loop, sets [[waitForUpdate]] to true.
-          await Promise.resolve();
-          try {
-            ev.updateWith(validDetails);
-            resolve(); // This is bad.
-          } catch (err) {
-            reject(err); // this is good.
-          }
+        ev => {
+          // Forces updateWith() to be run in the next event loop tick so that
+          // [[waitForUpdate]] is already true when it runs.
+          t.step_timeout(() => {
+            try {
+              ev.updateWith(validDetails);
+              resolve(); // This is bad.
+            } catch (err) {
+              reject(err); // this is good.
+            }
+          });
         },
         { once: true }
       );
     });
-    const response = await request.show();
+    const acceptPromise = request.show();
     await promise_rejects(
       t,
       "InvalidStateError",
       eventPromise,
       "The event loop already spun, so [[waitForUpdate]] is now true"
     );
+    const response = await acceptPromise;
     await response.complete();
   }, testName.trim());
 }
diff --git a/third_party/blink/web_tests/external/wpt/visual-viewport/viewport-scrollbars-cause-resize.html b/third_party/blink/web_tests/external/wpt/visual-viewport/viewport-scrollbars-cause-resize.html
index d0158c6..2767fcc 100644
--- a/third_party/blink/web_tests/external/wpt/visual-viewport/viewport-scrollbars-cause-resize.html
+++ b/third_party/blink/web_tests/external/wpt/visual-viewport/viewport-scrollbars-cause-resize.html
@@ -15,6 +15,8 @@
         scrollbars will cause a resize event to be fired at window.visualViewport.
     </h4>
     <script>
+      setup({ explicit_done: true });
+
       function runTest() {
         var scrollbarThickness = calculateScrollbarThickness();
 
@@ -59,7 +61,13 @@
 
       // Run the test after load to make sure any resize from a previous test
       // doesn't interfere.
-      window.onload = runTest;
+      window.onload = function() {
+        try {
+          runTest();
+        } finally {
+          done();
+        }
+      };
     </script>
     <div id="log"></div>
     </body>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-id-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-id-expected.txt
index 47040344..e2bcf02 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-id-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-id-expected.txt
@@ -2,7 +2,6 @@
 PASS DTLS client uses odd data channel IDs
 PASS DTLS server uses even data channel IDs
 FAIL In-band negotiation with a specific ID should not be allowed assert_unreached: Channel established with same ID using negotiated=false Reached unreachable code
-FAIL Odd/even role should not be violated when mixing with negotiated channels assert_equals: Channel id must be null before DTLS role has been determined expected (object) null but got (number) 65535
-FAIL Channel ID exhaustion handling (before and after connection establishment) assert_equals: Channel id must be null before DTLS role has been determined expected (object) null but got (number) 65535
+FAIL Odd/even role should not be violated when mixing with negotiated channels assert_equals: Channel id must be null before DTLS role has been determined expected (object) null but got (number) 0
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-id.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-id.html
index 98be63d..4c16547 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-id.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-id.html
@@ -246,6 +246,7 @@
       3.    Fire an event named error with an OperationError exception at channel.
       4.    Fire a simple event named close at channel.
  */
+/* TEST DISABLED - it takes so long, it times out.
 promise_test(async (t) => {
   const resolver = new Resolver();
   // Takes the DTLS server role
@@ -339,4 +340,6 @@
   await resolver;
 }, 'Channel ID exhaustion handling (before and after connection establishment)');
 
+END DISABLED TEST */
+
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-createDataChannel-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-createDataChannel-expected.txt
index d5a46b2..4064e79e0 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-createDataChannel-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-createDataChannel-expected.txt
@@ -54,7 +54,7 @@
       negotiated: true,
       id: null
     })" did not throw
-FAIL Channels created (after setRemoteDescription) should have id assigned assert_equals: Expect initial id to be null expected (object) null but got (number) 65535
+PASS Channels created (after setRemoteDescription) should have id assigned
 FAIL Reusing a data channel id that is in use should throw OperationError assert_throws: function "() =>
     pc.createDataChannel('channel-3', {
       negotiated: true,
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
index 9b3a9a8..73668e7b 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
@@ -210,10 +210,10 @@
   const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
   const transceiver = trackEvent.transceiver;
   assert_equals(transceiver.currentDirection, null,
-                'SRD(offer): transciever.currentDirection is null');
+                'SRD(offer): transceiver.currentDirection is null');
   await pc2.setLocalDescription(await pc2.createAnswer());
   assert_equals(transceiver.currentDirection, 'recvonly',
-                'SLD(answer): transciever.currentDirection is recvonly');
+                'SLD(answer): transceiver.currentDirection is recvonly');
 }, 'setLocalDescription(answer): transceiver.currentDirection is recvonly');
 
 promise_test(async t => {
@@ -223,10 +223,10 @@
   const pc2 = createPeerConnectionWithCleanup(t);
   await exchangeOffer(pc1, pc2);
   assert_equals(transceiver.currentDirection, null,
-                'SLD(offer): transciever.currentDirection is null');
+                'SLD(offer): transceiver.currentDirection is null');
   await exchangeAnswer(pc1, pc2);
   assert_equals(transceiver.currentDirection, 'sendonly',
-                'SRD(answer): transciever.currentDirection is sendonly');
+                'SRD(answer): transceiver.currentDirection is sendonly');
 }, 'setLocalDescription(answer): transceiver.currentDirection is sendonly');
 
 promise_test(async t => {
diff --git a/third_party/blink/web_tests/fast/dom/DOMImplementation/remove-adopted-option-element-expected.txt b/third_party/blink/web_tests/fast/dom/DOMImplementation/remove-adopted-option-element-expected.txt
new file mode 100644
index 0000000..730ebf6
--- /dev/null
+++ b/third_party/blink/web_tests/fast/dom/DOMImplementation/remove-adopted-option-element-expected.txt
@@ -0,0 +1 @@
+This test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/fast/dom/DOMImplementation/remove-adopted-option-element.html b/third_party/blink/web_tests/fast/dom/DOMImplementation/remove-adopted-option-element.html
new file mode 100644
index 0000000..3700701
--- /dev/null
+++ b/third_party/blink/web_tests/fast/dom/DOMImplementation/remove-adopted-option-element.html
@@ -0,0 +1,17 @@
+<div id="container">
+  <select><option id="child"></option></select>
+</div>
+<script>
+  window.onload = _ => {
+    let child = document.getElementById("child");
+    let container = document.getElementById("container");
+
+    doc = document.implementation.createDocument( "svg", null);
+    doc.adoptNode(child);
+    container.parentNode.removeChild(container);
+  }
+
+  if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
+This test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/fast/url/script-tests/standard-url.js b/third_party/blink/web_tests/fast/url/script-tests/standard-url.js
index f60d2e6..31c75dd 100644
--- a/third_party/blink/web_tests/fast/url/script-tests/standard-url.js
+++ b/third_party/blink/web_tests/fast/url/script-tests/standard-url.js
@@ -1,16 +1,23 @@
 description("Canonicalization of standard URLs");
 
+// Need to change the base URL to get the results to be consistent
+// across platforms. We can't do it in the HTML because we need the
+// original value in order to load this script.
+let base = document.createElement('base');
+base.href = 'file:///';
+document.head.appendChild(base);
+
 cases = [
   ["http://www.google.com/foo?bar=baz#", "http://www.google.com/foo?bar=baz#"],
   ["http://www.google.com/foo?bar=baz# \u00bb", "http://www.google.com/foo?bar=baz#%20%C2%BB"],
   ["http://[www.google.com]/", "http://[www.google.com]/"],
   ["http://www.google.com", "http://www.google.com/"],
-  // Disabled because whitespace gets treated different in this API.
-  // ["ht\ttp:@www.google.com:80/;p?#", "ht%09tp://www.google.com:80/;p?#"],
+  ["ht\ttp:@www.google.com:80/;p?#", "http://www.google.com/;p?#"],
   ["http:////////user:@google.com:99?foo", "http://user@google.com:99/?foo"],
-  // Disabled because this gets treated as a relative URL.
-  // ["www.google.com", ":www.google.com/"],
+  ["www.google.com", "file:///www.google.com"],
   ["http://192.0x00A80001", "http://192.168.0.1/"],
+  // This test matches Blink's current behaviour, but the URL standard
+  // does not unescape %2E.
   ["http://www/foo%2Ehtml", "http://www/foo.html"],
   ["http://user:pass@/", "http://user:pass@/"],
   ["http://%25DOMAIN:foobar@foodomain.com/", "http://%25DOMAIN:foobar@foodomain.com/"],
@@ -41,7 +48,7 @@
   ["ftp:/example.com/", "ftp://example.com/"],
   ["https:/example.com/", "https://example.com/"],
   ["madeupscheme:/example.com/", "madeupscheme:/example.com/"],
-  ["file:/example.com/", "file://localhost/example.com/"],
+  ["file:/example.com/", "file:///example.com/"],
   ["ftps:/example.com/", "ftps:/example.com/"],
   ["gopher:/example.com/", "gopher://example.com/"],
   ["ws:/example.com/", "ws://example.com/"],
diff --git a/third_party/blink/web_tests/platform/win7/fast/url/standard-url-expected.txt b/third_party/blink/web_tests/fast/url/standard-url-expected.txt
similarity index 94%
rename from third_party/blink/web_tests/platform/win7/fast/url/standard-url-expected.txt
rename to third_party/blink/web_tests/fast/url/standard-url-expected.txt
index c2212eb..77ae63aa 100644
--- a/third_party/blink/web_tests/platform/win7/fast/url/standard-url-expected.txt
+++ b/third_party/blink/web_tests/fast/url/standard-url-expected.txt
@@ -6,7 +6,9 @@
 PASS canonicalize('http://www.google.com/foo?bar=baz# »') is 'http://www.google.com/foo?bar=baz#%20%C2%BB'
 PASS canonicalize('http://[www.google.com]/') is 'http://[www.google.com]/'
 PASS canonicalize('http://www.google.com') is 'http://www.google.com/'
+PASS canonicalize('ht	tp:@www.google.com:80/;p?#') is 'http://www.google.com/;p?#'
 PASS canonicalize('http:////////user:@google.com:99?foo') is 'http://user@google.com:99/?foo'
+PASS canonicalize('www.google.com') is 'file:///www.google.com'
 PASS canonicalize('http://192.0x00A80001') is 'http://192.168.0.1/'
 PASS canonicalize('http://www/foo%2Ehtml') is 'http://www/foo.html'
 PASS canonicalize('http://user:pass@/') is 'http://user:pass@/'
@@ -35,7 +37,7 @@
 PASS canonicalize('ftp:/example.com/') is 'ftp://example.com/'
 PASS canonicalize('https:/example.com/') is 'https://example.com/'
 PASS canonicalize('madeupscheme:/example.com/') is 'madeupscheme:/example.com/'
-FAIL canonicalize('file:/example.com/') should be file://localhost/example.com/. Was file:///E:/example.com/.
+PASS canonicalize('file:/example.com/') is 'file:///example.com/'
 PASS canonicalize('ftps:/example.com/') is 'ftps:/example.com/'
 PASS canonicalize('gopher:/example.com/') is 'gopher://example.com/'
 PASS canonicalize('ws:/example.com/') is 'ws://example.com/'
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/datagrid-expected.txt b/third_party/blink/web_tests/http/tests/devtools/components/datagrid-expected.txt
index 18da43a..38f0b58 100644
--- a/third_party/blink/web_tests/http/tests/devtools/components/datagrid-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/components/datagrid-expected.txt
@@ -123,26 +123,26 @@
 
 Tree:
 
-Attached a to root
+Attached TextData to root
 
 Tree:
- a
+ TextData
 
 Added secondCol
 
 Tree:
- a | a foo
+ TextData | a foo
 
-Attached b to root
+Attached NullData to root
 
 Tree:
- a | a foo
- b | b foo
+ TextData | a foo
+ NullData | 
 
 Removed secondCol
 
 Tree:
- a
- b
+ TextData
+ NullData
 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/datagrid.js b/third_party/blink/web_tests/http/tests/devtools/components/datagrid.js
index 6a36b74..98e86ba 100644
--- a/third_party/blink/web_tests/http/tests/devtools/components/datagrid.js
+++ b/third_party/blink/web_tests/http/tests/devtools/components/datagrid.js
@@ -112,8 +112,8 @@
 
   var columns = [{id: 'id'}];
   var dataGrid = new DataGrid.DataGrid(columns);
-  var a = new DataGrid.DataGridNode({id: 'a', secondCol: 'a foo'});
-  var b = new DataGrid.DataGridNode({id: 'b', secondCol: 'b foo'});
+  var a = new DataGrid.DataGridNode({id: 'TextData', secondCol: 'a foo'});
+  var b = new DataGrid.DataGridNode({id: 'NullData', secondCol: null});
   var root = dataGrid.rootNode();
   attach(root, a);
   dumpNodes();
@@ -121,6 +121,7 @@
   TestRunner.addResult('Added secondCol');
   dumpNodes();
   attach(root, b);
+  dataGrid.autoSizeColumns(20, 80);
   dumpNodes();
   dataGrid.removeColumn('secondCol');
   TestRunner.addResult('Removed secondCol');
diff --git a/third_party/blink/web_tests/http/tests/images/feature-policy-legacy-formats-expected.txt b/third_party/blink/web_tests/http/tests/images/feature-policy-legacy-formats-expected.txt
deleted file mode 100644
index b3266af6..0000000
--- a/third_party/blink/web_tests/http/tests/images/feature-policy-legacy-formats-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-CONSOLE ERROR: Feature policy violation: legacy-image-formats is not allowed in this document.
diff --git a/third_party/blink/web_tests/http/tests/images/feature-policy-legacy-formats.html b/third_party/blink/web_tests/http/tests/images/feature-policy-legacy-formats.html
deleted file mode 100644
index 5052764..0000000
--- a/third_party/blink/web_tests/http/tests/images/feature-policy-legacy-formats.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE html>
-<style>
-body {
-  font: 10px Ahem;
-}
-</style>
-<body><iframe src="resources/frame-with-legacy-image.html" allow="legacy-image-formats 'none'" width="440" height="180"></iframe></body>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/block_cross_site_document_load-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/block_cross_site_document_load-expected.txt
index 8a2c52b..b001a1b 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/network/block_cross_site_document_load-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/block_cross_site_document_load-expected.txt
@@ -1,12 +1,6 @@
 Tests the blockedCrossSiteDocumentLoad bit available as a part of the loading finished signal.
 Blocking cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/nosniff.pl: shouldReportCorbBlocking=true.
-Blocking cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/nosniff.pl fetched via GET: shouldReportCorbBlocking=true.
-Blocking cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/nosniff.pl fetched via OPTIONS: shouldReportCorbBlocking=false.
-Blocking cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/nosniff.pl fetched via POST: shouldReportCorbBlocking=false.
 Blocking cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/simple-iframe.html: shouldReportCorbBlocking=true.
-Blocking cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/simple-iframe.html fetched via GET: shouldReportCorbBlocking=true.
-Blocking cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/simple-iframe.html fetched via OPTIONS: shouldReportCorbBlocking=false.
-Blocking cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/simple-iframe.html fetched via POST: shouldReportCorbBlocking=false.
 Blocking, but not reporting cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/204.pl: shouldReportCorbBlocking=false.
 Blocking, but not reporting cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/404.pl: shouldReportCorbBlocking=false.
 Blocking, but not reporting cross-site document at http://devtools.oopif.test:8000/inspector-protocol/network/resources/content-length-0.pl: shouldReportCorbBlocking=false.
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/block_cross_site_document_load.js b/third_party/blink/web_tests/http/tests/inspector-protocol/network/block_cross_site_document_load.js
index 3174efb..645e635 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/network/block_cross_site_document_load.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/block_cross_site_document_load.js
@@ -16,16 +16,6 @@
     testRunner.log(
         `Blocking cross-site document at ${url}: ` +
         `shouldReportCorbBlocking=${response.params.shouldReportCorbBlocking}.`);
-
-    // Only GET method requests should show a warning message.
-    let http_methods = ['GET', 'OPTIONS', 'POST'];
-    for (const method of http_methods) {
-      session.evaluate(`fetch('${url}', {method: '${method}'});`);
-      const response = await dp.Network.onceLoadingFinished();
-      testRunner.log(
-          `Blocking cross-site document at ${url} fetched via ${method}: ` +
-          `shouldReportCorbBlocking=${response.params.shouldReportCorbBlocking}.`);
-    }
   }
 
   let blocked_unreported_urls = [
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webvr-gamepad-origin-trial-interfaces.html b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webvr-gamepad-origin-trial-interfaces.html
index 0360459b..3e5b19980 100644
--- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webvr-gamepad-origin-trial-interfaces.html
+++ b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webvr-gamepad-origin-trial-interfaces.html
@@ -21,7 +21,7 @@
 ];
 
 // Skip this test if flags are not set properly.
-if(!self.internals.runtimeFlags.webVRGamepadSupportEnabled) {
+if (!self.internals.runtimeFlags.webVRGamepadSupportEnabled) {
   test(t => {
     OriginTrialsHelper.check_properties_missing(this, properties_to_check);
   }, "The WebVR-specific Gamepad properties are not available without a token.");
@@ -33,25 +33,33 @@
 
 OriginTrialsHelper.add_token(token);
 
-test(t => {
-  OriginTrialsHelper.check_properties(this, properties_to_check);
-}, 'The WebVR-specific Gamepad properties are available.');
+// TODO(https://crbug.com/920025): Remove this line. This check does not work
+// because of https://crbug.com/946246 but will be moot after fixing 920025.
+if (self.internals.runtimeFlags.webVRGamepadSupportEnabled) {
+  test(t => {
+    OriginTrialsHelper.check_properties(this, properties_to_check);
+  }, 'The WebVR-specific Gamepad properties are available.');
+}
 
-test(t => {
-  OriginTrialsHelper.check_interfaces(this, interfaces_to_check);
-  // Check the properties of the interfaces_to_check.
-  OriginTrialsHelper.check_properties(this, {
-    'GamepadPose': [
-      'hasOrientation',
-      'hasPosition',
-      'position',
-      'linearVelocity',
-      'linearAcceleration',
-      'orientation',
-      'angularVelocity',
-      'angularAcceleration'
-    ]
-  });
-}, 'The WebVR-specific Gamepad interfaces and their properties are available.');
+// TODO(https://crbug.com/920025): Remove this line. This check does not work
+// because of https://crbug.com/946246 but will be moot after fixing 920025.
+if (self.internals.runtimeFlags.webVRGamepadSupportEnabled) {
+  test(t => {
+    OriginTrialsHelper.check_interfaces(this, interfaces_to_check);
+    // Check the properties of the interfaces_to_check.
+    OriginTrialsHelper.check_properties(this, {
+      'GamepadPose': [
+        'hasOrientation',
+        'hasPosition',
+        'position',
+        'linearVelocity',
+        'linearAcceleration',
+        'orientation',
+        'angularVelocity',
+        'angularAcceleration'
+      ]
+    });
+  }, 'The WebVR-specific Gamepad interfaces and their properties are available.');
+}
 
 </script>
diff --git a/third_party/blink/web_tests/http/tests/resources/origin-trials-helper.js b/third_party/blink/web_tests/http/tests/resources/origin-trials-helper.js
index d5e438e..667696a9 100644
--- a/third_party/blink/web_tests/http/tests/resources/origin-trials-helper.js
+++ b/third_party/blink/web_tests/http/tests/resources/origin-trials-helper.js
@@ -54,7 +54,7 @@
             interface_prototype = interface_object.prototype;
           }
         }
-        assert_true(interface_prototype !== undefined, 'Interface ' + interface_name + ' not found');
+        assert_true(interface_prototype !== undefined, 'Interface ' + interface_name + ' exists');
         property_filters[interface_name].forEach(function(property_name) {
           assert_equals(interface_prototype.hasOwnProperty(property_name),
               should_exist,
diff --git a/third_party/blink/web_tests/http/tests/security/mixedContent/empty-url-plugin-in-frame-expected.txt b/third_party/blink/web_tests/http/tests/security/mixedContent/empty-url-plugin-in-frame-expected.txt
index d3e5458..f81fac1 100644
--- a/third_party/blink/web_tests/http/tests/security/mixedContent/empty-url-plugin-in-frame-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/mixedContent/empty-url-plugin-in-frame-expected.txt
@@ -1 +1,2 @@
+CONSOLE MESSAGE: Blink Test Plugin: initializing
 This test loads a secure iframe that loads a plugin without a URL. We should *not* get a mixed content callback because the plugin cannot be controlled by an active network attacker.
diff --git a/third_party/blink/web_tests/http/tests/security/mixedContent/empty-url-plugin-in-frame.html b/third_party/blink/web_tests/http/tests/security/mixedContent/empty-url-plugin-in-frame.html
index a4a5324..512d697 100644
--- a/third_party/blink/web_tests/http/tests/security/mixedContent/empty-url-plugin-in-frame.html
+++ b/third_party/blink/web_tests/http/tests/security/mixedContent/empty-url-plugin-in-frame.html
@@ -1,8 +1,13 @@
 <html>
 <body>
 <script>
-if (window.testRunner)
+if (window.testRunner) {
     testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+    window.addEventListener("message", _ => {
+      testRunner.notifyDone();
+    });
+}
 </script>
 <p>This test loads a secure iframe that loads a plugin without a URL.  We should
 *not* get a mixed content callback because the plugin cannot be controlled by
diff --git a/third_party/blink/web_tests/http/tests/security/mixedContent/resources/frame-with-empty-url-plugin.html b/third_party/blink/web_tests/http/tests/security/mixedContent/resources/frame-with-empty-url-plugin.html
index c264952..30e77c58 100644
--- a/third_party/blink/web_tests/http/tests/security/mixedContent/resources/frame-with-empty-url-plugin.html
+++ b/third_party/blink/web_tests/http/tests/security/mixedContent/resources/frame-with-empty-url-plugin.html
@@ -1,7 +1,11 @@
 <script>
 window.onload = function() {
+  if (window.internals)
+    internals.updateLayoutAndRunPostLayoutTasks();
   if (window.opener)
     window.opener.postMessage('done', '*');
+  if (window.parent)
+    window.parent.postMessage('done', '*');
 }
 </script>
 <object name='plugin' type='application/x-blink-test-plugin'></object>
diff --git a/third_party/blink/web_tests/platform/linux/fast/url/standard-url-expected.txt b/third_party/blink/web_tests/platform/linux/fast/url/standard-url-expected.txt
deleted file mode 100644
index 8f00dab0..0000000
--- a/third_party/blink/web_tests/platform/linux/fast/url/standard-url-expected.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-Canonicalization of standard URLs
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS canonicalize('http://www.google.com/foo?bar=baz#') is 'http://www.google.com/foo?bar=baz#'
-PASS canonicalize('http://www.google.com/foo?bar=baz# »') is 'http://www.google.com/foo?bar=baz#%20%C2%BB'
-PASS canonicalize('http://[www.google.com]/') is 'http://[www.google.com]/'
-PASS canonicalize('http://www.google.com') is 'http://www.google.com/'
-PASS canonicalize('http:////////user:@google.com:99?foo') is 'http://user@google.com:99/?foo'
-PASS canonicalize('http://192.0x00A80001') is 'http://192.168.0.1/'
-PASS canonicalize('http://www/foo%2Ehtml') is 'http://www/foo.html'
-PASS canonicalize('http://user:pass@/') is 'http://user:pass@/'
-PASS canonicalize('http://%25DOMAIN:foobar@foodomain.com/') is 'http://%25DOMAIN:foobar@foodomain.com/'
-PASS canonicalize('http:\\\\www.google.com\\foo') is 'http://www.google.com/foo'
-PASS canonicalize('http://www.google.com/asdf#\ud800') is 'http://www.google.com/asdf#%EF%BF%BD'
-PASS canonicalize('http://foo:80/') is 'http://foo/'
-PASS canonicalize('http://foo:81/') is 'http://foo:81/'
-PASS canonicalize('httpa://foo:80/') is 'httpa://foo:80/'
-PASS canonicalize('http://foo:-80/') is 'http://foo:-80/'
-PASS canonicalize('https://foo:443/') is 'https://foo/'
-PASS canonicalize('https://foo:80/') is 'https://foo:80/'
-PASS canonicalize('ftp://foo:21/') is 'ftp://foo/'
-PASS canonicalize('ftp://foo:80/') is 'ftp://foo:80/'
-PASS canonicalize('gopher://foo:70/') is 'gopher://foo/'
-PASS canonicalize('gopher://foo:443/') is 'gopher://foo:443/'
-PASS canonicalize('ws://foo:80/') is 'ws://foo/'
-PASS canonicalize('ws://foo:81/') is 'ws://foo:81/'
-PASS canonicalize('ws://foo:443/') is 'ws://foo:443/'
-PASS canonicalize('ws://foo:815/') is 'ws://foo:815/'
-PASS canonicalize('wss://foo:80/') is 'wss://foo:80/'
-PASS canonicalize('wss://foo:81/') is 'wss://foo:81/'
-PASS canonicalize('wss://foo:443/') is 'wss://foo/'
-PASS canonicalize('wss://foo:815/') is 'wss://foo:815/'
-PASS canonicalize('http:/example.com/') is 'http://example.com/'
-PASS canonicalize('ftp:/example.com/') is 'ftp://example.com/'
-PASS canonicalize('https:/example.com/') is 'https://example.com/'
-PASS canonicalize('madeupscheme:/example.com/') is 'madeupscheme:/example.com/'
-FAIL canonicalize('file:/example.com/') should be file://localhost/example.com/. Was file:///example.com/.
-PASS canonicalize('ftps:/example.com/') is 'ftps:/example.com/'
-PASS canonicalize('gopher:/example.com/') is 'gopher://example.com/'
-PASS canonicalize('ws:/example.com/') is 'ws://example.com/'
-PASS canonicalize('wss:/example.com/') is 'wss://example.com/'
-PASS canonicalize('data:/example.com/') is 'data:/example.com/'
-PASS canonicalize('javascript:/example.com/') is 'javascript:/example.com/'
-PASS canonicalize('mailto:/example.com/') is 'mailto:/example.com/'
-PASS canonicalize('http:example.com/') is 'http://example.com/'
-PASS canonicalize('ftp:example.com/') is 'ftp://example.com/'
-PASS canonicalize('https:example.com/') is 'https://example.com/'
-PASS canonicalize('madeupscheme:example.com/') is 'madeupscheme:example.com/'
-PASS canonicalize('ftps:example.com/') is 'ftps:example.com/'
-PASS canonicalize('gopher:example.com/') is 'gopher://example.com/'
-PASS canonicalize('ws:example.com/') is 'ws://example.com/'
-PASS canonicalize('wss:example.com/') is 'wss://example.com/'
-PASS canonicalize('data:example.com/') is 'data:example.com/'
-PASS canonicalize('javascript:example.com/') is 'javascript:example.com/'
-PASS canonicalize('mailto:example.com/') is 'mailto:example.com/'
-PASS canonicalize('javascript:alert(\t 1 \n\r)') is 'javascript:alert( 1 )'
-PASS canonicalize('javascript:alert("  β ")') is 'javascript:alert(" %01 %CE%B2 ")'
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/platform/linux/http/tests/images/feature-policy-legacy-formats-expected.png b/third_party/blink/web_tests/platform/linux/http/tests/images/feature-policy-legacy-formats-expected.png
deleted file mode 100644
index d83dcc1..0000000
--- a/third_party/blink/web_tests/platform/linux/http/tests/images/feature-policy-legacy-formats-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/flexbox/scrollbars-changed-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/flexbox/scrollbars-changed-expected.txt
deleted file mode 100644
index dba55d8..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/flexbox/scrollbars-changed-expected.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "VerticalScrollbar",
-          "rect": [185, 0, 15, 100],
-          "reason": "scroll control"
-        },
-        {
-          "object": "InlineTextBox 'a'",
-          "rect": [0, 4, 15, 17],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'z'",
-          "rect": [0, 4, 15, 17],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/overflow/inline-vertical-lr-overflow-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/overflow/inline-vertical-lr-overflow-expected.txt
deleted file mode 100644
index b01a80f..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/overflow/inline-vertical-lr-overflow-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'A\u00A0\u00A0B'",
-          "rect": [32, 33, 102, 250],
-          "reason": "style change"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/overflow/inline-vertical-rl-overflow-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/overflow/inline-vertical-rl-overflow-expected.txt
deleted file mode 100644
index 524f460..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/overflow/inline-vertical-rl-overflow-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'A\u00A0\u00A0B'",
-          "rect": [666, 33, 102, 250],
-          "reason": "style change"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/vertical-rl-as-paint-container-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/vertical-rl-as-paint-container-expected.txt
deleted file mode 100644
index 6502759..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/vertical-rl-as-paint-container-expected.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [800, 600],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='target'",
-      "position": [8, 8],
-      "bounds": [600, 400],
-      "backfaceVisibility": "hidden",
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Lorem ipsum dolor'",
-          "rect": [519, 0, 81, 340],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'adipiscing elit.'",
-          "rect": [519, 0, 81, 340],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'consectetur'",
-          "rect": [519, 0, 81, 340],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'sit amet,'",
-          "rect": [519, 0, 81, 340],
-          "reason": "style change"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/blink/web_tests/platform/mac/fast/url/standard-url-expected.txt b/third_party/blink/web_tests/platform/mac/fast/url/standard-url-expected.txt
deleted file mode 100644
index 8f00dab0..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/url/standard-url-expected.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-Canonicalization of standard URLs
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS canonicalize('http://www.google.com/foo?bar=baz#') is 'http://www.google.com/foo?bar=baz#'
-PASS canonicalize('http://www.google.com/foo?bar=baz# »') is 'http://www.google.com/foo?bar=baz#%20%C2%BB'
-PASS canonicalize('http://[www.google.com]/') is 'http://[www.google.com]/'
-PASS canonicalize('http://www.google.com') is 'http://www.google.com/'
-PASS canonicalize('http:////////user:@google.com:99?foo') is 'http://user@google.com:99/?foo'
-PASS canonicalize('http://192.0x00A80001') is 'http://192.168.0.1/'
-PASS canonicalize('http://www/foo%2Ehtml') is 'http://www/foo.html'
-PASS canonicalize('http://user:pass@/') is 'http://user:pass@/'
-PASS canonicalize('http://%25DOMAIN:foobar@foodomain.com/') is 'http://%25DOMAIN:foobar@foodomain.com/'
-PASS canonicalize('http:\\\\www.google.com\\foo') is 'http://www.google.com/foo'
-PASS canonicalize('http://www.google.com/asdf#\ud800') is 'http://www.google.com/asdf#%EF%BF%BD'
-PASS canonicalize('http://foo:80/') is 'http://foo/'
-PASS canonicalize('http://foo:81/') is 'http://foo:81/'
-PASS canonicalize('httpa://foo:80/') is 'httpa://foo:80/'
-PASS canonicalize('http://foo:-80/') is 'http://foo:-80/'
-PASS canonicalize('https://foo:443/') is 'https://foo/'
-PASS canonicalize('https://foo:80/') is 'https://foo:80/'
-PASS canonicalize('ftp://foo:21/') is 'ftp://foo/'
-PASS canonicalize('ftp://foo:80/') is 'ftp://foo:80/'
-PASS canonicalize('gopher://foo:70/') is 'gopher://foo/'
-PASS canonicalize('gopher://foo:443/') is 'gopher://foo:443/'
-PASS canonicalize('ws://foo:80/') is 'ws://foo/'
-PASS canonicalize('ws://foo:81/') is 'ws://foo:81/'
-PASS canonicalize('ws://foo:443/') is 'ws://foo:443/'
-PASS canonicalize('ws://foo:815/') is 'ws://foo:815/'
-PASS canonicalize('wss://foo:80/') is 'wss://foo:80/'
-PASS canonicalize('wss://foo:81/') is 'wss://foo:81/'
-PASS canonicalize('wss://foo:443/') is 'wss://foo/'
-PASS canonicalize('wss://foo:815/') is 'wss://foo:815/'
-PASS canonicalize('http:/example.com/') is 'http://example.com/'
-PASS canonicalize('ftp:/example.com/') is 'ftp://example.com/'
-PASS canonicalize('https:/example.com/') is 'https://example.com/'
-PASS canonicalize('madeupscheme:/example.com/') is 'madeupscheme:/example.com/'
-FAIL canonicalize('file:/example.com/') should be file://localhost/example.com/. Was file:///example.com/.
-PASS canonicalize('ftps:/example.com/') is 'ftps:/example.com/'
-PASS canonicalize('gopher:/example.com/') is 'gopher://example.com/'
-PASS canonicalize('ws:/example.com/') is 'ws://example.com/'
-PASS canonicalize('wss:/example.com/') is 'wss://example.com/'
-PASS canonicalize('data:/example.com/') is 'data:/example.com/'
-PASS canonicalize('javascript:/example.com/') is 'javascript:/example.com/'
-PASS canonicalize('mailto:/example.com/') is 'mailto:/example.com/'
-PASS canonicalize('http:example.com/') is 'http://example.com/'
-PASS canonicalize('ftp:example.com/') is 'ftp://example.com/'
-PASS canonicalize('https:example.com/') is 'https://example.com/'
-PASS canonicalize('madeupscheme:example.com/') is 'madeupscheme:example.com/'
-PASS canonicalize('ftps:example.com/') is 'ftps:example.com/'
-PASS canonicalize('gopher:example.com/') is 'gopher://example.com/'
-PASS canonicalize('ws:example.com/') is 'ws://example.com/'
-PASS canonicalize('wss:example.com/') is 'wss://example.com/'
-PASS canonicalize('data:example.com/') is 'data:example.com/'
-PASS canonicalize('javascript:example.com/') is 'javascript:example.com/'
-PASS canonicalize('mailto:example.com/') is 'mailto:example.com/'
-PASS canonicalize('javascript:alert(\t 1 \n\r)') is 'javascript:alert( 1 )'
-PASS canonicalize('javascript:alert("  β ")') is 'javascript:alert(" %01 %CE%B2 ")'
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/platform/mac/http/tests/images/feature-policy-legacy-formats-expected.png b/third_party/blink/web_tests/platform/mac/http/tests/images/feature-policy-legacy-formats-expected.png
deleted file mode 100644
index cba9b3b..0000000
--- a/third_party/blink/web_tests/platform/mac/http/tests/images/feature-policy-legacy-formats-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/url/standard-url-expected.txt b/third_party/blink/web_tests/platform/win/fast/url/standard-url-expected.txt
deleted file mode 100644
index d29e0065..0000000
--- a/third_party/blink/web_tests/platform/win/fast/url/standard-url-expected.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-Canonicalization of standard URLs
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS canonicalize('http://www.google.com/foo?bar=baz#') is 'http://www.google.com/foo?bar=baz#'
-PASS canonicalize('http://www.google.com/foo?bar=baz# »') is 'http://www.google.com/foo?bar=baz#%20%C2%BB'
-PASS canonicalize('http://[www.google.com]/') is 'http://[www.google.com]/'
-PASS canonicalize('http://www.google.com') is 'http://www.google.com/'
-PASS canonicalize('http:////////user:@google.com:99?foo') is 'http://user@google.com:99/?foo'
-PASS canonicalize('http://192.0x00A80001') is 'http://192.168.0.1/'
-PASS canonicalize('http://www/foo%2Ehtml') is 'http://www/foo.html'
-PASS canonicalize('http://user:pass@/') is 'http://user:pass@/'
-PASS canonicalize('http://%25DOMAIN:foobar@foodomain.com/') is 'http://%25DOMAIN:foobar@foodomain.com/'
-PASS canonicalize('http:\\\\www.google.com\\foo') is 'http://www.google.com/foo'
-PASS canonicalize('http://www.google.com/asdf#\ud800') is 'http://www.google.com/asdf#%EF%BF%BD'
-PASS canonicalize('http://foo:80/') is 'http://foo/'
-PASS canonicalize('http://foo:81/') is 'http://foo:81/'
-PASS canonicalize('httpa://foo:80/') is 'httpa://foo:80/'
-PASS canonicalize('http://foo:-80/') is 'http://foo:-80/'
-PASS canonicalize('https://foo:443/') is 'https://foo/'
-PASS canonicalize('https://foo:80/') is 'https://foo:80/'
-PASS canonicalize('ftp://foo:21/') is 'ftp://foo/'
-PASS canonicalize('ftp://foo:80/') is 'ftp://foo:80/'
-PASS canonicalize('gopher://foo:70/') is 'gopher://foo/'
-PASS canonicalize('gopher://foo:443/') is 'gopher://foo:443/'
-PASS canonicalize('ws://foo:80/') is 'ws://foo/'
-PASS canonicalize('ws://foo:81/') is 'ws://foo:81/'
-PASS canonicalize('ws://foo:443/') is 'ws://foo:443/'
-PASS canonicalize('ws://foo:815/') is 'ws://foo:815/'
-PASS canonicalize('wss://foo:80/') is 'wss://foo:80/'
-PASS canonicalize('wss://foo:81/') is 'wss://foo:81/'
-PASS canonicalize('wss://foo:443/') is 'wss://foo/'
-PASS canonicalize('wss://foo:815/') is 'wss://foo:815/'
-PASS canonicalize('http:/example.com/') is 'http://example.com/'
-PASS canonicalize('ftp:/example.com/') is 'ftp://example.com/'
-PASS canonicalize('https:/example.com/') is 'https://example.com/'
-PASS canonicalize('madeupscheme:/example.com/') is 'madeupscheme:/example.com/'
-FAIL canonicalize('file:/example.com/') should be file://localhost/example.com/. Was file:///C:/example.com/.
-PASS canonicalize('ftps:/example.com/') is 'ftps:/example.com/'
-PASS canonicalize('gopher:/example.com/') is 'gopher://example.com/'
-PASS canonicalize('ws:/example.com/') is 'ws://example.com/'
-PASS canonicalize('wss:/example.com/') is 'wss://example.com/'
-PASS canonicalize('data:/example.com/') is 'data:/example.com/'
-PASS canonicalize('javascript:/example.com/') is 'javascript:/example.com/'
-PASS canonicalize('mailto:/example.com/') is 'mailto:/example.com/'
-PASS canonicalize('http:example.com/') is 'http://example.com/'
-PASS canonicalize('ftp:example.com/') is 'ftp://example.com/'
-PASS canonicalize('https:example.com/') is 'https://example.com/'
-PASS canonicalize('madeupscheme:example.com/') is 'madeupscheme:example.com/'
-PASS canonicalize('ftps:example.com/') is 'ftps:example.com/'
-PASS canonicalize('gopher:example.com/') is 'gopher://example.com/'
-PASS canonicalize('ws:example.com/') is 'ws://example.com/'
-PASS canonicalize('wss:example.com/') is 'wss://example.com/'
-PASS canonicalize('data:example.com/') is 'data:example.com/'
-PASS canonicalize('javascript:example.com/') is 'javascript:example.com/'
-PASS canonicalize('mailto:example.com/') is 'mailto:example.com/'
-PASS canonicalize('javascript:alert(\t 1 \n\r)') is 'javascript:alert( 1 )'
-PASS canonicalize('javascript:alert("  β ")') is 'javascript:alert(" %01 %CE%B2 ")'
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/platform/win/http/tests/images/feature-policy-legacy-formats-expected.png b/third_party/blink/web_tests/platform/win/http/tests/images/feature-policy-legacy-formats-expected.png
deleted file mode 100644
index 18281d5..0000000
--- a/third_party/blink/web_tests/platform/win/http/tests/images/feature-policy-legacy-formats-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/fetch/api/response/response-stream-with-broken-then.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/fetch/api/response/response-stream-with-broken-then.any-expected.txt
new file mode 100644
index 0000000..bd51f5f
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/fetch/api/response/response-stream-with-broken-then.any-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS Attempt to inject {done: false, value: bye} via Object.prototype.then.
+PASS Attempt to inject value: undefined via Object.prototype.then.
+PASS Attempt to inject undefined via Object.prototype.then.
+PASS Attempt to inject 8.2 via Object.prototype.then.
+PASS intercepting arraybuffer to text conversion via Object.prototype.then should not be possible
+FAIL intercepting arraybuffer to body readable stream conversion via Object.prototype.then should not be possible promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any-expected.txt
index cc045448..ea3f60a 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 FAIL Closing must be propagated backward: starts closed; preventCancel omitted; fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
-FAIL Closing must be propagated backward: starts closed; preventCancel omitted; rejected cancel promise assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Closing must be propagated backward: starts closed; preventCancel omitted; rejected cancel promise assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
 FAIL Closing must be propagated backward: starts closed; preventCancel = undefined (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
 FAIL Closing must be propagated backward: starts closed; preventCancel = null (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
 FAIL Closing must be propagated backward: starts closed; preventCancel = false (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.serviceworker-expected.txt
index cc045448..ea3f60a 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.serviceworker-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 FAIL Closing must be propagated backward: starts closed; preventCancel omitted; fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
-FAIL Closing must be propagated backward: starts closed; preventCancel omitted; rejected cancel promise assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Closing must be propagated backward: starts closed; preventCancel omitted; rejected cancel promise assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
 FAIL Closing must be propagated backward: starts closed; preventCancel = undefined (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
 FAIL Closing must be propagated backward: starts closed; preventCancel = null (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
 FAIL Closing must be propagated backward: starts closed; preventCancel = false (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.sharedworker-expected.txt
index cc045448..ea3f60a 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.sharedworker-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 FAIL Closing must be propagated backward: starts closed; preventCancel omitted; fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
-FAIL Closing must be propagated backward: starts closed; preventCancel omitted; rejected cancel promise assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Closing must be propagated backward: starts closed; preventCancel omitted; rejected cancel promise assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
 FAIL Closing must be propagated backward: starts closed; preventCancel = undefined (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
 FAIL Closing must be propagated backward: starts closed; preventCancel = null (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
 FAIL Closing must be propagated backward: starts closed; preventCancel = false (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.worker-expected.txt
index cc045448..ea3f60a 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/close-propagation-backward.any.worker-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 FAIL Closing must be propagated backward: starts closed; preventCancel omitted; fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
-FAIL Closing must be propagated backward: starts closed; preventCancel omitted; rejected cancel promise assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Closing must be propagated backward: starts closed; preventCancel omitted; rejected cancel promise assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
 FAIL Closing must be propagated backward: starts closed; preventCancel = undefined (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
 FAIL Closing must be propagated backward: starts closed; preventCancel = null (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
 FAIL Closing must be propagated backward: starts closed; preventCancel = false (falsy); fulfilled cancel promise assert_array_equals: lengths differ, expected 2 got 0
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any-expected.txt
index a26df844..562e861 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks, but then does promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL Piping from an empty ReadableStream into a WritableStream that does not desire chunks, but then the readable stream becomes non-empty and the writable stream starts desiring chunks promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
+FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks, but then does promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL Piping from an empty ReadableStream into a WritableStream that does not desire chunks, but then the readable stream becomes non-empty and the writable stream starts desiring chunks promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 FAIL Piping from a ReadableStream to a WritableStream that desires more chunks before finishing with previous ones assert_equals: chunks should continue to be enqueued until the HWM is reached expected 1 but got 3
-FAIL Piping to a WritableStream that does not consume the writes fast enough exerts backpressure on the ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping to a WritableStream that does not consume the writes fast enough exerts backpressure on the ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.serviceworker-expected.txt
index a26df844..562e861 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.serviceworker-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks, but then does promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL Piping from an empty ReadableStream into a WritableStream that does not desire chunks, but then the readable stream becomes non-empty and the writable stream starts desiring chunks promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
+FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks, but then does promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL Piping from an empty ReadableStream into a WritableStream that does not desire chunks, but then the readable stream becomes non-empty and the writable stream starts desiring chunks promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 FAIL Piping from a ReadableStream to a WritableStream that desires more chunks before finishing with previous ones assert_equals: chunks should continue to be enqueued until the HWM is reached expected 1 but got 3
-FAIL Piping to a WritableStream that does not consume the writes fast enough exerts backpressure on the ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping to a WritableStream that does not consume the writes fast enough exerts backpressure on the ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.sharedworker-expected.txt
index a26df844..562e861 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.sharedworker-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks, but then does promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL Piping from an empty ReadableStream into a WritableStream that does not desire chunks, but then the readable stream becomes non-empty and the writable stream starts desiring chunks promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
+FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks, but then does promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL Piping from an empty ReadableStream into a WritableStream that does not desire chunks, but then the readable stream becomes non-empty and the writable stream starts desiring chunks promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 FAIL Piping from a ReadableStream to a WritableStream that desires more chunks before finishing with previous ones assert_equals: chunks should continue to be enqueued until the HWM is reached expected 1 but got 3
-FAIL Piping to a WritableStream that does not consume the writes fast enough exerts backpressure on the ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping to a WritableStream that does not consume the writes fast enough exerts backpressure on the ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.worker-expected.txt
index a26df844..562e861 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/flow-control.any.worker-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks, but then does promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL Piping from an empty ReadableStream into a WritableStream that does not desire chunks, but then the readable stream becomes non-empty and the writable stream starts desiring chunks promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
+FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks assert_throws: pipeTo must reject with the same error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a non-empty ReadableStream into a WritableStream that does not desire chunks, but then does promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL Piping from an empty ReadableStream into a WritableStream that does not desire chunks, but then the readable stream becomes non-empty and the writable stream starts desiring chunks promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 FAIL Piping from a ReadableStream to a WritableStream that desires more chunks before finishing with previous ones assert_equals: chunks should continue to be enqueued until the HWM is reached expected 1 but got 3
-FAIL Piping to a WritableStream that does not consume the writes fast enough exerts backpressure on the ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping to a WritableStream that does not consume the writes fast enough exerts backpressure on the ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any-expected.txt
index c2e9ee38..6e9fc67 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any-expected.txt
@@ -1,15 +1,15 @@
 This is a testharness.js-based test.
 FAIL Piping must lock both the ReadableStream and WritableStream assert_true: the ReadableStream must become locked expected true got false
-FAIL Piping finishing must unlock both the ReadableStream and WritableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping finishing must unlock both the ReadableStream and WritableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 PASS pipeTo must check the brand of its ReadableStream this value
 PASS pipeTo must check the brand of its WritableStream argument
 PASS pipeTo must fail if the ReadableStream is locked, and not lock the WritableStream
 PASS pipeTo must fail if the WritableStream is locked, and not lock the ReadableStream
-FAIL Piping from a ReadableStream from which lots of chunks are synchronously readable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL Piping from a ReadableStream for which a chunk becomes asynchronously readable after the pipeTo promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping from a ReadableStream from which lots of chunks are synchronously readable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL Piping from a ReadableStream for which a chunk becomes asynchronously readable after the pipeTo promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.serviceworker-expected.txt
index 2ad000e..4e3e65b 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.serviceworker-expected.txt
@@ -1,16 +1,16 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
 FAIL Piping must lock both the ReadableStream and WritableStream assert_true: the ReadableStream must become locked expected true got false
-FAIL Piping finishing must unlock both the ReadableStream and WritableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping finishing must unlock both the ReadableStream and WritableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 PASS pipeTo must check the brand of its ReadableStream this value
 PASS pipeTo must check the brand of its WritableStream argument
 PASS pipeTo must fail if the ReadableStream is locked, and not lock the WritableStream
 PASS pipeTo must fail if the WritableStream is locked, and not lock the ReadableStream
-FAIL Piping from a ReadableStream from which lots of chunks are synchronously readable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL Piping from a ReadableStream for which a chunk becomes asynchronously readable after the pipeTo promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping from a ReadableStream from which lots of chunks are synchronously readable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL Piping from a ReadableStream for which a chunk becomes asynchronously readable after the pipeTo promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.sharedworker-expected.txt
index c2e9ee38..6e9fc67 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.sharedworker-expected.txt
@@ -1,15 +1,15 @@
 This is a testharness.js-based test.
 FAIL Piping must lock both the ReadableStream and WritableStream assert_true: the ReadableStream must become locked expected true got false
-FAIL Piping finishing must unlock both the ReadableStream and WritableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping finishing must unlock both the ReadableStream and WritableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 PASS pipeTo must check the brand of its ReadableStream this value
 PASS pipeTo must check the brand of its WritableStream argument
 PASS pipeTo must fail if the ReadableStream is locked, and not lock the WritableStream
 PASS pipeTo must fail if the WritableStream is locked, and not lock the ReadableStream
-FAIL Piping from a ReadableStream from which lots of chunks are synchronously readable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL Piping from a ReadableStream for which a chunk becomes asynchronously readable after the pipeTo promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping from a ReadableStream from which lots of chunks are synchronously readable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL Piping from a ReadableStream for which a chunk becomes asynchronously readable after the pipeTo promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.worker-expected.txt
index c2e9ee38..6e9fc67 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/general.any.worker-expected.txt
@@ -1,15 +1,15 @@
 This is a testharness.js-based test.
 FAIL Piping must lock both the ReadableStream and WritableStream assert_true: the ReadableStream must become locked expected true got false
-FAIL Piping finishing must unlock both the ReadableStream and WritableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping finishing must unlock both the ReadableStream and WritableStream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 PASS pipeTo must check the brand of its ReadableStream this value
 PASS pipeTo must check the brand of its WritableStream argument
 PASS pipeTo must fail if the ReadableStream is locked, and not lock the WritableStream
 PASS pipeTo must fail if the WritableStream is locked, and not lock the ReadableStream
-FAIL Piping from a ReadableStream from which lots of chunks are synchronously readable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL Piping from a ReadableStream for which a chunk becomes asynchronously readable after the pipeTo promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping from a ReadableStream from which lots of chunks are synchronously readable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL Piping from a ReadableStream for which a chunk becomes asynchronously readable after the pipeTo promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from pull should cause pipeTo() to reject when preventAbort is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is true assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL an undefined rejection from write should cause pipeTo() to reject when preventCancel is false assert_equals: rejection value should be undefined expected (undefined) undefined but got (object) object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any-expected.txt
index 72fb64f..615015d 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
-FAIL Piping from an errored readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error2: error2!" ("error2")
-FAIL Piping from an errored readable stream to an errored writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to an erroring writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to an errored writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to a closing writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to a closed writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a closed readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a closed readable stream to an errored writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error2: error2!" ("error2")
-FAIL Piping from a closed readable stream to a closed writable stream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping from an errored readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error2: error2!" ("error2")
+FAIL Piping from an errored readable stream to an errored writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to an erroring writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to an errored writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to a closing writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to a closed writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a closed readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a closed readable stream to an errored writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error2: error2!" ("error2")
+FAIL Piping from a closed readable stream to a closed writable stream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.serviceworker-expected.txt
index 72fb64f..615015d 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.serviceworker-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
-FAIL Piping from an errored readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error2: error2!" ("error2")
-FAIL Piping from an errored readable stream to an errored writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to an erroring writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to an errored writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to a closing writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to a closed writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a closed readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a closed readable stream to an errored writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error2: error2!" ("error2")
-FAIL Piping from a closed readable stream to a closed writable stream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping from an errored readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error2: error2!" ("error2")
+FAIL Piping from an errored readable stream to an errored writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to an erroring writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to an errored writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to a closing writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to a closed writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a closed readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a closed readable stream to an errored writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error2: error2!" ("error2")
+FAIL Piping from a closed readable stream to a closed writable stream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.sharedworker-expected.txt
index 72fb64f..615015d 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.sharedworker-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
-FAIL Piping from an errored readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error2: error2!" ("error2")
-FAIL Piping from an errored readable stream to an errored writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to an erroring writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to an errored writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to a closing writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to a closed writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a closed readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a closed readable stream to an errored writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error2: error2!" ("error2")
-FAIL Piping from a closed readable stream to a closed writable stream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping from an errored readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error2: error2!" ("error2")
+FAIL Piping from an errored readable stream to an errored writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to an erroring writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to an errored writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to a closing writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to a closed writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a closed readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a closed readable stream to an errored writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error2: error2!" ("error2")
+FAIL Piping from a closed readable stream to a closed writable stream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.worker-expected.txt
index 72fb64f..615015d 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/multiple-propagation.any.worker-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
-FAIL Piping from an errored readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error2: error2!" ("error2")
-FAIL Piping from an errored readable stream to an errored writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to an erroring writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to an errored writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to a closing writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from an errored readable stream to a closed writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a closed readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1!" ("error1")
-FAIL Piping from a closed readable stream to an errored writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error2: error2!" ("error2")
-FAIL Piping from a closed readable stream to a closed writable stream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL Piping from an errored readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error2: error2!" ("error2")
+FAIL Piping from an errored readable stream to an errored writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to an erroring writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to an errored writable stream; preventAbort = true assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to a closing writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from an errored readable stream to a closed writable stream assert_throws: pipeTo must reject with the readable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a closed readable stream to an erroring writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error1: error1!" ("error1")
+FAIL Piping from a closed readable stream to an errored writable stream assert_throws: pipeTo must reject with the writable stream's error function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented" ("TypeError") expected object "error2: error2!" ("error2")
+FAIL Piping from a closed readable stream to a closed writable stream promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any-expected.txt
index 343dd47..f1a90efc 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any-expected.txt
@@ -1,42 +1,42 @@
 This is a testharness.js-based test.
-FAIL Piping through a duck-typed pass-through transform stream should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL Piping through a transform errored on the writable end does not cause an unhandled promise rejection Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL pipeThrough should not call pipeTo on this Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL pipeThrough should not call pipeTo on the ReadableStream prototype Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL Piping through a duck-typed pass-through transform stream should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL Piping through a transform errored on the writable end does not cause an unhandled promise rejection Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL pipeThrough should not call pipeTo on this Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL pipeThrough should not call pipeTo on the ReadableStream prototype Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 PASS pipeThrough should brand-check this and not allow 'null'
-PASS pipeThrough should brand-check readable and not allow 'null'
+FAIL pipeThrough should brand-check readable and not allow 'null' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'undefined'
-PASS pipeThrough should brand-check readable and not allow 'undefined'
+FAIL pipeThrough should brand-check readable and not allow 'undefined' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow '0'
-PASS pipeThrough should brand-check readable and not allow '0'
+FAIL pipeThrough should brand-check readable and not allow '0' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'NaN'
-PASS pipeThrough should brand-check readable and not allow 'NaN'
+FAIL pipeThrough should brand-check readable and not allow 'NaN' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'true'
-PASS pipeThrough should brand-check readable and not allow 'true'
+FAIL pipeThrough should brand-check readable and not allow 'true' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'ReadableStream'
-PASS pipeThrough should brand-check readable and not allow 'ReadableStream'
+FAIL pipeThrough should brand-check readable and not allow 'ReadableStream' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow '[object ReadableStream]'
-PASS pipeThrough should brand-check readable and not allow '[object ReadableStream]'
-PASS pipeThrough should brand-check writable and not allow 'null'
-PASS pipeThrough should brand-check writable and not allow 'undefined'
-PASS pipeThrough should brand-check writable and not allow '0'
-PASS pipeThrough should brand-check writable and not allow 'NaN'
-PASS pipeThrough should brand-check writable and not allow 'true'
-PASS pipeThrough should brand-check writable and not allow 'WritableStream'
-PASS pipeThrough should brand-check writable and not allow '[object WritableStream]'
-PASS pipeThrough should rethrow errors from accessing readable or writable
+FAIL pipeThrough should brand-check readable and not allow '[object ReadableStream]' assert_true: writable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'null' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'undefined' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow '0' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'NaN' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'true' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'WritableStream' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow '[object WritableStream]' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should rethrow errors from accessing readable or writable assert_throws: pipeThrough should rethrow the error thrown by the writable getter function "() => ReadableStream.prototype.pipeThrough.call(rs, throwingWritable, {})" threw object "TypeError: Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented" ("TypeError") expected object "custom" ("custom")
 PASS invalid values of signal should throw; specifically 'null'
 PASS invalid values of signal should throw; specifically '0'
 PASS invalid values of signal should throw; specifically 'NaN'
 PASS invalid values of signal should throw; specifically 'true'
 PASS invalid values of signal should throw; specifically 'AbortSignal'
 PASS invalid values of signal should throw; specifically '[object AbortSignal]'
-FAIL pipeThrough should accept a real AbortSignal Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL pipeThrough should accept a real AbortSignal Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 PASS pipeThrough should throw if this is locked
 PASS pipeThrough should throw if writable is locked
-FAIL pipeThrough should not care if readable is locked Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventCancel should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventClose should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventAbort should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL pipeThrough should not care if readable is locked Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventCancel should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventClose should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventAbort should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.serviceworker-expected.txt
index 343dd47..f1a90efc 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.serviceworker-expected.txt
@@ -1,42 +1,42 @@
 This is a testharness.js-based test.
-FAIL Piping through a duck-typed pass-through transform stream should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL Piping through a transform errored on the writable end does not cause an unhandled promise rejection Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL pipeThrough should not call pipeTo on this Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL pipeThrough should not call pipeTo on the ReadableStream prototype Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL Piping through a duck-typed pass-through transform stream should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL Piping through a transform errored on the writable end does not cause an unhandled promise rejection Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL pipeThrough should not call pipeTo on this Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL pipeThrough should not call pipeTo on the ReadableStream prototype Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 PASS pipeThrough should brand-check this and not allow 'null'
-PASS pipeThrough should brand-check readable and not allow 'null'
+FAIL pipeThrough should brand-check readable and not allow 'null' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'undefined'
-PASS pipeThrough should brand-check readable and not allow 'undefined'
+FAIL pipeThrough should brand-check readable and not allow 'undefined' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow '0'
-PASS pipeThrough should brand-check readable and not allow '0'
+FAIL pipeThrough should brand-check readable and not allow '0' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'NaN'
-PASS pipeThrough should brand-check readable and not allow 'NaN'
+FAIL pipeThrough should brand-check readable and not allow 'NaN' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'true'
-PASS pipeThrough should brand-check readable and not allow 'true'
+FAIL pipeThrough should brand-check readable and not allow 'true' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'ReadableStream'
-PASS pipeThrough should brand-check readable and not allow 'ReadableStream'
+FAIL pipeThrough should brand-check readable and not allow 'ReadableStream' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow '[object ReadableStream]'
-PASS pipeThrough should brand-check readable and not allow '[object ReadableStream]'
-PASS pipeThrough should brand-check writable and not allow 'null'
-PASS pipeThrough should brand-check writable and not allow 'undefined'
-PASS pipeThrough should brand-check writable and not allow '0'
-PASS pipeThrough should brand-check writable and not allow 'NaN'
-PASS pipeThrough should brand-check writable and not allow 'true'
-PASS pipeThrough should brand-check writable and not allow 'WritableStream'
-PASS pipeThrough should brand-check writable and not allow '[object WritableStream]'
-PASS pipeThrough should rethrow errors from accessing readable or writable
+FAIL pipeThrough should brand-check readable and not allow '[object ReadableStream]' assert_true: writable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'null' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'undefined' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow '0' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'NaN' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'true' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'WritableStream' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow '[object WritableStream]' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should rethrow errors from accessing readable or writable assert_throws: pipeThrough should rethrow the error thrown by the writable getter function "() => ReadableStream.prototype.pipeThrough.call(rs, throwingWritable, {})" threw object "TypeError: Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented" ("TypeError") expected object "custom" ("custom")
 PASS invalid values of signal should throw; specifically 'null'
 PASS invalid values of signal should throw; specifically '0'
 PASS invalid values of signal should throw; specifically 'NaN'
 PASS invalid values of signal should throw; specifically 'true'
 PASS invalid values of signal should throw; specifically 'AbortSignal'
 PASS invalid values of signal should throw; specifically '[object AbortSignal]'
-FAIL pipeThrough should accept a real AbortSignal Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL pipeThrough should accept a real AbortSignal Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 PASS pipeThrough should throw if this is locked
 PASS pipeThrough should throw if writable is locked
-FAIL pipeThrough should not care if readable is locked Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventCancel should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventClose should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventAbort should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL pipeThrough should not care if readable is locked Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventCancel should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventClose should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventAbort should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.sharedworker-expected.txt
index 343dd47..f1a90efc 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.sharedworker-expected.txt
@@ -1,42 +1,42 @@
 This is a testharness.js-based test.
-FAIL Piping through a duck-typed pass-through transform stream should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL Piping through a transform errored on the writable end does not cause an unhandled promise rejection Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL pipeThrough should not call pipeTo on this Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL pipeThrough should not call pipeTo on the ReadableStream prototype Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL Piping through a duck-typed pass-through transform stream should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL Piping through a transform errored on the writable end does not cause an unhandled promise rejection Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL pipeThrough should not call pipeTo on this Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL pipeThrough should not call pipeTo on the ReadableStream prototype Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 PASS pipeThrough should brand-check this and not allow 'null'
-PASS pipeThrough should brand-check readable and not allow 'null'
+FAIL pipeThrough should brand-check readable and not allow 'null' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'undefined'
-PASS pipeThrough should brand-check readable and not allow 'undefined'
+FAIL pipeThrough should brand-check readable and not allow 'undefined' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow '0'
-PASS pipeThrough should brand-check readable and not allow '0'
+FAIL pipeThrough should brand-check readable and not allow '0' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'NaN'
-PASS pipeThrough should brand-check readable and not allow 'NaN'
+FAIL pipeThrough should brand-check readable and not allow 'NaN' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'true'
-PASS pipeThrough should brand-check readable and not allow 'true'
+FAIL pipeThrough should brand-check readable and not allow 'true' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'ReadableStream'
-PASS pipeThrough should brand-check readable and not allow 'ReadableStream'
+FAIL pipeThrough should brand-check readable and not allow 'ReadableStream' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow '[object ReadableStream]'
-PASS pipeThrough should brand-check readable and not allow '[object ReadableStream]'
-PASS pipeThrough should brand-check writable and not allow 'null'
-PASS pipeThrough should brand-check writable and not allow 'undefined'
-PASS pipeThrough should brand-check writable and not allow '0'
-PASS pipeThrough should brand-check writable and not allow 'NaN'
-PASS pipeThrough should brand-check writable and not allow 'true'
-PASS pipeThrough should brand-check writable and not allow 'WritableStream'
-PASS pipeThrough should brand-check writable and not allow '[object WritableStream]'
-PASS pipeThrough should rethrow errors from accessing readable or writable
+FAIL pipeThrough should brand-check readable and not allow '[object ReadableStream]' assert_true: writable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'null' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'undefined' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow '0' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'NaN' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'true' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'WritableStream' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow '[object WritableStream]' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should rethrow errors from accessing readable or writable assert_throws: pipeThrough should rethrow the error thrown by the writable getter function "() => ReadableStream.prototype.pipeThrough.call(rs, throwingWritable, {})" threw object "TypeError: Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented" ("TypeError") expected object "custom" ("custom")
 PASS invalid values of signal should throw; specifically 'null'
 PASS invalid values of signal should throw; specifically '0'
 PASS invalid values of signal should throw; specifically 'NaN'
 PASS invalid values of signal should throw; specifically 'true'
 PASS invalid values of signal should throw; specifically 'AbortSignal'
 PASS invalid values of signal should throw; specifically '[object AbortSignal]'
-FAIL pipeThrough should accept a real AbortSignal Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL pipeThrough should accept a real AbortSignal Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 PASS pipeThrough should throw if this is locked
 PASS pipeThrough should throw if writable is locked
-FAIL pipeThrough should not care if readable is locked Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventCancel should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventClose should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventAbort should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL pipeThrough should not care if readable is locked Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventCancel should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventClose should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventAbort should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.worker-expected.txt
index 343dd47..f1a90efc 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/pipe-through.any.worker-expected.txt
@@ -1,42 +1,42 @@
 This is a testharness.js-based test.
-FAIL Piping through a duck-typed pass-through transform stream should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL Piping through a transform errored on the writable end does not cause an unhandled promise rejection Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL pipeThrough should not call pipeTo on this Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL pipeThrough should not call pipeTo on the ReadableStream prototype Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL Piping through a duck-typed pass-through transform stream should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL Piping through a transform errored on the writable end does not cause an unhandled promise rejection Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL pipeThrough should not call pipeTo on this Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL pipeThrough should not call pipeTo on the ReadableStream prototype Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 PASS pipeThrough should brand-check this and not allow 'null'
-PASS pipeThrough should brand-check readable and not allow 'null'
+FAIL pipeThrough should brand-check readable and not allow 'null' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'undefined'
-PASS pipeThrough should brand-check readable and not allow 'undefined'
+FAIL pipeThrough should brand-check readable and not allow 'undefined' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow '0'
-PASS pipeThrough should brand-check readable and not allow '0'
+FAIL pipeThrough should brand-check readable and not allow '0' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'NaN'
-PASS pipeThrough should brand-check readable and not allow 'NaN'
+FAIL pipeThrough should brand-check readable and not allow 'NaN' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'true'
-PASS pipeThrough should brand-check readable and not allow 'true'
+FAIL pipeThrough should brand-check readable and not allow 'true' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow 'ReadableStream'
-PASS pipeThrough should brand-check readable and not allow 'ReadableStream'
+FAIL pipeThrough should brand-check readable and not allow 'ReadableStream' assert_true: writable should have been accessed expected true got false
 PASS pipeThrough should brand-check this and not allow '[object ReadableStream]'
-PASS pipeThrough should brand-check readable and not allow '[object ReadableStream]'
-PASS pipeThrough should brand-check writable and not allow 'null'
-PASS pipeThrough should brand-check writable and not allow 'undefined'
-PASS pipeThrough should brand-check writable and not allow '0'
-PASS pipeThrough should brand-check writable and not allow 'NaN'
-PASS pipeThrough should brand-check writable and not allow 'true'
-PASS pipeThrough should brand-check writable and not allow 'WritableStream'
-PASS pipeThrough should brand-check writable and not allow '[object WritableStream]'
-PASS pipeThrough should rethrow errors from accessing readable or writable
+FAIL pipeThrough should brand-check readable and not allow '[object ReadableStream]' assert_true: writable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'null' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'undefined' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow '0' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'NaN' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'true' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow 'WritableStream' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should brand-check writable and not allow '[object WritableStream]' assert_true: readable should have been accessed expected true got false
+FAIL pipeThrough should rethrow errors from accessing readable or writable assert_throws: pipeThrough should rethrow the error thrown by the writable getter function "() => ReadableStream.prototype.pipeThrough.call(rs, throwingWritable, {})" threw object "TypeError: Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented" ("TypeError") expected object "custom" ("custom")
 PASS invalid values of signal should throw; specifically 'null'
 PASS invalid values of signal should throw; specifically '0'
 PASS invalid values of signal should throw; specifically 'NaN'
 PASS invalid values of signal should throw; specifically 'true'
 PASS invalid values of signal should throw; specifically 'AbortSignal'
 PASS invalid values of signal should throw; specifically '[object AbortSignal]'
-FAIL pipeThrough should accept a real AbortSignal Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL pipeThrough should accept a real AbortSignal Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 PASS pipeThrough should throw if this is locked
 PASS pipeThrough should throw if writable is locked
-FAIL pipeThrough should not care if readable is locked Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventCancel should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventClose should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
-FAIL preventAbort should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL pipeThrough should not care if readable is locked Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventCancel should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventClose should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
+FAIL preventAbort should work Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough not yet implemented
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/then-interception.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/then-interception.any-expected.txt
index b6257f1..37259389 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/then-interception.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/then-interception.any-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL piping should not be observable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
-FAIL tee should not be observable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled"
+FAIL piping should not be observable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
+FAIL tee should not be observable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any-expected.txt
new file mode 100644
index 0000000..13d86ff9
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL Can get the ReadableByteStreamController constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStreamBYOBReader enforces a brand check on its argument
+FAIL ReadableStreamBYOBReader.prototype.closed enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.cancel enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.read enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check Cannot read property 'prototype' of undefined
+PASS ReadableByteStreamController enforces a brand check on its arguments
+PASS ReadableByteStreamController can't be given a fully-constructed ReadableStream
+FAIL ReadableByteStreamController.prototype.byobRequest enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.close enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.enqueue enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.error enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBRequest enforces brand checks Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.serviceworker-expected.txt
new file mode 100644
index 0000000..13d86ff9
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.serviceworker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL Can get the ReadableByteStreamController constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStreamBYOBReader enforces a brand check on its argument
+FAIL ReadableStreamBYOBReader.prototype.closed enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.cancel enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.read enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check Cannot read property 'prototype' of undefined
+PASS ReadableByteStreamController enforces a brand check on its arguments
+PASS ReadableByteStreamController can't be given a fully-constructed ReadableStream
+FAIL ReadableByteStreamController.prototype.byobRequest enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.close enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.enqueue enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.error enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBRequest enforces brand checks Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.sharedworker-expected.txt
new file mode 100644
index 0000000..13d86ff9
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.sharedworker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL Can get the ReadableByteStreamController constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStreamBYOBReader enforces a brand check on its argument
+FAIL ReadableStreamBYOBReader.prototype.closed enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.cancel enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.read enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check Cannot read property 'prototype' of undefined
+PASS ReadableByteStreamController enforces a brand check on its arguments
+PASS ReadableByteStreamController can't be given a fully-constructed ReadableStream
+FAIL ReadableByteStreamController.prototype.byobRequest enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.close enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.enqueue enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.error enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBRequest enforces brand checks Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.worker-expected.txt
new file mode 100644
index 0000000..13d86ff9
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/brand-checks.any.worker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL Can get the ReadableByteStreamController constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStreamBYOBReader enforces a brand check on its argument
+FAIL ReadableStreamBYOBReader.prototype.closed enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.cancel enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.read enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check Cannot read property 'prototype' of undefined
+PASS ReadableByteStreamController enforces a brand check on its arguments
+PASS ReadableByteStreamController can't be given a fully-constructed ReadableStream
+FAIL ReadableByteStreamController.prototype.byobRequest enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.close enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.enqueue enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.error enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBRequest enforces brand checks Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any-expected.txt
new file mode 100644
index 0000000..8ec519e1
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL construct-byob-request Uncaught RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any.sharedworker-expected.txt
new file mode 100644
index 0000000..8ec519e1
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any.sharedworker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL construct-byob-request Uncaught RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any.worker-expected.txt
new file mode 100644
index 0000000..8ec519e1
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/construct-byob-request.any.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL construct-byob-request Uncaught RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any-expected.txt
new file mode 100644
index 0000000..76867b4
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL ReadableStream with byte source: read()ing from a closed stream still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueuing an already-detached buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: reading into an already-detached buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.serviceworker-expected.txt
new file mode 100644
index 0000000..76867b4
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.serviceworker-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL ReadableStream with byte source: read()ing from a closed stream still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueuing an already-detached buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: reading into an already-detached buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.sharedworker-expected.txt
new file mode 100644
index 0000000..76867b4
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.sharedworker-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL ReadableStream with byte source: read()ing from a closed stream still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueuing an already-detached buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: reading into an already-detached buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.worker-expected.txt
new file mode 100644
index 0000000..76867b4
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/detached-buffers.any.worker-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL ReadableStream with byte source: read()ing from a closed stream still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueuing an already-detached buffer throws Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: reading into an already-detached buffer rejects Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state) Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any-expected.txt
new file mode 100644
index 0000000..1ccd08a
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any-expected.txt
@@ -0,0 +1,84 @@
+This is a testharness.js-based test.
+Found 77 tests; 2 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS getReader({mode: "byob"}) throws on non-bytes streams
+FAIL ReadableStream with byte source can be constructed with no errors Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL getReader({mode}) must perform ToString() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Construct and expect start and pull being called Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: No automatic pull call if start doesn't finish Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Construct with highWaterMark of 0 Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: desiredSize when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: desiredSize when errored Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader() with mode set to byob, then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that closing a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that erroring a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: releaseLock() on ReadableStreamReader with pending read() must throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() and read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: autoAllocateChunkSize Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Mix of auto allocate and BYOB Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() and read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Push source that doesn't understand pull signal Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: pull() function is not callable assert_throws: constructor should throw function "() => new ReadableStream({
+    pull: 'foo',
+    type: 'bytes'
+  })" threw object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), read(view) partially, then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), enqueue(), close(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), close(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to pull() by enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to pull() by enqueue() asynchronously Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to multiple pull() by separate enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() with too big value Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), read(view), then cancel() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: cancel() with partially filled pending pull() request Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a smaller views Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throw if close()-ed more than once Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throw on enqueue() after close() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() and close() in pull() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read() twice, then enqueue() twice Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view), close() and respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view), big enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view) and multiple enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with passing undefined as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with zero-length view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with passing an empty object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read() on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respond() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respondWithNewView() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respond(0) twice on the same byobRequest should throw even when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL pull() resolving should not make releaseLock() possible Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader can be constructed directly Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires a ReadableStream argument Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires an unlocked ReadableStream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes" Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.serviceworker-expected.txt
new file mode 100644
index 0000000..1ccd08a
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.serviceworker-expected.txt
@@ -0,0 +1,84 @@
+This is a testharness.js-based test.
+Found 77 tests; 2 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS getReader({mode: "byob"}) throws on non-bytes streams
+FAIL ReadableStream with byte source can be constructed with no errors Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL getReader({mode}) must perform ToString() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Construct and expect start and pull being called Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: No automatic pull call if start doesn't finish Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Construct with highWaterMark of 0 Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: desiredSize when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: desiredSize when errored Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader() with mode set to byob, then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that closing a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that erroring a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: releaseLock() on ReadableStreamReader with pending read() must throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() and read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: autoAllocateChunkSize Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Mix of auto allocate and BYOB Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() and read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Push source that doesn't understand pull signal Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: pull() function is not callable assert_throws: constructor should throw function "() => new ReadableStream({
+    pull: 'foo',
+    type: 'bytes'
+  })" threw object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), read(view) partially, then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), enqueue(), close(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), close(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to pull() by enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to pull() by enqueue() asynchronously Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to multiple pull() by separate enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() with too big value Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), read(view), then cancel() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: cancel() with partially filled pending pull() request Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a smaller views Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throw if close()-ed more than once Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throw on enqueue() after close() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() and close() in pull() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read() twice, then enqueue() twice Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view), close() and respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view), big enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view) and multiple enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with passing undefined as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with zero-length view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with passing an empty object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read() on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respond() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respondWithNewView() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respond(0) twice on the same byobRequest should throw even when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL pull() resolving should not make releaseLock() possible Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader can be constructed directly Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires a ReadableStream argument Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires an unlocked ReadableStream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes" Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.sharedworker-expected.txt
new file mode 100644
index 0000000..1ccd08a
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.sharedworker-expected.txt
@@ -0,0 +1,84 @@
+This is a testharness.js-based test.
+Found 77 tests; 2 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS getReader({mode: "byob"}) throws on non-bytes streams
+FAIL ReadableStream with byte source can be constructed with no errors Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL getReader({mode}) must perform ToString() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Construct and expect start and pull being called Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: No automatic pull call if start doesn't finish Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Construct with highWaterMark of 0 Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: desiredSize when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: desiredSize when errored Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader() with mode set to byob, then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that closing a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that erroring a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: releaseLock() on ReadableStreamReader with pending read() must throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() and read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: autoAllocateChunkSize Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Mix of auto allocate and BYOB Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() and read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Push source that doesn't understand pull signal Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: pull() function is not callable assert_throws: constructor should throw function "() => new ReadableStream({
+    pull: 'foo',
+    type: 'bytes'
+  })" threw object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), read(view) partially, then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), enqueue(), close(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), close(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to pull() by enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to pull() by enqueue() asynchronously Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to multiple pull() by separate enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() with too big value Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), read(view), then cancel() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: cancel() with partially filled pending pull() request Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a smaller views Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throw if close()-ed more than once Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throw on enqueue() after close() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() and close() in pull() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read() twice, then enqueue() twice Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view), close() and respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view), big enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view) and multiple enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with passing undefined as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with zero-length view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with passing an empty object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read() on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respond() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respondWithNewView() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respond(0) twice on the same byobRequest should throw even when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL pull() resolving should not make releaseLock() possible Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader can be constructed directly Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires a ReadableStream argument Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires an unlocked ReadableStream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes" Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.worker-expected.txt
new file mode 100644
index 0000000..1ccd08a
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/general.any.worker-expected.txt
@@ -0,0 +1,84 @@
+This is a testharness.js-based test.
+Found 77 tests; 2 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS getReader({mode: "byob"}) throws on non-bytes streams
+FAIL ReadableStream with byte source can be constructed with no errors Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL getReader({mode}) must perform ToString() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Construct and expect start and pull being called Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: No automatic pull call if start doesn't finish Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Construct with highWaterMark of 0 Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: desiredSize when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: desiredSize when errored Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader() with mode set to byob, then releaseLock() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that closing a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that erroring a stream does not release a reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: releaseLock() on ReadableStreamReader with pending read() must throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() and read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: autoAllocateChunkSize Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Mix of auto allocate and BYOB Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Automatic pull() after start() and read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Push source that doesn't understand pull signal Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: pull() function is not callable assert_throws: constructor should throw function "() => new ReadableStream({
+    pull: 'foo',
+    type: 'bytes'
+  })" threw object "RangeError: Failed to construct 'ReadableStream': bytes type is not yet implemented" ("RangeError") expected object "TypeError" ("TypeError")
+FAIL ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), read(view) partially, then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), enqueue(), close(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), close(), getReader(), then read() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to pull() by enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to pull() by enqueue() asynchronously Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Respond to multiple pull() by separate enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() with too big value Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: getReader(), read(view), then cancel() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: cancel() with partially filled pending pull() request Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view) Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue(), getReader(), then read(view) with a smaller views Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throw if close()-ed more than once Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throw on enqueue() after close() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then respond() and close() in pull() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read() twice, then enqueue() twice Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view), close() and respond() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view), big enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Multiple read(view) and multiple enqueue() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with passing undefined as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with zero-length view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) with passing an empty object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read() on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view) on an errored stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: read(view), then error() Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respond() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respondWithNewView() twice on the same byobRequest should throw Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL calling respond(0) twice on the same byobRequest should throw even when closed Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL pull() resolving should not make releaseLock() possible Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader can be constructed directly Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires a ReadableStream argument Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires an unlocked ReadableStream Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes" Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any-expected.txt
new file mode 100644
index 0000000..46b3754
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStreamBYOBReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamBYOBReader instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBRequest instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableByteStreamController instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.serviceworker-expected.txt
new file mode 100644
index 0000000..46b3754
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.serviceworker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStreamBYOBReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamBYOBReader instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBRequest instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableByteStreamController instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.sharedworker-expected.txt
new file mode 100644
index 0000000..46b3754
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.sharedworker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStreamBYOBReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamBYOBReader instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBRequest instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableByteStreamController instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.worker-expected.txt
new file mode 100644
index 0000000..46b3754
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-byte-streams/properties.any.worker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly Failed to construct 'ReadableStream': bytes type is not yet implemented
+PASS ReadableStreamBYOBReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamBYOBReader instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableStreamBYOBRequest instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+FAIL ReadableByteStreamController instances should have the correct list of properties Failed to construct 'ReadableStream': bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any-expected.txt
new file mode 100644
index 0000000..f1581e3
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+PASS Can get the ReadableStreamDefaultReader constructor indirectly
+PASS ReadableStreamDefaultReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamDefaultReader instances should have the correct list of properties assert_equals: cancel has 1 parameter expected 1 but got 0
+PASS ReadableStreamDefaultReader closed should always return the same promise object
+PASS Constructing a ReadableStreamDefaultReader directly should fail if the stream is already locked (via direct construction)
+PASS Getting a ReadableStreamDefaultReader via getReader should fail if the stream is already locked (via direct construction)
+PASS Constructing a ReadableStreamDefaultReader directly should fail if the stream is already locked (via getReader)
+PASS Getting a ReadableStreamDefaultReader via getReader should fail if the stream is already locked (via getReader)
+PASS Constructing a ReadableStreamDefaultReader directly should be OK if the stream is closed
+PASS Constructing a ReadableStreamDefaultReader directly should be OK if the stream is errored
+PASS Reading from a reader for an empty stream will wait until a chunk is available
+PASS cancel() on a reader does not release the reader
+PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
+PASS closed should be rejected after reader releases its lock (multiple stream locks)
+PASS Multiple readers can access the stream in sequence
+PASS Cannot use an already-released reader to unlock a stream again
+PASS cancel() on a released reader is a no-op and does not pass through
+PASS Getting a second reader after erroring the stream and releasing the reader should succeed
+PASS ReadableStreamDefaultReader closed promise should be rejected with undefined if that is the error
+PASS ReadableStreamDefaultReader: if start rejects with no parameter, it should error the stream with an undefined error
+PASS Erroring a ReadableStream after checking closed should reject ReadableStreamDefaultReader closed promise
+PASS Erroring a ReadableStream before checking closed should reject ReadableStreamDefaultReader closed promise
+PASS Reading twice on a stream that gets closed
+PASS Reading twice on a closed stream
+PASS Reading twice on an errored stream
+PASS Reading twice on a stream that gets errored
+PASS getReader() should call ToString() on mode
+PASS controller.close() should clear the list of pending read requests
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.serviceworker-expected.txt
new file mode 100644
index 0000000..f1581e3
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.serviceworker-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+PASS Can get the ReadableStreamDefaultReader constructor indirectly
+PASS ReadableStreamDefaultReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamDefaultReader instances should have the correct list of properties assert_equals: cancel has 1 parameter expected 1 but got 0
+PASS ReadableStreamDefaultReader closed should always return the same promise object
+PASS Constructing a ReadableStreamDefaultReader directly should fail if the stream is already locked (via direct construction)
+PASS Getting a ReadableStreamDefaultReader via getReader should fail if the stream is already locked (via direct construction)
+PASS Constructing a ReadableStreamDefaultReader directly should fail if the stream is already locked (via getReader)
+PASS Getting a ReadableStreamDefaultReader via getReader should fail if the stream is already locked (via getReader)
+PASS Constructing a ReadableStreamDefaultReader directly should be OK if the stream is closed
+PASS Constructing a ReadableStreamDefaultReader directly should be OK if the stream is errored
+PASS Reading from a reader for an empty stream will wait until a chunk is available
+PASS cancel() on a reader does not release the reader
+PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
+PASS closed should be rejected after reader releases its lock (multiple stream locks)
+PASS Multiple readers can access the stream in sequence
+PASS Cannot use an already-released reader to unlock a stream again
+PASS cancel() on a released reader is a no-op and does not pass through
+PASS Getting a second reader after erroring the stream and releasing the reader should succeed
+PASS ReadableStreamDefaultReader closed promise should be rejected with undefined if that is the error
+PASS ReadableStreamDefaultReader: if start rejects with no parameter, it should error the stream with an undefined error
+PASS Erroring a ReadableStream after checking closed should reject ReadableStreamDefaultReader closed promise
+PASS Erroring a ReadableStream before checking closed should reject ReadableStreamDefaultReader closed promise
+PASS Reading twice on a stream that gets closed
+PASS Reading twice on a closed stream
+PASS Reading twice on an errored stream
+PASS Reading twice on a stream that gets errored
+PASS getReader() should call ToString() on mode
+PASS controller.close() should clear the list of pending read requests
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.sharedworker-expected.txt
new file mode 100644
index 0000000..f1581e3
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.sharedworker-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+PASS Can get the ReadableStreamDefaultReader constructor indirectly
+PASS ReadableStreamDefaultReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamDefaultReader instances should have the correct list of properties assert_equals: cancel has 1 parameter expected 1 but got 0
+PASS ReadableStreamDefaultReader closed should always return the same promise object
+PASS Constructing a ReadableStreamDefaultReader directly should fail if the stream is already locked (via direct construction)
+PASS Getting a ReadableStreamDefaultReader via getReader should fail if the stream is already locked (via direct construction)
+PASS Constructing a ReadableStreamDefaultReader directly should fail if the stream is already locked (via getReader)
+PASS Getting a ReadableStreamDefaultReader via getReader should fail if the stream is already locked (via getReader)
+PASS Constructing a ReadableStreamDefaultReader directly should be OK if the stream is closed
+PASS Constructing a ReadableStreamDefaultReader directly should be OK if the stream is errored
+PASS Reading from a reader for an empty stream will wait until a chunk is available
+PASS cancel() on a reader does not release the reader
+PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
+PASS closed should be rejected after reader releases its lock (multiple stream locks)
+PASS Multiple readers can access the stream in sequence
+PASS Cannot use an already-released reader to unlock a stream again
+PASS cancel() on a released reader is a no-op and does not pass through
+PASS Getting a second reader after erroring the stream and releasing the reader should succeed
+PASS ReadableStreamDefaultReader closed promise should be rejected with undefined if that is the error
+PASS ReadableStreamDefaultReader: if start rejects with no parameter, it should error the stream with an undefined error
+PASS Erroring a ReadableStream after checking closed should reject ReadableStreamDefaultReader closed promise
+PASS Erroring a ReadableStream before checking closed should reject ReadableStreamDefaultReader closed promise
+PASS Reading twice on a stream that gets closed
+PASS Reading twice on a closed stream
+PASS Reading twice on an errored stream
+PASS Reading twice on a stream that gets errored
+PASS getReader() should call ToString() on mode
+PASS controller.close() should clear the list of pending read requests
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.worker-expected.txt
new file mode 100644
index 0000000..f1581e3
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/default-reader.any.worker-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+PASS Can get the ReadableStreamDefaultReader constructor indirectly
+PASS ReadableStreamDefaultReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamDefaultReader instances should have the correct list of properties assert_equals: cancel has 1 parameter expected 1 but got 0
+PASS ReadableStreamDefaultReader closed should always return the same promise object
+PASS Constructing a ReadableStreamDefaultReader directly should fail if the stream is already locked (via direct construction)
+PASS Getting a ReadableStreamDefaultReader via getReader should fail if the stream is already locked (via direct construction)
+PASS Constructing a ReadableStreamDefaultReader directly should fail if the stream is already locked (via getReader)
+PASS Getting a ReadableStreamDefaultReader via getReader should fail if the stream is already locked (via getReader)
+PASS Constructing a ReadableStreamDefaultReader directly should be OK if the stream is closed
+PASS Constructing a ReadableStreamDefaultReader directly should be OK if the stream is errored
+PASS Reading from a reader for an empty stream will wait until a chunk is available
+PASS cancel() on a reader does not release the reader
+PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
+PASS closed should be rejected after reader releases its lock (multiple stream locks)
+PASS Multiple readers can access the stream in sequence
+PASS Cannot use an already-released reader to unlock a stream again
+PASS cancel() on a released reader is a no-op and does not pass through
+PASS Getting a second reader after erroring the stream and releasing the reader should succeed
+PASS ReadableStreamDefaultReader closed promise should be rejected with undefined if that is the error
+PASS ReadableStreamDefaultReader: if start rejects with no parameter, it should error the stream with an undefined error
+PASS Erroring a ReadableStream after checking closed should reject ReadableStreamDefaultReader closed promise
+PASS Erroring a ReadableStream before checking closed should reject ReadableStreamDefaultReader closed promise
+PASS Reading twice on a stream that gets closed
+PASS Reading twice on a closed stream
+PASS Reading twice on an errored stream
+PASS Reading twice on a stream that gets errored
+PASS getReader() should call ToString() on mode
+PASS controller.close() should clear the list of pending read requests
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any-expected.txt
new file mode 100644
index 0000000..0d1c378
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any-expected.txt
@@ -0,0 +1,42 @@
+This is a testharness.js-based test.
+PASS ReadableStream can be constructed with no errors
+PASS ReadableStream can't be constructed with garbage
+PASS ReadableStream can't be constructed with an invalid type
+FAIL ReadableStream instances should have the correct list of properties assert_array_equals: should have all the correct properties lengths differ, expected 8 got 7
+PASS ReadableStream constructor should throw for non-function start arguments
+PASS ReadableStream constructor will not tolerate initial garbage as cancel argument
+PASS ReadableStream constructor will not tolerate initial garbage as pull argument
+FAIL ReadableStream start should be called with the proper parameters assert_equals: enqueue should have 1 parameter expected 1 but got 0
+PASS ReadableStream start controller parameter should be extensible
+PASS default ReadableStream getReader() should only accept mode:undefined
+PASS ReadableStream should be able to call start method within prototype chain of its source
+PASS ReadableStream start should be able to return a promise
+PASS ReadableStream start should be able to return a promise and reject it
+PASS ReadableStream should be able to enqueue different objects.
+PASS ReadableStream: if pull rejects, it should error the stream
+PASS ReadableStream: should only call pull once upon starting the stream
+PASS ReadableStream: should call pull when trying to read from a started, empty stream
+PASS ReadableStream: should only call pull once on a non-empty stream read from before start fulfills
+PASS ReadableStream: should only call pull once on a non-empty stream read from after start fulfills
+PASS ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining
+PASS ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining
+PASS ReadableStream: should not call pull until the previous pull call's promise fulfills
+PASS ReadableStream: should pull after start, and after every read
+PASS ReadableStream: should not call pull after start if the stream is now closed
+PASS ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows
+PASS ReadableStream pull should be able to close a stream.
+PASS ReadableStream pull should be able to error a stream.
+PASS ReadableStream pull should be able to error a stream and throw.
+PASS ReadableStream: enqueue should throw when the stream is readable but draining
+PASS ReadableStream: enqueue should throw when the stream is closed
+PASS ReadableStream: should call underlying source methods as methods
+PASS ReadableStream: desiredSize when closed
+PASS ReadableStream: desiredSize when errored
+PASS Subclassing ReadableStream should work
+PASS ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue
+PASS ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately
+PASS ReadableStream integration test: adapting a random push source
+PASS ReadableStream integration test: adapting a sync pull source
+PASS ReadableStream integration test: adapting an async pull source
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.serviceworker-expected.txt
new file mode 100644
index 0000000..0d1c378
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.serviceworker-expected.txt
@@ -0,0 +1,42 @@
+This is a testharness.js-based test.
+PASS ReadableStream can be constructed with no errors
+PASS ReadableStream can't be constructed with garbage
+PASS ReadableStream can't be constructed with an invalid type
+FAIL ReadableStream instances should have the correct list of properties assert_array_equals: should have all the correct properties lengths differ, expected 8 got 7
+PASS ReadableStream constructor should throw for non-function start arguments
+PASS ReadableStream constructor will not tolerate initial garbage as cancel argument
+PASS ReadableStream constructor will not tolerate initial garbage as pull argument
+FAIL ReadableStream start should be called with the proper parameters assert_equals: enqueue should have 1 parameter expected 1 but got 0
+PASS ReadableStream start controller parameter should be extensible
+PASS default ReadableStream getReader() should only accept mode:undefined
+PASS ReadableStream should be able to call start method within prototype chain of its source
+PASS ReadableStream start should be able to return a promise
+PASS ReadableStream start should be able to return a promise and reject it
+PASS ReadableStream should be able to enqueue different objects.
+PASS ReadableStream: if pull rejects, it should error the stream
+PASS ReadableStream: should only call pull once upon starting the stream
+PASS ReadableStream: should call pull when trying to read from a started, empty stream
+PASS ReadableStream: should only call pull once on a non-empty stream read from before start fulfills
+PASS ReadableStream: should only call pull once on a non-empty stream read from after start fulfills
+PASS ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining
+PASS ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining
+PASS ReadableStream: should not call pull until the previous pull call's promise fulfills
+PASS ReadableStream: should pull after start, and after every read
+PASS ReadableStream: should not call pull after start if the stream is now closed
+PASS ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows
+PASS ReadableStream pull should be able to close a stream.
+PASS ReadableStream pull should be able to error a stream.
+PASS ReadableStream pull should be able to error a stream and throw.
+PASS ReadableStream: enqueue should throw when the stream is readable but draining
+PASS ReadableStream: enqueue should throw when the stream is closed
+PASS ReadableStream: should call underlying source methods as methods
+PASS ReadableStream: desiredSize when closed
+PASS ReadableStream: desiredSize when errored
+PASS Subclassing ReadableStream should work
+PASS ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue
+PASS ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately
+PASS ReadableStream integration test: adapting a random push source
+PASS ReadableStream integration test: adapting a sync pull source
+PASS ReadableStream integration test: adapting an async pull source
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.sharedworker-expected.txt
new file mode 100644
index 0000000..0d1c378
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.sharedworker-expected.txt
@@ -0,0 +1,42 @@
+This is a testharness.js-based test.
+PASS ReadableStream can be constructed with no errors
+PASS ReadableStream can't be constructed with garbage
+PASS ReadableStream can't be constructed with an invalid type
+FAIL ReadableStream instances should have the correct list of properties assert_array_equals: should have all the correct properties lengths differ, expected 8 got 7
+PASS ReadableStream constructor should throw for non-function start arguments
+PASS ReadableStream constructor will not tolerate initial garbage as cancel argument
+PASS ReadableStream constructor will not tolerate initial garbage as pull argument
+FAIL ReadableStream start should be called with the proper parameters assert_equals: enqueue should have 1 parameter expected 1 but got 0
+PASS ReadableStream start controller parameter should be extensible
+PASS default ReadableStream getReader() should only accept mode:undefined
+PASS ReadableStream should be able to call start method within prototype chain of its source
+PASS ReadableStream start should be able to return a promise
+PASS ReadableStream start should be able to return a promise and reject it
+PASS ReadableStream should be able to enqueue different objects.
+PASS ReadableStream: if pull rejects, it should error the stream
+PASS ReadableStream: should only call pull once upon starting the stream
+PASS ReadableStream: should call pull when trying to read from a started, empty stream
+PASS ReadableStream: should only call pull once on a non-empty stream read from before start fulfills
+PASS ReadableStream: should only call pull once on a non-empty stream read from after start fulfills
+PASS ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining
+PASS ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining
+PASS ReadableStream: should not call pull until the previous pull call's promise fulfills
+PASS ReadableStream: should pull after start, and after every read
+PASS ReadableStream: should not call pull after start if the stream is now closed
+PASS ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows
+PASS ReadableStream pull should be able to close a stream.
+PASS ReadableStream pull should be able to error a stream.
+PASS ReadableStream pull should be able to error a stream and throw.
+PASS ReadableStream: enqueue should throw when the stream is readable but draining
+PASS ReadableStream: enqueue should throw when the stream is closed
+PASS ReadableStream: should call underlying source methods as methods
+PASS ReadableStream: desiredSize when closed
+PASS ReadableStream: desiredSize when errored
+PASS Subclassing ReadableStream should work
+PASS ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue
+PASS ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately
+PASS ReadableStream integration test: adapting a random push source
+PASS ReadableStream integration test: adapting a sync pull source
+PASS ReadableStream integration test: adapting an async pull source
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.worker-expected.txt
new file mode 100644
index 0000000..0d1c378
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/general.any.worker-expected.txt
@@ -0,0 +1,42 @@
+This is a testharness.js-based test.
+PASS ReadableStream can be constructed with no errors
+PASS ReadableStream can't be constructed with garbage
+PASS ReadableStream can't be constructed with an invalid type
+FAIL ReadableStream instances should have the correct list of properties assert_array_equals: should have all the correct properties lengths differ, expected 8 got 7
+PASS ReadableStream constructor should throw for non-function start arguments
+PASS ReadableStream constructor will not tolerate initial garbage as cancel argument
+PASS ReadableStream constructor will not tolerate initial garbage as pull argument
+FAIL ReadableStream start should be called with the proper parameters assert_equals: enqueue should have 1 parameter expected 1 but got 0
+PASS ReadableStream start controller parameter should be extensible
+PASS default ReadableStream getReader() should only accept mode:undefined
+PASS ReadableStream should be able to call start method within prototype chain of its source
+PASS ReadableStream start should be able to return a promise
+PASS ReadableStream start should be able to return a promise and reject it
+PASS ReadableStream should be able to enqueue different objects.
+PASS ReadableStream: if pull rejects, it should error the stream
+PASS ReadableStream: should only call pull once upon starting the stream
+PASS ReadableStream: should call pull when trying to read from a started, empty stream
+PASS ReadableStream: should only call pull once on a non-empty stream read from before start fulfills
+PASS ReadableStream: should only call pull once on a non-empty stream read from after start fulfills
+PASS ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining
+PASS ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining
+PASS ReadableStream: should not call pull until the previous pull call's promise fulfills
+PASS ReadableStream: should pull after start, and after every read
+PASS ReadableStream: should not call pull after start if the stream is now closed
+PASS ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows
+PASS ReadableStream pull should be able to close a stream.
+PASS ReadableStream pull should be able to error a stream.
+PASS ReadableStream pull should be able to error a stream and throw.
+PASS ReadableStream: enqueue should throw when the stream is readable but draining
+PASS ReadableStream: enqueue should throw when the stream is closed
+PASS ReadableStream: should call underlying source methods as methods
+PASS ReadableStream: desiredSize when closed
+PASS ReadableStream: desiredSize when errored
+PASS Subclassing ReadableStream should work
+PASS ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue
+PASS ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately
+PASS ReadableStream integration test: adapting a random push source
+PASS ReadableStream integration test: adapting a sync pull source
+PASS ReadableStream integration test: adapting an async pull source
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any-expected.txt
index 508c1a7..d553698 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
 PASS enqueue() inside size() should work
 PASS close() inside size() should not crash
 PASS close request inside size() should work
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.serviceworker-expected.txt
index 508c1a7..d553698 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.serviceworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
 PASS enqueue() inside size() should work
 PASS close() inside size() should not crash
 PASS close request inside size() should work
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.sharedworker-expected.txt
index 508c1a7..d553698 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.sharedworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
 PASS enqueue() inside size() should work
 PASS close() inside size() should not crash
 PASS close request inside size() should work
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.worker-expected.txt
index 508c1a7..d553698 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/readable-streams/reentrant-strategies.any.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
+Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo not yet implemented
 PASS enqueue() inside size() should work
 PASS close() inside size() should not crash
 PASS close request inside size() should work
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/err-invalid-hwm-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/err-invalid-hwm-expected.txt
index 8790fc9e..7597481 100644
--- a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/err-invalid-hwm-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/err-invalid-hwm-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-PASS ReadableStream RangeError on invalid highWaterMark should have an appropriate message
+FAIL ReadableStream RangeError on invalid highWaterMark should have an appropriate message assert_equals: message should be relevant expected "A queueing strategy's highWaterMark property must be a nonnegative, non-NaN number" but got "Failed to construct 'ReadableStream': A queuing strategy's highWaterMark property must be a nonnegative, non-NaN number"
 FAIL WritableStream RangeError on invalid highWaterMark should have an appropriate message assert_equals: message should be relevant expected "A queueing strategy's highWaterMark property must be a nonnegative, non-NaN number" but got "Failed to construct 'WritableStream': A queuing strategy's highWaterMark property must be a nonnegative, non-NaN number"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/readable-stream-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/readable-stream-expected.txt
index dd671bf..a398705f 100644
--- a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/readable-stream-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/readable-stream-expected.txt
@@ -3,7 +3,7 @@
 FAIL sending ten chunks through a transferred stream should work promise_test: Unhandled rejection with value: object "Error: what is this thing: "null"?"
 FAIL sending ten chunks one at a time should work promise_test: Unhandled rejection with value: object "Error: what is this thing: "null"?"
 FAIL sending ten chunks on demand should work promise_test: Unhandled rejection with value: object "Error: what is this thing: "null"?"
-PASS transferring a stream should relieve backpressure
+FAIL transferring a stream should relieve backpressure assert_array_equals: pull() should have been called lengths differ, expected 1 got 0
 FAIL transferring a stream should add one chunk to the queue size promise_test: Unhandled rejection with value: object "Error: what is this thing: "null"?"
 FAIL the extra queue from transferring is counted in chunks promise_test: Unhandled rejection with value: object "Error: what is this thing: "null"?"
 FAIL cancel should be propagated to the original promise_test: Unhandled rejection with value: object "Error: what is this thing: "null"?"
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/service-worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/service-worker-expected.txt
index 68a7e42c..d487631 100644
--- a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/service-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/service-worker-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 PASS service-worker
-FAIL serviceWorker.controller.postMessage should be able to transfer a ReadableStream promise_test: Unhandled rejection with value: "BAD: TypeError: Cannot read property 'constructor' of null"
-FAIL postMessage in a service worker should be able to transfer ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'constructor' of null"
+FAIL serviceWorker.controller.postMessage should be able to transfer a ReadableStream assert_true: the original stream should be locked expected true got false
+FAIL postMessage in a service worker should be able to transfer ReadableStream promise_test: Unhandled rejection with value: "BAD: TypeError: Cannot read property 'constructor' of null"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/shared-worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/shared-worker-expected.txt
index 20648c3..36e8d16 100644
--- a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/shared-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/shared-worker-expected.txt
@@ -1,5 +1,7 @@
+CONSOLE ERROR: line 79: Uncaught (in promise) BAD: TypeError: Cannot read property 'constructor' of null
 This is a testharness.js-based test.
-FAIL worker.postMessage should be able to transfer a ReadableStream promise_test: Unhandled rejection with value: "BAD: TypeError: Cannot read property 'constructor' of null"
+Harness Error. harness_status.status = 1 , harness_status.message = undefined
+FAIL worker.postMessage should be able to transfer a ReadableStream assert_true: the original stream should be locked expected true got false
 FAIL postMessage in a worker should be able to transfer a ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'constructor' of null"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/worker-expected.txt
index 2aecae0..d3ca9a3 100644
--- a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/worker-expected.txt
@@ -1,7 +1,7 @@
 CONSOLE ERROR: line 2: Uncaught TypeError: Failed to execute 'postMessage' on 'DedicatedWorkerGlobalScope': Value at index 0 is an untransferable 'null' value.
 CONSOLE ERROR: line 2: Uncaught TypeError: Failed to execute 'postMessage' on 'DedicatedWorkerGlobalScope': Value at index 0 is an untransferable 'null' value.
 This is a testharness.js-based test.
-FAIL worker.postMessage should be able to transfer a ReadableStream promise_test: Unhandled rejection with value: "BAD: TypeError: Cannot read property 'constructor' of null"
+FAIL worker.postMessage should be able to transfer a ReadableStream assert_true: the original stream should be locked expected true got false
 FAIL postMessage in a worker should be able to transfer a ReadableStream promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'constructor' of null"
 FAIL terminating a worker should not error the stream promise_test: Unhandled rejection with value: "error in worker"
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt b/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt
index 2a2fa283..d779f94 100644
--- a/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt
+++ b/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt
@@ -17,7 +17,6 @@
 idle-detection
 layout-animations
 lazyload
-legacy-image-formats
 magnetometer
 microphone
 midi
diff --git a/third_party/byte_buddy/BUILD.gn b/third_party/byte_buddy/BUILD.gn
index 6e9c9a1..c651ac2 100644
--- a/third_party/byte_buddy/BUILD.gn
+++ b/third_party/byte_buddy/BUILD.gn
@@ -22,7 +22,7 @@
   testonly = true
   enable_bytecode_checks = false
   deps = [
-    "//third_party/android_tools:dx_25_0_2_java",
+    "//third_party/android_sdk:dx_25_0_2_java",
   ]
   proguard_configs = [ "//third_party/byte_buddy/proguard.flags" ]
   jar_path = "lib/byte-buddy-android.jar"
diff --git a/third_party/cacheinvalidation/BUILD.gn b/third_party/cacheinvalidation/BUILD.gn
index b5affe28..3b055f3 100644
--- a/third_party/cacheinvalidation/BUILD.gn
+++ b/third_party/cacheinvalidation/BUILD.gn
@@ -141,7 +141,7 @@
       "$google_play_services_package:google_play_services_iid_java",
       "$google_play_services_package:google_play_services_tasks_java",
       "//third_party/android_protobuf:protobuf_nano_javalib",
-      "//third_party/android_tools:android_gcm_java",
+      "//third_party/android_sdk:android_gcm_java",
     ]
 
     java_files = [
diff --git a/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/sha1-digest-function.h b/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/sha1-digest-function.h
index d12c971d..9fc4b5d 100644
--- a/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/sha1-digest-function.h
+++ b/third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/sha1-digest-function.h
@@ -9,7 +9,7 @@
 
 #include <string>
 
-#include "base/sha1.h"
+#include "base/hash/sha1.h"
 #include "google/cacheinvalidation/deps/digest-function.h"
 #include "google/cacheinvalidation/deps/stl-namespace.h"
 
diff --git a/third_party/crashpad/crashpad/handler/BUILD.gn b/third_party/crashpad/crashpad/handler/BUILD.gn
index e1e673e26..054d1ef 100644
--- a/third_party/crashpad/crashpad/handler/BUILD.gn
+++ b/third_party/crashpad/crashpad/handler/BUILD.gn
@@ -14,10 +14,6 @@
 
 import("../build/crashpad_buildconfig.gni")
 
-if (crashpad_is_in_chromium) {
-  import("//build/config/sanitizers/sanitizers.gni")
-}
-
 static_library("handler") {
   sources = [
     "crash_report_upload_thread.cc",
@@ -181,8 +177,7 @@
 
     ldflags = [ "-llog" ]
 
-    # TODO(thakis): Remove !using_sanitizer, https://crbug.com/936418
-    if (crashpad_is_in_chromium && !using_sanitizer) {
+    if (crashpad_is_in_chromium) {
       no_default_deps = true
     }
     remove_configs =
diff --git a/third_party/gvr-android-keyboard/BUILD.gn b/third_party/gvr-android-keyboard/BUILD.gn
index 74f266d..bf0afad 100644
--- a/third_party/gvr-android-keyboard/BUILD.gn
+++ b/third_party/gvr-android-keyboard/BUILD.gn
@@ -5,9 +5,6 @@
 import("//build/config/android/rules.gni")
 
 android_library("kb_java") {
-  deps = [
-    "//base:base_java",
-  ]
   srcjar_deps = [ ":aidl" ]
 }
 
diff --git a/third_party/hunspell/google/bdict.h b/third_party/hunspell/google/bdict.h
index dc33369..716f2ef 100644
--- a/third_party/hunspell/google/bdict.h
+++ b/third_party/hunspell/google/bdict.h
@@ -8,7 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/md5.h"
+#include "base/hash/md5.h"
 
 // BDict (binary dictionary) format. All offsets are little endian.
 //
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium
index d8349fb4..fa5ffd2 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: 1e65f2e3a9759b799ca3a87a41dcc9f58fdd720f
+Revision: e7e48a48215b7f5c591920a2e06c68e5334cc60a
 License: BSD
 License File: LICENSE
 Security Critical: no
diff --git a/third_party/inspector_protocol/encoding/encoding.cc b/third_party/inspector_protocol/encoding/encoding.cc
index c2c6545a4..0026b0a 100644
--- a/third_party/inspector_protocol/encoding/encoding.cc
+++ b/third_party/inspector_protocol/encoding/encoding.cc
@@ -5,6 +5,7 @@
 #include "encoding.h"
 
 #include <cassert>
+#include <cmath>
 #include <cstring>
 #include <limits>
 #include <stack>
@@ -1107,6 +1108,12 @@
     if (!status_->ok())
       return;
     state_.top().StartElement(out_);
+    // JSON cannot represent NaN or Infinity. So, for compatibility,
+    // we behave like the JSON object in web browsers: emit 'null'.
+    if (!std::isfinite(value)) {
+      out_->append("null");
+      return;
+    }
     std::unique_ptr<char[]> str_value = platform_->DToStr(value);
 
     // DToStr may fail to emit a 0 before the decimal dot. E.g. this is
diff --git a/third_party/inspector_protocol/encoding/encoding_test.cc b/third_party/inspector_protocol/encoding/encoding_test.cc
index a03c7fc..c73afd72 100644
--- a/third_party/inspector_protocol/encoding/encoding_test.cc
+++ b/third_party/inspector_protocol/encoding/encoding_test.cc
@@ -1165,6 +1165,25 @@
       out);
 }
 
+TEST(JsonStdStringWriterTest, RepresentingNonFiniteValuesAsNull) {
+  // JSON can't represent +Infinity, -Infinity, or NaN.
+  // So in practice it's mapped to null.
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  writer->HandleMapBegin();
+  writer->HandleString8(SpanFromStdString("Infinity"));
+  writer->HandleDouble(std::numeric_limits<double>::infinity());
+  writer->HandleString8(SpanFromStdString("-Infinity"));
+  writer->HandleDouble(-std::numeric_limits<double>::infinity());
+  writer->HandleString8(SpanFromStdString("NaN"));
+  writer->HandleDouble(std::numeric_limits<double>::quiet_NaN());
+  writer->HandleMapEnd();
+  EXPECT_TRUE(status.ok());
+  EXPECT_EQ("{\"Infinity\":null,\"-Infinity\":null,\"NaN\":null}", out);
+}
+
 TEST(JsonStdStringWriterTest, BinaryEncodedAsJsonString) {
   // The encoder emits binary submitted to StreamingParserHandler::HandleBinary
   // as base64. The following three examples are taken from
diff --git a/third_party/junit/BUILD.gn b/third_party/junit/BUILD.gn
index c17c1de3..2b3dcd4 100644
--- a/third_party/junit/BUILD.gn
+++ b/third_party/junit/BUILD.gn
@@ -9,8 +9,8 @@
   testonly = true
   proguard_configs = [ "//third_party/junit/proguard.flags" ]
   deps = [
-    "//third_party/android_tools:android_test_base_java",
-    "//third_party/android_tools:android_test_runner_java",
+    "//third_party/android_sdk:android_test_base_java",
+    "//third_party/android_sdk:android_test_runner_java",
     "//third_party/hamcrest:hamcrest_java",
   ]
   java_files = [
diff --git a/third_party/libaom/BUILD.gn b/third_party/libaom/BUILD.gn
index 424aae8..727d3626 100644
--- a/third_party/libaom/BUILD.gn
+++ b/third_party/libaom/BUILD.gn
@@ -205,7 +205,7 @@
       deps += [ ":libaom_intrinsics_neon" ]
     }
     if (is_android) {
-      deps += [ "//third_party/android_tools:cpu_features" ]
+      deps += [ "//third_party/android_sdk:cpu_features" ]
     }
     public_configs = [ ":libaom_external_config" ]
   }
diff --git a/third_party/libaom/options.gni b/third_party/libaom/options.gni
index c3d02367..b9480b2 100644
--- a/third_party/libaom/options.gni
+++ b/third_party/libaom/options.gni
@@ -2,5 +2,5 @@
 
 declare_args() {
   # Enable decoding AV1 video files.
-  enable_libaom_decoder = !is_android && !is_ios
+  enable_libaom_decoder = false
 }
diff --git a/third_party/libvpx/BUILD.gn b/third_party/libvpx/BUILD.gn
index 4a6d99b..cabd7ee 100644
--- a/third_party/libvpx/BUILD.gn
+++ b/third_party/libvpx/BUILD.gn
@@ -362,7 +362,7 @@
     deps += [ ":libvpx_intrinsics_neon" ]
   }
   if (is_android) {
-    deps += [ "//third_party/android_tools:cpu_features" ]
+    deps += [ "//third_party/android_sdk:cpu_features" ]
   }
   if (current_cpu == "arm" && arm_assembly_sources != []) {
     deps += [ ":libvpx_assembly_arm" ]
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index 0d2bf0d..11769cdac 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: Monday March 25 2019
+Date: Thursday March 28 2019
 Branch: master
-Commit: 0d2299c1ee04b9fb7c30e3ad555bf12e95157dfa
+Commit: ecae7f8f81d866ac340834de3422f8c02d46a995
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni
index 376acb9..52b42ef1 100644
--- a/third_party/libvpx/libvpx_srcs.gni
+++ b/third_party/libvpx/libvpx_srcs.gni
@@ -447,7 +447,6 @@
 libvpx_srcs_x86_sse3 = []
 libvpx_srcs_x86_ssse3 = [
   "//third_party/libvpx/source/libvpx/vp8/encoder/x86/vp8_quantize_ssse3.c",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_dct_ssse3.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_frame_scale_ssse3.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_intrapred_intrin_ssse3.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_ssse3.c",
@@ -930,7 +929,6 @@
 libvpx_srcs_x86_64_sse3 = []
 libvpx_srcs_x86_64_ssse3 = [
   "//third_party/libvpx/source/libvpx/vp8/encoder/x86/vp8_quantize_ssse3.c",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_dct_ssse3.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_frame_scale_ssse3.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_intrapred_intrin_ssse3.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_ssse3.c",
@@ -1515,7 +1513,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_job_queue.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_job_queue.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_denoiser_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_error_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_frame_scale_neon.c",
@@ -2123,7 +2120,6 @@
   "//third_party/libvpx/source/libvpx/vp9/common/arm/neon/vp9_iht16x16_add_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/common/arm/neon/vp9_iht4x4_add_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/common/arm/neon/vp9_iht8x8_add_neon.c",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_denoiser_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_error_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_frame_scale_neon.c",
@@ -2364,7 +2360,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_job_queue.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_job_queue.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_denoiser_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_error_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_frame_scale_neon.c",
@@ -2776,7 +2771,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_job_queue.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_job_queue.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_denoiser_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_frame_scale_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_quantize_neon.c",
@@ -3216,7 +3210,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_job_queue.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_job_queue.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_denoiser_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_frame_scale_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_quantize_neon.c",
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vp9_rtcd.h b/third_party/libvpx/source/config/ios/arm-neon/vp9_rtcd.h
index cdfebccf..e17954d 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm-neon/vp9_rtcd.h
@@ -76,34 +76,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_neon(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_neon
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/ios/arm64/vp9_rtcd.h b/third_party/libvpx/source/config/ios/arm64/vp9_rtcd.h
index cdfebccf..e17954d 100644
--- a/third_party/libvpx/source/config/ios/arm64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm64/vp9_rtcd.h
@@ -76,34 +76,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_neon(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_neon
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp9_rtcd.h
index e7c5c4e..f5fa140 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp9_rtcd.h
@@ -86,46 +86,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_neon(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-RTCD_EXTERN void (*vp9_fdct8x8_quant)(const int16_t* input,
-                                      int stride,
-                                      tran_low_t* coeff_ptr,
-                                      intptr_t n_coeffs,
-                                      int skip_block,
-                                      const int16_t* round_ptr,
-                                      const int16_t* quant_ptr,
-                                      tran_low_t* qcoeff_ptr,
-                                      tran_low_t* dqcoeff_ptr,
-                                      const int16_t* dequant_ptr,
-                                      uint16_t* eob_ptr,
-                                      const int16_t* scan,
-                                      const int16_t* iscan);
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
@@ -299,9 +259,6 @@
   vp9_denoiser_filter = vp9_denoiser_filter_c;
   if (flags & HAS_NEON)
     vp9_denoiser_filter = vp9_denoiser_filter_neon;
-  vp9_fdct8x8_quant = vp9_fdct8x8_quant_c;
-  if (flags & HAS_NEON)
-    vp9_fdct8x8_quant = vp9_fdct8x8_quant_neon;
   vp9_iht16x16_256_add = vp9_iht16x16_256_add_c;
   if (flags & HAS_NEON)
     vp9_iht16x16_256_add = vp9_iht16x16_256_add_neon;
diff --git a/third_party/libvpx/source/config/linux/arm-neon-highbd/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-highbd/vp9_rtcd.h
index 684bd98..ca740f4 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-highbd/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-highbd/vp9_rtcd.h
@@ -73,34 +73,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_neon(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_neon
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon/vp9_rtcd.h
index cdfebccf..e17954d 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon/vp9_rtcd.h
@@ -76,34 +76,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_neon(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_neon
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/arm/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm/vp9_rtcd.h
index 6880668..5465fc0 100644
--- a/third_party/libvpx/source/config/linux/arm/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm/vp9_rtcd.h
@@ -64,21 +64,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_c
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/arm64-highbd/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm64-highbd/vp9_rtcd.h
index 684bd98..ca740f4 100644
--- a/third_party/libvpx/source/config/linux/arm64-highbd/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm64-highbd/vp9_rtcd.h
@@ -73,34 +73,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_neon(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_neon
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/arm64/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm64/vp9_rtcd.h
index cdfebccf..e17954d 100644
--- a/third_party/libvpx/source/config/linux/arm64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm64/vp9_rtcd.h
@@ -76,34 +76,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_neon(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_neon
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/generic/vp9_rtcd.h b/third_party/libvpx/source/config/linux/generic/vp9_rtcd.h
index 25555a7..00913931 100644
--- a/third_party/libvpx/source/config/linux/generic/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/generic/vp9_rtcd.h
@@ -64,21 +64,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_c
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
index d5c1c519..e079a2d 100644
--- a/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
@@ -110,59 +110,6 @@
     const struct vp9_variance_vtable* fn_ptr,
     const struct mv* center_mv);
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_sse2(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-void vp9_fdct8x8_quant_ssse3(const int16_t* input,
-                             int stride,
-                             tran_low_t* coeff_ptr,
-                             intptr_t n_coeffs,
-                             int skip_block,
-                             const int16_t* round_ptr,
-                             const int16_t* quant_ptr,
-                             tran_low_t* qcoeff_ptr,
-                             tran_low_t* dqcoeff_ptr,
-                             const int16_t* dequant_ptr,
-                             uint16_t* eob_ptr,
-                             const int16_t* scan,
-                             const int16_t* iscan);
-RTCD_EXTERN void (*vp9_fdct8x8_quant)(const int16_t* input,
-                                      int stride,
-                                      tran_low_t* coeff_ptr,
-                                      intptr_t n_coeffs,
-                                      int skip_block,
-                                      const int16_t* round_ptr,
-                                      const int16_t* quant_ptr,
-                                      tran_low_t* qcoeff_ptr,
-                                      tran_low_t* dqcoeff_ptr,
-                                      const int16_t* dequant_ptr,
-                                      uint16_t* eob_ptr,
-                                      const int16_t* scan,
-                                      const int16_t* iscan);
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
@@ -484,9 +431,6 @@
   vp9_diamond_search_sad = vp9_diamond_search_sad_c;
   if (flags & HAS_AVX)
     vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
-  vp9_fdct8x8_quant = vp9_fdct8x8_quant_sse2;
-  if (flags & HAS_SSSE3)
-    vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
   vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_c;
   if (flags & HAS_SSE4_1)
     vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_sse4_1;
diff --git a/third_party/libvpx/source/config/linux/mips64el/vp9_rtcd.h b/third_party/libvpx/source/config/linux/mips64el/vp9_rtcd.h
index d187b0a..9e956fb1 100644
--- a/third_party/libvpx/source/config/linux/mips64el/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/mips64el/vp9_rtcd.h
@@ -64,21 +64,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_c
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/mipsel/vp9_rtcd.h b/third_party/libvpx/source/config/linux/mipsel/vp9_rtcd.h
index d187b0a..9e956fb1 100644
--- a/third_party/libvpx/source/config/linux/mipsel/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/mipsel/vp9_rtcd.h
@@ -64,21 +64,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_c
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h b/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
index 7d8c367..12b9110d 100644
--- a/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
@@ -110,59 +110,6 @@
     const struct vp9_variance_vtable* fn_ptr,
     const struct mv* center_mv);
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_sse2(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-void vp9_fdct8x8_quant_ssse3(const int16_t* input,
-                             int stride,
-                             tran_low_t* coeff_ptr,
-                             intptr_t n_coeffs,
-                             int skip_block,
-                             const int16_t* round_ptr,
-                             const int16_t* quant_ptr,
-                             tran_low_t* qcoeff_ptr,
-                             tran_low_t* dqcoeff_ptr,
-                             const int16_t* dequant_ptr,
-                             uint16_t* eob_ptr,
-                             const int16_t* scan,
-                             const int16_t* iscan);
-RTCD_EXTERN void (*vp9_fdct8x8_quant)(const int16_t* input,
-                                      int stride,
-                                      tran_low_t* coeff_ptr,
-                                      intptr_t n_coeffs,
-                                      int skip_block,
-                                      const int16_t* round_ptr,
-                                      const int16_t* quant_ptr,
-                                      tran_low_t* qcoeff_ptr,
-                                      tran_low_t* dqcoeff_ptr,
-                                      const int16_t* dequant_ptr,
-                                      uint16_t* eob_ptr,
-                                      const int16_t* scan,
-                                      const int16_t* iscan);
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
@@ -516,9 +463,6 @@
   vp9_diamond_search_sad = vp9_diamond_search_sad_c;
   if (flags & HAS_AVX)
     vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
-  vp9_fdct8x8_quant = vp9_fdct8x8_quant_sse2;
-  if (flags & HAS_SSSE3)
-    vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
   vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_c;
   if (flags & HAS_SSE4_1)
     vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_sse4_1;
diff --git a/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
index d5c1c519..e079a2d 100644
--- a/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
@@ -110,59 +110,6 @@
     const struct vp9_variance_vtable* fn_ptr,
     const struct mv* center_mv);
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_sse2(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-void vp9_fdct8x8_quant_ssse3(const int16_t* input,
-                             int stride,
-                             tran_low_t* coeff_ptr,
-                             intptr_t n_coeffs,
-                             int skip_block,
-                             const int16_t* round_ptr,
-                             const int16_t* quant_ptr,
-                             tran_low_t* qcoeff_ptr,
-                             tran_low_t* dqcoeff_ptr,
-                             const int16_t* dequant_ptr,
-                             uint16_t* eob_ptr,
-                             const int16_t* scan,
-                             const int16_t* iscan);
-RTCD_EXTERN void (*vp9_fdct8x8_quant)(const int16_t* input,
-                                      int stride,
-                                      tran_low_t* coeff_ptr,
-                                      intptr_t n_coeffs,
-                                      int skip_block,
-                                      const int16_t* round_ptr,
-                                      const int16_t* quant_ptr,
-                                      tran_low_t* qcoeff_ptr,
-                                      tran_low_t* dqcoeff_ptr,
-                                      const int16_t* dequant_ptr,
-                                      uint16_t* eob_ptr,
-                                      const int16_t* scan,
-                                      const int16_t* iscan);
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
@@ -484,9 +431,6 @@
   vp9_diamond_search_sad = vp9_diamond_search_sad_c;
   if (flags & HAS_AVX)
     vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
-  vp9_fdct8x8_quant = vp9_fdct8x8_quant_sse2;
-  if (flags & HAS_SSSE3)
-    vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
   vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_c;
   if (flags & HAS_SSE4_1)
     vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_sse4_1;
diff --git a/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h b/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
index 7d8c367..12b9110d 100644
--- a/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
@@ -110,59 +110,6 @@
     const struct vp9_variance_vtable* fn_ptr,
     const struct mv* center_mv);
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_sse2(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-void vp9_fdct8x8_quant_ssse3(const int16_t* input,
-                             int stride,
-                             tran_low_t* coeff_ptr,
-                             intptr_t n_coeffs,
-                             int skip_block,
-                             const int16_t* round_ptr,
-                             const int16_t* quant_ptr,
-                             tran_low_t* qcoeff_ptr,
-                             tran_low_t* dqcoeff_ptr,
-                             const int16_t* dequant_ptr,
-                             uint16_t* eob_ptr,
-                             const int16_t* scan,
-                             const int16_t* iscan);
-RTCD_EXTERN void (*vp9_fdct8x8_quant)(const int16_t* input,
-                                      int stride,
-                                      tran_low_t* coeff_ptr,
-                                      intptr_t n_coeffs,
-                                      int skip_block,
-                                      const int16_t* round_ptr,
-                                      const int16_t* quant_ptr,
-                                      tran_low_t* qcoeff_ptr,
-                                      tran_low_t* dqcoeff_ptr,
-                                      const int16_t* dequant_ptr,
-                                      uint16_t* eob_ptr,
-                                      const int16_t* scan,
-                                      const int16_t* iscan);
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
@@ -516,9 +463,6 @@
   vp9_diamond_search_sad = vp9_diamond_search_sad_c;
   if (flags & HAS_AVX)
     vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
-  vp9_fdct8x8_quant = vp9_fdct8x8_quant_sse2;
-  if (flags & HAS_SSSE3)
-    vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
   vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_c;
   if (flags & HAS_SSE4_1)
     vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_sse4_1;
diff --git a/third_party/libvpx/source/config/nacl/vp9_rtcd.h b/third_party/libvpx/source/config/nacl/vp9_rtcd.h
index 25555a7..00913931 100644
--- a/third_party/libvpx/source/config/nacl/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/nacl/vp9_rtcd.h
@@ -64,21 +64,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_c
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 8d324e6..2746b6f1 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  "303-g0d2299c1ee"
+#define VERSION_EXTRA  "315-gecae7f8f81"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.8.0-303-g0d2299c1ee"
-#define VERSION_STRING      " v1.8.0-303-g0d2299c1ee"
+#define VERSION_STRING_NOSP "v1.8.0-315-gecae7f8f81"
+#define VERSION_STRING      " v1.8.0-315-gecae7f8f81"
diff --git a/third_party/libvpx/source/config/win/arm64/vp9_rtcd.h b/third_party/libvpx/source/config/win/arm64/vp9_rtcd.h
index 684bd98..ca740f4 100644
--- a/third_party/libvpx/source/config/win/arm64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/win/arm64/vp9_rtcd.h
@@ -73,34 +73,6 @@
                              const struct mv* center_mv);
 #define vp9_diamond_search_sad vp9_diamond_search_sad_c
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_neon(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-#define vp9_fdct8x8_quant vp9_fdct8x8_quant_neon
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
diff --git a/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
index d5c1c519..e079a2d 100644
--- a/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
@@ -110,59 +110,6 @@
     const struct vp9_variance_vtable* fn_ptr,
     const struct mv* center_mv);
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_sse2(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-void vp9_fdct8x8_quant_ssse3(const int16_t* input,
-                             int stride,
-                             tran_low_t* coeff_ptr,
-                             intptr_t n_coeffs,
-                             int skip_block,
-                             const int16_t* round_ptr,
-                             const int16_t* quant_ptr,
-                             tran_low_t* qcoeff_ptr,
-                             tran_low_t* dqcoeff_ptr,
-                             const int16_t* dequant_ptr,
-                             uint16_t* eob_ptr,
-                             const int16_t* scan,
-                             const int16_t* iscan);
-RTCD_EXTERN void (*vp9_fdct8x8_quant)(const int16_t* input,
-                                      int stride,
-                                      tran_low_t* coeff_ptr,
-                                      intptr_t n_coeffs,
-                                      int skip_block,
-                                      const int16_t* round_ptr,
-                                      const int16_t* quant_ptr,
-                                      tran_low_t* qcoeff_ptr,
-                                      tran_low_t* dqcoeff_ptr,
-                                      const int16_t* dequant_ptr,
-                                      uint16_t* eob_ptr,
-                                      const int16_t* scan,
-                                      const int16_t* iscan);
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
@@ -484,9 +431,6 @@
   vp9_diamond_search_sad = vp9_diamond_search_sad_c;
   if (flags & HAS_AVX)
     vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
-  vp9_fdct8x8_quant = vp9_fdct8x8_quant_sse2;
-  if (flags & HAS_SSSE3)
-    vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
   vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_c;
   if (flags & HAS_SSE4_1)
     vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_sse4_1;
diff --git a/third_party/libvpx/source/config/win/x64/vp9_rtcd.h b/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
index 7d8c367..12b9110d 100644
--- a/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
@@ -110,59 +110,6 @@
     const struct vp9_variance_vtable* fn_ptr,
     const struct mv* center_mv);
 
-void vp9_fdct8x8_quant_c(const int16_t* input,
-                         int stride,
-                         tran_low_t* coeff_ptr,
-                         intptr_t n_coeffs,
-                         int skip_block,
-                         const int16_t* round_ptr,
-                         const int16_t* quant_ptr,
-                         tran_low_t* qcoeff_ptr,
-                         tran_low_t* dqcoeff_ptr,
-                         const int16_t* dequant_ptr,
-                         uint16_t* eob_ptr,
-                         const int16_t* scan,
-                         const int16_t* iscan);
-void vp9_fdct8x8_quant_sse2(const int16_t* input,
-                            int stride,
-                            tran_low_t* coeff_ptr,
-                            intptr_t n_coeffs,
-                            int skip_block,
-                            const int16_t* round_ptr,
-                            const int16_t* quant_ptr,
-                            tran_low_t* qcoeff_ptr,
-                            tran_low_t* dqcoeff_ptr,
-                            const int16_t* dequant_ptr,
-                            uint16_t* eob_ptr,
-                            const int16_t* scan,
-                            const int16_t* iscan);
-void vp9_fdct8x8_quant_ssse3(const int16_t* input,
-                             int stride,
-                             tran_low_t* coeff_ptr,
-                             intptr_t n_coeffs,
-                             int skip_block,
-                             const int16_t* round_ptr,
-                             const int16_t* quant_ptr,
-                             tran_low_t* qcoeff_ptr,
-                             tran_low_t* dqcoeff_ptr,
-                             const int16_t* dequant_ptr,
-                             uint16_t* eob_ptr,
-                             const int16_t* scan,
-                             const int16_t* iscan);
-RTCD_EXTERN void (*vp9_fdct8x8_quant)(const int16_t* input,
-                                      int stride,
-                                      tran_low_t* coeff_ptr,
-                                      intptr_t n_coeffs,
-                                      int skip_block,
-                                      const int16_t* round_ptr,
-                                      const int16_t* quant_ptr,
-                                      tran_low_t* qcoeff_ptr,
-                                      tran_low_t* dqcoeff_ptr,
-                                      const int16_t* dequant_ptr,
-                                      uint16_t* eob_ptr,
-                                      const int16_t* scan,
-                                      const int16_t* iscan);
-
 void vp9_fht16x16_c(const int16_t* input,
                     tran_low_t* output,
                     int stride,
@@ -516,9 +463,6 @@
   vp9_diamond_search_sad = vp9_diamond_search_sad_c;
   if (flags & HAS_AVX)
     vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
-  vp9_fdct8x8_quant = vp9_fdct8x8_quant_sse2;
-  if (flags & HAS_SSSE3)
-    vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
   vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_c;
   if (flags & HAS_SSE4_1)
     vp9_highbd_iht16x16_256_add = vp9_highbd_iht16x16_256_add_sse4_1;
diff --git a/third_party/libwebp/BUILD.gn b/third_party/libwebp/BUILD.gn
index 65c1c736..a162ae0b 100644
--- a/third_party/libwebp/BUILD.gn
+++ b/third_party/libwebp/BUILD.gn
@@ -180,7 +180,7 @@
     ":libwebp_webp",
   ]
   if (is_android) {
-    deps += [ "//third_party/android_tools:cpu_features" ]
+    deps += [ "//third_party/android_sdk:cpu_features" ]
   }
   if (current_cpu == "x86" || current_cpu == "x64") {
     defines = [
diff --git a/third_party/mockito/BUILD.gn b/third_party/mockito/BUILD.gn
index 7cc06a13..3305b38 100644
--- a/third_party/mockito/BUILD.gn
+++ b/third_party/mockito/BUILD.gn
@@ -11,7 +11,7 @@
   testonly = true
   proguard_configs = [ "//third_party/mockito/proguard.flags" ]
   deps = [
-    "//third_party/android_tools:android_test_base_java",
+    "//third_party/android_sdk:android_test_base_java",
     "//third_party/byte_buddy:byte_buddy_agent_java",
     "//third_party/byte_buddy:byte_buddy_android_java",
     "//third_party/byte_buddy:byte_buddy_java",
diff --git a/third_party/openh264/BUILD.gn b/third_party/openh264/BUILD.gn
index 7624dda..02a056a 100644
--- a/third_party/openh264/BUILD.gn
+++ b/third_party/openh264/BUILD.gn
@@ -144,7 +144,7 @@
       # files replaces these using macros for "wels_..." versions of the same
       # functions. We do not have access to these and use the <cpu-features.h>
       # ones instead.
-      "//third_party/android_tools:cpu_features",
+      "//third_party/android_sdk:cpu_features",
     ]
   }
 }
diff --git a/third_party/ub-uiautomator/BUILD.gn b/third_party/ub-uiautomator/BUILD.gn
index 74f89a5..abee947 100644
--- a/third_party/ub-uiautomator/BUILD.gn
+++ b/third_party/ub-uiautomator/BUILD.gn
@@ -8,8 +8,8 @@
   testonly = true
   jar_path = "lib/ub-uiautomator.jar"
   deps = [
-    "//third_party/android_tools:android_test_base_java",
-    "//third_party/android_tools:android_test_runner_java",
+    "//third_party/android_sdk:android_test_base_java",
+    "//third_party/android_sdk:android_test_runner_java",
     "//third_party/junit:junit",
   ]
 }
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index 9f7897a..0aec27f 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -87,7 +87,7 @@
         import("//build/config/android/config.gni")
         if (defined(android_ndk_root) && android_ndk_root != "") {
           deps = [
-            "//third_party/android_tools:cpu_features",
+            "//third_party/android_sdk:cpu_features",
           ]
         }
       }
diff --git a/third_party/zlib/google/zip_reader_unittest.cc b/third_party/zlib/google/zip_reader_unittest.cc
index 51a4938..a8b1ef2 100644
--- a/third_party/zlib/google/zip_reader_unittest.cc
+++ b/third_party/zlib/google/zip_reader_unittest.cc
@@ -15,8 +15,8 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
diff --git a/tools/android/md5sum/md5sum.cc b/tools/android/md5sum/md5sum.cc
index eaee434..1d51dad 100644
--- a/tools/android/md5sum/md5sum.cc
+++ b/tools/android/md5sum/md5sum.cc
@@ -16,8 +16,8 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/hash/md5.h"
 #include "base/logging.h"
-#include "base/md5.h"
 
 namespace {
 
diff --git a/tools/chrome_proxy/webdriver/client_config.py b/tools/chrome_proxy/webdriver/client_config.py
index cff3eb8..f87ed26 100644
--- a/tools/chrome_proxy/webdriver/client_config.py
+++ b/tools/chrome_proxy/webdriver/client_config.py
@@ -22,11 +22,6 @@
       responses = t.GetHTTPResponses()
       self.assertEqual(2, len(responses))
       for response in responses:
-        chrome_proxy_header = response.request_headers['chrome-proxy']
-        header_values = [v.strip(' ') for v in chrome_proxy_header.split(',')]
-        self.assertTrue(any(v[:2] == 's=' for v in header_values))
-        self.assertFalse(any(v[:3] == 'ps=' for v in header_values))
-        self.assertFalse(any(v[:4] == 'sid=' for v in header_values))
         # Verify that the proxy server honored the session ID.
         self.assertHasChromeProxyViaHeader(response)
         self.assertEqual(200, response.status)
diff --git a/tools/chrome_proxy/webdriver/video.py b/tools/chrome_proxy/webdriver/video.py
index 874855d..519ed76 100644
--- a/tools/chrome_proxy/webdriver/video.py
+++ b/tools/chrome_proxy/webdriver/video.py
@@ -204,8 +204,9 @@
             video_etag = rh['etag']
           else:
             self.assertEqual(video_etag, rh['etag'])
-          if ('range' in response.request_headers and
-              response.request_headers['range'] != 'bytes=0-'):
+          if ('status' in rh and rh['status']=='206' and 'content-range' in rh
+              and rh['content-range'].startswith('bytes ') and
+              not rh['content-range'].startswith('bytes 0-')):
             num_partial_requests += 1
       # Also make sure that we had at least one partial Range request.
       self.assertGreaterEqual(num_partial_requests, 1)
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 539f1b6..10b061f 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -43,7 +43,7 @@
   CLANG_REVISION = 'HEAD'
 
 # This is incremented when pushing a new build of Clang at the same revision.
-CLANG_SUB_REVISION=2
+CLANG_SUB_REVISION=3
 
 PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
 
@@ -836,10 +836,8 @@
         os.mkdir(os.path.join(build_dir))
       os.chdir(build_dir)
       target_triple = target_arch
-      abi_libs = 'c++abi'
       if target_arch == 'arm':
         target_triple = 'armv7'
-        abi_libs += ';unwind'
       target_triple += '-linux-android' + api_level
       cflags = ['--target=%s' % target_triple,
                 '--sysroot=%s/sysroot' % toolchain_dir,
@@ -852,8 +850,7 @@
         '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
         '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags),
         '-DCMAKE_ASM_FLAGS=' + ' '.join(cflags),
-        '-DSANITIZER_CXX_ABI=none',
-        '-DSANITIZER_CXX_ABI_LIBRARY=' + abi_libs,
+        '-DSANITIZER_CXX_ABI=libcxxabi',
         '-DCMAKE_SHARED_LINKER_FLAGS=-Wl,-u__cxa_demangle',
         '-DANDROID=1']
       RmCmakeCache('.')
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 10ee7f1..6c505ef 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -129,9 +129,9 @@
     Tracks what mode the user has selected for accessibility image labels,
     either always enabled, enabled once, or disabled.
   </summary>
-  <int value="0" label="Enabled (always)"/>
-  <int value="1" label="Enabled (once)"/>
-  <int value="2" label="Disabled"/>
+  <int value="1" label="Enabled (always)"/>
+  <int value="2" label="Enabled (once)"/>
+  <int value="3" label="Disabled"/>
 </enum>
 
 <enum name="AccessibilityModeFlagEnum">
@@ -5621,6 +5621,11 @@
   <int value="1" label="inappropriate_fallback alert"/>
 </enum>
 
+<enum name="BooleanIncluded">
+  <int value="0" label="Not included"/>
+  <int value="1" label="Included"/>
+</enum>
+
 <enum name="BooleanIncludesHash">
   <int value="0" label="Hash Missing"/>
   <int value="1" label="Hash Included"/>
@@ -21723,7 +21728,7 @@
   <int value="1977" label="CrossOriginPropertyAccess"/>
   <int value="1978" label="CrossOriginPropertyAccessFromOpener"/>
   <int value="1979" label="CredentialManagerCreate"/>
-  <int value="1980" label="WebDatabaseCreateDropFTS3Table"/>
+  <int value="1980" label="OBSOLETE_WebDatabaseCreateDropFTS3Table"/>
   <int value="1981" label="FieldEditInSecureContext"/>
   <int value="1982" label="FieldEditInNonSecureContext"/>
   <int value="1983"
@@ -22640,6 +22645,9 @@
 <enum name="FeaturePolicyFeature">
 <!-- Generated from third_party/blink/public/mojom/feature_policy/feature_policy.mojom.-->
 
+<!-- Obsolete / deprecated features in this enum should be prefixed with
+"Deprecated: " -->
+
   <int value="0" label="NotFound"/>
   <int value="1" label="Autoplay"/>
   <int value="2" label="Camera"/>
@@ -22662,7 +22670,7 @@
   <int value="19" label="Gyroscope"/>
   <int value="20" label="Magnetometer"/>
   <int value="21" label="UnsizedMedia"/>
-  <int value="22" label="LegacyImageFormats"/>
+  <int value="22" label="Deprecated: LegacyImageFormats"/>
   <int value="23" label="Deprecated: UnoptimizedImages"/>
   <int value="24" label="Animations"/>
   <int value="25" label="OversizedImages"/>
@@ -55454,6 +55462,18 @@
   <int value="13" label="kContentId"/>
 </enum>
 
+<enum name="UsageStatsEvents">
+  <int value="0" label="Opt In"/>
+  <int value="1" label="Opt Out"/>
+  <int value="2" label="Start Tracking Token"/>
+  <int value="3" label="Stop Tracking Token"/>
+  <int value="4" label="Suspend Sites"/>
+  <int value="5" label="Unsuspend Sites"/>
+  <int value="6" label="Query Events"/>
+  <int value="7" label="Clear All History"/>
+  <int value="8" label="Clear Range of History"/>
+</enum>
+
 <enum name="UsedInDraw">
   <obsolete>
     Deprecated 02/2017 in Issue 675840.
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b1a20fe..aac1af1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -10494,6 +10494,18 @@
   </summary>
 </histogram>
 
+<histogram
+    name="BackgroundSync.Registration.OneShot.EventSucceededAtCompletion"
+    enum="BooleanSuccess" expires_after="2020-12-31">
+  <owner>nator@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records whether the dispatched sync event succeeded at the completion of the
+    one-shot Background Sync registration.
+  </summary>
+</histogram>
+
 <histogram name="BackgroundSync.Registration.OneShot.IsDuplicate"
     enum="BooleanRegistrationIsDuplicate">
   <owner>iclelland@chromium.org</owner>
@@ -10503,6 +10515,18 @@
   </summary>
 </histogram>
 
+<histogram
+    name="BackgroundSync.Registration.OneShot.NumAttemptsForSuccessfulEvent"
+    units="attempts" expires_after="2020-12-31">
+  <owner>nator@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records the number of times a sync event was dispatched for a one-shot
+    Background Sync registration before it succeeded.
+  </summary>
+</histogram>
+
 <histogram name="BackgroundSync.Registration.Periodic"
     enum="BackgroundSyncStatus">
   <obsolete>
@@ -43498,6 +43522,21 @@
   </summary>
 </histogram>
 
+<histogram
+    name="ImageAnnotationService.AccessibilityV1.ImageRequestIncludesDesc"
+    enum="BooleanIncluded" expires_after="2019-06-04">
+  <owner>amoylan@chromium.org</owner>
+  <owner>martis@chromium.org</owner>
+  <summary>
+    For each image request sent to the image annotation server, records whether
+    or not the description backend is included among the requested backends.
+
+    The description backend will not be included when the image is known to
+    violate the description model policy (i.e. be too small or have too-high an
+    aspect ratio).
+  </summary>
+</histogram>
+
 <histogram name="ImageAnnotationService.AccessibilityV1.JsonParseSuccess"
     enum="BooleanSuccess" expires_after="2019-06-04">
   <owner>amoylan@chromium.org</owner>
@@ -119159,6 +119198,18 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.DownloadedPasswordsCountWhenInitialMergeFails"
+    units="entries" expires_after="2020-04-01">
+  <owner>mamir@chromium.org</owner>
+  <owner>mastiz@chromium.org</owner>
+  <summary>
+    Counts the number of password updates downloaded in case of error during the
+    MergeSyncData(). This is introduced to detect if there is corrleation
+    between number of password updates and failure during merge. Recorded only
+    for USS implementation.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Sync.DuplicateClientTagHashInApplyPendingUpdates"
     enum="BooleanPresent" expires_after="2019-09-30">
   <owner>treib@chromium.org</owner>
@@ -126179,6 +126230,15 @@
   </summary>
 </histogram>
 
+<histogram name="UMA.PrimaryUserType" enum="UserType"
+    expires_after="2020-04-01">
+  <owner>michaelpg@chromium.org</owner>
+  <owner>yilkal@chromium.org</owner>
+  <summary>
+    This UMA logs the primary user type per metrics recording interval.
+  </summary>
+</histogram>
+
 <histogram name="UMA.ProfilesCount.AfterErase">
   <obsolete>
     Deprecated as of Jun 2016. The histogram was added for debugging purpose and
@@ -127323,6 +127383,16 @@
   </summary>
 </histogram>
 
+<histogram name="UsageStats.Events" enum="UsageStatsEvents"
+    expires_after="2020-03-19">
+  <owner>pnoland@chromium.org</owner>
+  <owner>fgorski@chromium.org</owner>
+  <summary>
+    Android: count of Usage Stats events. Recorded as these events occur; e.g.
+    when a domain is associated with a token, or a site is suspended.
+  </summary>
+</histogram>
+
 <histogram name="UserActivation.AvailabilityCheck.FrameResult"
     enum="UserActivationFrameResultEnum">
   <owner>mustaq@chromium.org</owner>
@@ -142555,7 +142625,11 @@
 <histogram_suffixes name="MediaLearningDroppedFrameRatioTask" separator=".">
   <suffix name="BaseTable" label="Basic features, lookup table model"/>
   <suffix name="BaseTree" label="Basic feaetures, ExtraTrees model"/>
+  <suffix name="BinarySmoothnessTree"
+      label="Basic+extra features, pre-thresholded ExtraTrees model"/>
   <suffix name="EnhancedTree" label="Basic+extra features, ExtraTrees model"/>
+  <suffix name="EnhancedUnweightedTree"
+      label="Basic+extra features, unweighted ExtraTrees model"/>
   <affected-histogram
       name="Media.Learning.MediaCapabilities.DroppedFrameRatioTask"/>
 </histogram_suffixes>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 6afd36b..a400afc7 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -45,8 +45,6 @@
 sizes (linux),thestig@chromium.org,thomasanderson@chromium.org,Internals>PlatformIntegration,
 sizes (mac),tapted@chromium.org,,,
 sizes (win),grt@chromium.org,Internals>PlatformIntegration,,
-smoothness.gpu_rasterization.tough_pinch_zoom_cases,ericrk@chromium.org,,,"gpu_rasterization,representative_mac_desktop,tough_pinch_zoom"
-smoothness.tough_pinch_zoom_cases,bokan@chromium.org,Blink>Scroll,,"gpu_rasterization,representative_mac_desktop,tough_pinch_zoom"
 speedometer,hablich@chromium.org,Blink,,
 speedometer-future,hablich@chromium.org,Blink,,
 speedometer2,hablich@chromium.org,Blink,,
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
deleted file mode 100644
index c4a6c3e..0000000
--- a/tools/perf/benchmarks/smoothness.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-from core import perf_benchmark
-
-from benchmarks import silk_flags
-import page_sets
-from telemetry import benchmark
-from telemetry import story as story_module
-from telemetry.timeline import chrome_trace_category_filter
-from telemetry.web_perf import timeline_based_measurement
-
-
-class _Smoothness(perf_benchmark.PerfBenchmark):
-  """Base class for smoothness-based benchmarks."""
-
-  @classmethod
-  def Name(cls):
-    return 'smoothness'
-
-  def CreateCoreTimelineBasedMeasurementOptions(self):
-    category_filter = chrome_trace_category_filter.CreateLowOverheadFilter()
-    options = timeline_based_measurement.Options(category_filter)
-    options.config.chrome_trace_config.EnableUMAHistograms(
-        'Event.Latency.ScrollBegin.Touch.TimeToScrollUpdateSwapBegin4',
-        'Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin4')
-    options.SetTimelineBasedMetrics(['renderingMetric', 'umaMetric'])
-    return options
-
-
-@benchmark.Info(emails=['bokan@chromium.org'], component='Blink>Scroll')
-class SmoothnessToughPinchZoomCases(_Smoothness):
-  """Measures rendering statistics for pinch-zooming in the tough pinch zoom
-  cases.
-  """
-  page_set = page_sets.AndroidToughPinchZoomCasesPageSet
-  SUPPORTED_PLATFORMS = [story_module.expectations.ALL_MOBILE]
-
-  @classmethod
-  def Name(cls):
-    return 'smoothness.tough_pinch_zoom_cases'
-
-
-@benchmark.Info(emails=['ericrk@chromium.org'])
-class SmoothnessGpuRasterizationToughPinchZoomCases(_Smoothness):
-  """Measures rendering statistics for pinch-zooming in the tough pinch zoom
-  cases with GPU rasterization.
-  """
-  tag = 'gpu_rasterization'
-  page_set = page_sets.AndroidToughPinchZoomCasesPageSet
-  SUPPORTED_PLATFORMS = [story_module.expectations.ALL_MOBILE]
-
-  def SetExtraBrowserOptions(self, options):
-    silk_flags.CustomizeBrowserOptionsForGpuRasterization(options)
-
-  @classmethod
-  def Name(cls):
-    return 'smoothness.gpu_rasterization.tough_pinch_zoom_cases'
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py
index b8eac16..5b923f8 100755
--- a/tools/perf/core/results_dashboard.py
+++ b/tools/perf/core/results_dashboard.py
@@ -7,6 +7,8 @@
 
 # This file was copy-pasted over from:
 # //build/scripts/slave/results_dashboard.py
+# That file is now deprecated and this one is
+# the new source of truth.
 
 import calendar
 import datetime
@@ -47,9 +49,6 @@
   args = ['luci-auth', 'token']
   if service_account_file:
     args += ['-service-account-json', service_account_file]
-  else:
-    print ('service_account_file is not set. '
-           'Use LUCI swarming task service account')
   p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
   if p.wait() == 0:
     return p.stdout.read()
diff --git a/tools/perf/core/shard_maps/android-nexus5x-perf_map.json b/tools/perf/core/shard_maps/android-nexus5x-perf_map.json
index dae6397..006fe38 100644
--- a/tools/perf/core/shard_maps/android-nexus5x-perf_map.json
+++ b/tools/perf/core/shard_maps/android-nexus5x-perf_map.json
@@ -102,18 +102,11 @@
         "benchmarks": {
             "rendering.mobile": {
                 "begin": 360
-            },
-            "smoothness.gpu_rasterization.tough_pinch_zoom_cases": {},
-            "smoothness.tough_pinch_zoom_cases": {
-                "end": 17
             }
         }
     },
     "10": {
         "benchmarks": {
-            "smoothness.tough_pinch_zoom_cases": {
-                "begin": 17
-            },
             "speedometer": {},
             "speedometer-future": {},
             "speedometer2": {},
diff --git a/tools/perf/core/shard_maps/android-pixel2-perf_map.json b/tools/perf/core/shard_maps/android-pixel2-perf_map.json
index 0f0c66f4..543de43 100644
--- a/tools/perf/core/shard_maps/android-pixel2-perf_map.json
+++ b/tools/perf/core/shard_maps/android-pixel2-perf_map.json
@@ -62,8 +62,6 @@
             "rendering.mobile": {
                 "begin": 395
             },
-            "smoothness.gpu_rasterization.tough_pinch_zoom_cases": {},
-            "smoothness.tough_pinch_zoom_cases": {},
             "speedometer": {},
             "speedometer-future": {},
             "speedometer2": {},
diff --git a/tools/perf/core/shard_maps/android-pixel2_webview-perf_map.json b/tools/perf/core/shard_maps/android-pixel2_webview-perf_map.json
index 38ea5c0..06f949fb 100644
--- a/tools/perf/core/shard_maps/android-pixel2_webview-perf_map.json
+++ b/tools/perf/core/shard_maps/android-pixel2_webview-perf_map.json
@@ -53,18 +53,11 @@
         "benchmarks": {
             "rendering.mobile": {
                 "begin": 165
-            },
-            "smoothness.gpu_rasterization.tough_pinch_zoom_cases": {},
-            "smoothness.tough_pinch_zoom_cases": {
-                "end": 4
             }
         }
     },
     "4": {
         "benchmarks": {
-            "smoothness.tough_pinch_zoom_cases": {
-                "begin": 4
-            },
             "speedometer": {},
             "speedometer-future": {},
             "speedometer2": {},
diff --git a/tools/perf/core/shard_maps/android_nexus5_perf_map.json b/tools/perf/core/shard_maps/android_nexus5_perf_map.json
index 13d006f9..7e8b5879 100644
--- a/tools/perf/core/shard_maps/android_nexus5_perf_map.json
+++ b/tools/perf/core/shard_maps/android_nexus5_perf_map.json
@@ -94,9 +94,7 @@
         "benchmarks": {
             "rendering.mobile": {
                 "begin": 362
-            },
-            "smoothness.gpu_rasterization.tough_pinch_zoom_cases": {},
-            "smoothness.tough_pinch_zoom_cases": {}
+            }
         }
     },
     "10": {
diff --git a/tools/perf/core/shard_maps/android_nexus5x_webview_perf_map.json b/tools/perf/core/shard_maps/android_nexus5x_webview_perf_map.json
index f9fa993..7ca02bf 100644
--- a/tools/perf/core/shard_maps/android_nexus5x_webview_perf_map.json
+++ b/tools/perf/core/shard_maps/android_nexus5x_webview_perf_map.json
@@ -99,8 +99,6 @@
             "rendering.mobile": {
                 "begin": 403
             },
-            "smoothness.gpu_rasterization.tough_pinch_zoom_cases": {},
-            "smoothness.tough_pinch_zoom_cases": {},
             "speedometer": {},
             "speedometer-future": {},
             "speedometer2": {},
diff --git a/tools/perf/core/shard_maps/android_nexus6_webview_perf_map.json b/tools/perf/core/shard_maps/android_nexus6_webview_perf_map.json
index 0806679f..ae1209d 100644
--- a/tools/perf/core/shard_maps/android_nexus6_webview_perf_map.json
+++ b/tools/perf/core/shard_maps/android_nexus6_webview_perf_map.json
@@ -57,8 +57,6 @@
             "rendering.mobile": {
                 "begin": 254
             },
-            "smoothness.gpu_rasterization.tough_pinch_zoom_cases": {},
-            "smoothness.tough_pinch_zoom_cases": {},
             "speedometer": {},
             "speedometer-future": {},
             "speedometer2": {},
diff --git a/tools/perf/core/undocumented_benchmarks.py b/tools/perf/core/undocumented_benchmarks.py
index 9767e34..58fac31 100644
--- a/tools/perf/core/undocumented_benchmarks.py
+++ b/tools/perf/core/undocumented_benchmarks.py
@@ -29,8 +29,6 @@
   'resource_sizes',
   'sizes (mac)',
   'sizes (win)',
-  'smoothness.gpu_rasterization.tough_pinch_zoom_cases',
-  'smoothness.tough_pinch_zoom_cases',
   'speedometer',
   'speedometer-future',
   'speedometer2',
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 6cab3e5..bbae3a4 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -323,6 +323,7 @@
 crbug.com/896851 [ Android ] system_health.memory_mobile/background:tools:gmail [ Skip ]
 crbug.com/892704 [ Android_Webview ] system_health.memory_mobile/browse:tech:discourse_infinite_scroll:2018 [ Skip ]
 crbug.com/923527 [ Android_Webview ] system_health.memory_mobile/load:media:soundcloud:2018 [ Skip ]
+crbug.com/947267 [ Nexus_5X ] system_health.memory_mobile/background:media:imgur [ Skip ]
 
 # Benchmark: tab_switching.typical_25
 crbug.com/747026 [ Mac ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
diff --git a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
index 54b52a3..5de2bed 100644
--- a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
+++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
@@ -1,7 +1,6 @@
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-from telemetry import story
 from telemetry.util import wpr_modes
 
 from page_sets.rendering import rendering_shared_state
@@ -257,44 +256,3 @@
   BASE_NAME = 'yahoo_sports_pinch'
   YEAR = '2018'
   URL = 'http://sports.yahoo.com/'
-
-
-# TODO(crbug.com/760553):remove this class after
-# smoothness.tough_pinch_zoom_cases benchmark is completely
-# replaced by rendering benchmarks
-class AndroidToughPinchZoomCasesPageSet(story.StorySet):
-
-  """ Set of pages that are tricky to pinch-zoom """
-
-  def __init__(self):
-    super(AndroidToughPinchZoomCasesPageSet, self).__init__(
-      archive_data_file='../data/tough_pinch_zoom_cases.json',
-      cloud_storage_bucket=story.PARTNER_BUCKET)
-
-    self.target_scale_factor = 7.0
-
-    self.AddStory(GmailPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(GoogleCalendarPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(GoogleImagePinchZoom2018Page(
-        page_set=self))
-    self.AddStory(YoutubePinchZoom2018Page(
-        page_set=self))
-    self.AddStory(BlogSpotPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(FacebookPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(TwitterPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(ESPNPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(YahooNewsPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(AmazonPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(YahooSportsPinchZoom2018Page(
-        page_set=self))
-    self.AddStory(BookingPinchZoom2018Page(
-        page_set=self))
-
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py
index 34957c0..d990bad5 100755
--- a/tools/perf/process_perf_results.py
+++ b/tools/perf/process_perf_results.py
@@ -531,7 +531,7 @@
                   indent=4, separators=(',', ': ')),
       content_type=JSON_CONTENT_TYPE)
   if upload_failures_counter > 0:
-    logdog_label += ('Upload Failure (%s benchmark upload failures)' %
+    logdog_label += (' %s merge script perf data upload failures' %
                       upload_failures_counter)
   extra_links[logdog_label] = logdog_stream
   end_time = time.time()
@@ -591,6 +591,7 @@
 
 def main():
   """ See collect_task.collect_task for more on the merge script API. """
+  print sys.argv
   parser = argparse.ArgumentParser()
   # configuration-name (previously perf-id) is the name of bot the tests run on
   # For example, buildbot-test is the name of the android-go-perf bot
diff --git a/tools/ubsan/blacklist.txt b/tools/ubsan/blacklist.txt
index 13dce2bd..844d1eb 100644
--- a/tools/ubsan/blacklist.txt
+++ b/tools/ubsan/blacklist.txt
@@ -24,7 +24,6 @@
 
 #############################################################################
 # Undefined arithmetic that can be safely ignored.
-src:*/base/numerics/saturated_arithmetic.h
 src:*/ppapi/shared_impl/id_assignment.h
 
 #############################################################################
diff --git a/tools/ubsan/security_blacklist.txt b/tools/ubsan/security_blacklist.txt
index 97cfc813..79b44a4 100644
--- a/tools/ubsan/security_blacklist.txt
+++ b/tools/ubsan/security_blacklist.txt
@@ -39,7 +39,6 @@
 
 #############################################################################
 # Undefined arithmetic that can be safely ignored.
-src:*/base/numerics/saturated_arithmetic.h
 src:*/ppapi/shared_impl/id_assignment.h
 
 #############################################################################
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc
index f795bb5..fa55444 100644
--- a/ui/accessibility/ax_event_generator.cc
+++ b/ui/accessibility/ax_event_generator.cc
@@ -168,6 +168,9 @@
     case ax::mojom::State::kMultiselectable:
       AddEvent(node, Event::MULTISELECTABLE_STATE_CHANGED);
       break;
+    case ax::mojom::State::kRequired:
+      AddEvent(node, Event::REQUIRED_STATE_CHANGED);
+      break;
     default:
       break;
   }
diff --git a/ui/accessibility/ax_event_generator.h b/ui/accessibility/ax_event_generator.h
index ec56cecb..1d56618 100644
--- a/ui/accessibility/ax_event_generator.h
+++ b/ui/accessibility/ax_event_generator.h
@@ -57,6 +57,7 @@
     POSITION_IN_SET_CHANGED,
     RELATED_NODE_CHANGED,
     READONLY_CHANGED,
+    REQUIRED_STATE_CHANGED,
     ROLE_CHANGED,
     ROW_COUNT_CHANGED,
     SCROLL_POSITION_CHANGED,
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc
index d78564ef..01c10b7 100644
--- a/ui/accessibility/ax_event_generator_unittest.cc
+++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -116,11 +116,14 @@
       case AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
         event_name = "POSITION_IN_SET_CHANGED";
         break;
+      case AXEventGenerator::Event::READONLY_CHANGED:
+        event_name = "READONLY_CHANGED";
+        break;
       case AXEventGenerator::Event::RELATED_NODE_CHANGED:
         event_name = "RELATED_NODE_CHANGED";
         break;
-      case AXEventGenerator::Event::READONLY_CHANGED:
-        event_name = "READONLY_CHANGED";
+      case AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
+        event_name = "REQUIRED_STATE_CHANGED";
         break;
       case AXEventGenerator::Event::ROLE_CHANGED:
         event_name = "ROLE_CHANGED";
@@ -1118,4 +1121,21 @@
             DumpEvents(&event_generator));
 }
 
+TEST(AXEventGeneratorTest, RequiredStateChanged) {
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(1);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kTextField;
+
+  AXTree tree(initial_state);
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+
+  update.nodes[0].AddState(ax::mojom::State::kRequired);
+  EXPECT_TRUE(tree.Unserialize(update));
+  EXPECT_EQ("REQUIRED_STATE_CHANGED on 1, STATE_CHANGED on 1",
+            DumpEvents(&event_generator));
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index 80d0e46..2ed547a5 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -946,13 +946,16 @@
   int original_level = original_node.GetIntAttribute(
       ax::mojom::IntAttribute::kHierarchicalLevel);
   // If original node is ordered set, then set its hierarchical level equal to
-  // its first child to ensure the items vector gets populated.
-  // This is due to ordered sets having a hierarchical level of 0, while their
-  // nodes have non-zero hierarchical values.
-  if ((ordered_set == &original_node) &&
-      ordered_set->GetUnignoredChildAtIndex(0)) {
-    original_level = ordered_set->GetUnignoredChildAtIndex(0)->GetIntAttribute(
-        ax::mojom::IntAttribute::kHierarchicalLevel);
+  // its first child that sets a hierarchical level, if any.
+  if (ordered_set == &original_node) {
+    for (int32_t i = 0; i < original_node.GetUnignoredChildCount(); ++i) {
+      int32_t level =
+          original_node.GetUnignoredChildAtIndex(i)->GetIntAttribute(
+              ax::mojom::IntAttribute::kHierarchicalLevel);
+      if (level)
+        original_level =
+            original_level ? std::min(level, original_level) : level;
+    }
   }
   int original_node_index = original_node.GetUnignoredIndexInParent();
   bool node_is_radio_button =
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index 818898d..43f87a9 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -1176,7 +1176,8 @@
       !text_input_client_->HasCompositionText()) {
     // This is a special case to handle text replacement scenarios during
     // English typing when we are trying to replace an existing text with some
-    // new text.
+    // new text. Some third-party IMEs also use SetText() API instead of
+    // InsertTextAtSelection() API to insert new text.
     size_t new_text_size;
     if (new_size == replace_text_range_.start()) {
       // This usually happens when TSF is trying to replace a part of a string
@@ -1187,16 +1188,21 @@
     }
     const base::string16& new_committed_string = string_buffer_document_.substr(
         replace_text_range_.start(), new_text_size);
-    text_input_client_->ExtendSelectionAndDelete(
-        replace_text_range_.end() - replace_text_range_.start(), 0);
+    // if the |replace_text_range_| start is greater than |old_size|, then we
+    // don't need to delete anything because the replacement text hasn't been
+    // inserted into blink yet.
+    if (old_size > replace_text_range_.start()) {
+      text_input_client_->ExtendSelectionAndDelete(
+          old_size - replace_text_range_.start(), 0);
+    }
     text_input_client_->InsertText(new_committed_string);
   } else {
     // Construct string to be committed.
     size_t new_committed_string_offset = old_size;
     size_t new_committed_string_size = new_size - old_size;
-    // This is a special case. if we are replacing existing text, then
-    // commit the new text.
-    if (new_text_inserted_ &&
+    // This is a special case. We should only replace existing text and commit
+    // the new text if replacement text has already been inserted into Blink.
+    if (new_text_inserted_ && (old_size > replace_text_range_.start()) &&
         (replace_text_range_.start() != replace_text_range_.end())) {
       new_committed_string_offset = replace_text_range_.start();
       new_committed_string_size = replace_text_size_;
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc
index 3672fe4..1b532c9 100644
--- a/ui/base/l10n/l10n_util.cc
+++ b/ui/base/l10n/l10n_util.cc
@@ -584,9 +584,17 @@
     UErrorCode error = U_ZERO_ERROR;
     const int kBufferSize = 1024;
 
-    int actual_size = uloc_getDisplayName(
-        locale_code.c_str(), display_locale.c_str(),
-        base::WriteInto(&display_name, kBufferSize), kBufferSize - 1, &error);
+    int actual_size;
+    // For Country code in ICU64 we need to call uloc_getDisplayCountry
+    if (locale_code[0] == '-' || locale_code[0] == '_') {
+      actual_size = uloc_getDisplayCountry(
+          locale_code.c_str(), display_locale.c_str(),
+          base::WriteInto(&display_name, kBufferSize), kBufferSize - 1, &error);
+    } else {
+      actual_size = uloc_getDisplayName(
+          locale_code.c_str(), display_locale.c_str(),
+          base::WriteInto(&display_name, kBufferSize), kBufferSize - 1, &error);
+    }
     DCHECK(U_SUCCESS(error));
     display_name.resize(actual_size);
   }
diff --git a/ui/base/win/shell.cc b/ui/base/win/shell.cc
index a2aa2308..6301000 100644
--- a/ui/base/win/shell.cc
+++ b/ui/base/win/shell.cc
@@ -185,7 +185,7 @@
 bool IsDwmCompositionEnabled() {
   // As of Windows 8, DWM composition is always enabled.
   // In Windows 7 this can change at runtime.
-  if (GetVersion() >= base::win::VERSION_WIN8) {
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
     return true;
   }
   BOOL is_enabled;
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index b914cf4..aa3d8b5 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -1017,6 +1017,37 @@
   }
 }
 
+void Layer::StackChildrenAtBottom(
+    const std::vector<Layer*>& new_leading_children) {
+  std::vector<Layer*> new_children_order;
+  new_children_order.reserve(children_.size());
+
+  cc::LayerList new_cc_children_order;
+  new_cc_children_order.reserve(cc_layer_->children().size());
+
+  for (Layer* leading_child : new_leading_children) {
+    DCHECK_EQ(leading_child->cc_layer_->parent(), cc_layer_);
+    DCHECK_EQ(leading_child->parent(), this);
+    new_children_order.emplace_back(leading_child);
+    new_cc_children_order.emplace_back(
+        scoped_refptr<cc::Layer>(leading_child->cc_layer_));
+  }
+
+  base::flat_set<Layer*> reordered_children(new_children_order);
+
+  const cc::LayerList& old_cc_children_order = cc_layer_->children();
+
+  for (size_t i = 0; i < children_.size(); ++i) {
+    if (reordered_children.count(children_.at(i)) > 0)
+      continue;
+    new_children_order.emplace_back(children_.at(i));
+    new_cc_children_order.emplace_back(old_cc_children_order.at(i));
+  }
+
+  children_ = std::move(new_children_order);
+  cc_layer_->ReorderChildren(&new_cc_children_order);
+}
+
 void Layer::SuppressPaint() {
   if (!delegate_)
     return;
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 9f55961..047d8d69 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -351,6 +351,12 @@
   // Show a solid color instead of delegated or surface contents.
   void SetShowSolidColorContent();
 
+  // Reorder the children to have all children inside |new_leading_children| to
+  // be at the front of the children vector, and the remaining children will
+  // stay in their relative order. |this| must be a parent of all the Layer*
+  // inside |new_leading_children|.
+  void StackChildrenAtBottom(const std::vector<Layer*>& new_leading_children);
+
   // Sets the layer's fill color.  May only be called for LAYER_SOLID_COLOR.
   void SetColor(SkColor color);
   SkColor GetTargetColor() const;
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index 6756eae8..79fcc7d3 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
@@ -1334,6 +1335,34 @@
 
   root->StackBelow(l3.get(), l1.get());
   EXPECT_EQ("2 3 1", test::ChildLayerNamesAsString(*root.get()));
+
+  std::vector<Layer*> child_bottom_stack;
+  child_bottom_stack.emplace_back(l1.get());
+  root->StackChildrenAtBottom(child_bottom_stack);
+  EXPECT_EQ("1 2 3", test::ChildLayerNamesAsString(*root.get()));
+
+  child_bottom_stack.clear();
+  child_bottom_stack.emplace_back(l3.get());
+  child_bottom_stack.emplace_back(l2.get());
+  root->StackChildrenAtBottom(child_bottom_stack);
+  EXPECT_EQ("3 2 1", test::ChildLayerNamesAsString(*root.get()));
+
+  child_bottom_stack.clear();
+  child_bottom_stack.emplace_back(l2.get());
+  child_bottom_stack.emplace_back(l1.get());
+  root->StackChildrenAtBottom(child_bottom_stack);
+  EXPECT_EQ("2 1 3", test::ChildLayerNamesAsString(*root.get()));
+
+  child_bottom_stack.clear();
+  child_bottom_stack.emplace_back(l3.get());
+  child_bottom_stack.emplace_back(l1.get());
+  child_bottom_stack.emplace_back(l2.get());
+  root->StackChildrenAtBottom(child_bottom_stack);
+  EXPECT_EQ("3 1 2", test::ChildLayerNamesAsString(*root.get()));
+
+  child_bottom_stack.clear();
+  root->StackChildrenAtBottom(child_bottom_stack);
+  EXPECT_EQ("3 1 2", test::ChildLayerNamesAsString(*root.get()));
 }
 
 // Verifies SetBounds triggers the appropriate painting/drawing.
diff --git a/ui/display/manager/fake_display_delegate.cc b/ui/display/manager/fake_display_delegate.cc
index 147be83..3337cb8 100644
--- a/ui/display/manager/fake_display_delegate.cc
+++ b/ui/display/manager/fake_display_delegate.cc
@@ -9,7 +9,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
diff --git a/ui/display/manager/touch_device_manager.cc b/ui/display/manager/touch_device_manager.cc
index 45c7bb6..713ecff 100644
--- a/ui/display/manager/touch_device_manager.cc
+++ b/ui/display/manager/touch_device_manager.cc
@@ -10,7 +10,7 @@
 #include <tuple>
 
 #include "base/files/file_util.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
diff --git a/ui/display/util/edid_parser.cc b/ui/display/util/edid_parser.cc
index 868819a..7b98349a 100644
--- a/ui/display/util/edid_parser.cc
+++ b/ui/display/util/edid_parser.cc
@@ -8,7 +8,7 @@
 
 #include <algorithm>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_byteorder.h"
diff --git a/ui/display/win/display_info.cc b/ui/display/win/display_info.cc
index b311708..e26f539 100644
--- a/ui/display/win/display_info.cc
+++ b/ui/display/win/display_info.cc
@@ -4,7 +4,7 @@
 
 #include "ui/display/win/display_info.h"
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/strings/utf_string_conversions.h"
 
 namespace display {
diff --git a/ui/events/keycodes/platform_key_map_win.h b/ui/events/keycodes/platform_key_map_win.h
index fe884c241..d0e4e65 100644
--- a/ui/events/keycodes/platform_key_map_win.h
+++ b/ui/events/keycodes/platform_key_map_win.h
@@ -9,7 +9,7 @@
 
 #include <unordered_map>
 
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "ui/events/event.h"
 #include "ui/events/events_export.h"
 #include "ui/events/keycodes/dom/dom_key.h"
diff --git a/ui/file_manager/file_manager/foreground/css/menu.css b/ui/file_manager/file_manager/foreground/css/menu.css
index d77c7c4..663b34c 100644
--- a/ui/file_manager/file_manager/foreground/css/menu.css
+++ b/ui/file_manager/file_manager/foreground/css/menu.css
@@ -44,6 +44,10 @@
   font-size: 0.7em;
 }
 
+cr-menu > [sub-menu][disabled]::after {
+  color: rgba(51, 51, 51, 0.20);
+}
+
 html[dir='rtl'] cr-menu > [shortcutText]::after {
   float: left;
 }
diff --git a/ui/file_manager/file_manager/foreground/js/actions_controller.js b/ui/file_manager/file_manager/foreground/js/actions_controller.js
index 53611a1..4dbcc99 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_controller.js
@@ -4,92 +4,250 @@
 
 /**
  * Manages actions for the current selection.
- *
- * @param {!VolumeManager} volumeManager
- * @param {!MetadataModel} metadataModel
- * @param {!DirectoryModel} directoryModel
- * @param {!FolderShortcutsDataModel} shortcutsModel
- * @param {!DriveSyncHandler} driveSyncHandler
- * @param {!FileSelectionHandler} selectionHandler
- * @param {!FileManagerUI} ui
- * @constructor
- * @struct
  */
-function ActionsController(
-    volumeManager, metadataModel, directoryModel, shortcutsModel,
-    driveSyncHandler, selectionHandler, ui) {
+class ActionsController {
   /**
-   * @private
-   * @const
+   * @param {!VolumeManager} volumeManager
+   * @param {!MetadataModel} metadataModel
+   * @param {!DirectoryModel} directoryModel
+   * @param {!FolderShortcutsDataModel} shortcutsModel
+   * @param {!DriveSyncHandler} driveSyncHandler
+   * @param {!FileSelectionHandler} selectionHandler
+   * @param {!FileManagerUI} ui
    */
-  this.volumeManager_ = volumeManager;
+  constructor(
+      volumeManager, metadataModel, directoryModel, shortcutsModel,
+      driveSyncHandler, selectionHandler, ui) {
+    /**
+     * @private
+     * @const
+     */
+    this.volumeManager_ = volumeManager;
+
+    /**
+     * @private
+     * @const
+     */
+    this.metadataModel_ = metadataModel;
+
+    /**
+     * @private
+     * @const
+     */
+    this.directoryModel_ = directoryModel;
+
+    /**
+     * @private
+     * @const
+     */
+    this.shortcutsModel_ = shortcutsModel;
+
+    /**
+     * @private
+     * @const
+     */
+    this.driveSyncHandler_ = driveSyncHandler;
+
+    /**
+     * @private
+     * @const
+     */
+    this.selectionHandler_ = selectionHandler;
+
+    /**
+     * @private
+     * @const
+     */
+    this.ui_ = ui;
+
+    /**
+     * @private {ActionsModel}
+     */
+    this.fileListActionsModel_ = null;
+
+    /**
+     * @private {ActionsModel}
+     */
+    this.navigationListActionsModel_ = null;
+
+    /**
+     * @private {number}
+     */
+    this.navigationListSequence_ = 0;
+
+    /**
+     * @private {ActionsController.Context}
+     */
+    this.menuContext_ = ActionsController.Context.UNKNOWN;
+
+    this.ui_.directoryTree.addEventListener(
+        'change', this.onNavigationListSelectionChanged_.bind(this), true);
+    this.selectionHandler_.addEventListener(
+        FileSelectionHandler.EventType.CHANGE,
+        this.onSelectionChanged_.bind(this));
+    this.selectionHandler_.addEventListener(
+        FileSelectionHandler.EventType.CHANGE_THROTTLED,
+        this.onSelectionChangeThrottled_.bind(this));
+    cr.ui.contextMenuHandler.addEventListener(
+        'show', this.onContextMenuShow_.bind(this));
+  }
+
+  /**
+   * @param {Element} element
+   * @return {ActionsController.Context}
+   * @private
+   */
+  getContextFor_(element) {
+    // Element can be null, eg. when invoking a command via a keyboard shortcut.
+    // By default, all actions refer to the file list, so return FILE_LIST.
+    if (element === null) {
+      return ActionsController.Context.FILE_LIST;
+    }
+
+    if (this.ui_.listContainer.element.contains(element) ||
+        this.ui_.toolbar.contains(element)) {
+      return ActionsController.Context.FILE_LIST;
+    } else if (this.ui_.directoryTree.contains(element)) {
+      return ActionsController.Context.NAVIGATION_LIST;
+    } else {
+      return ActionsController.Context.UNKNOWN;
+    }
+  }
 
   /**
    * @private
-   * @const
    */
-  this.metadataModel_ = metadataModel;
+  updateUI_() {
+    const actionsModel = this.getActionsModelForContext(this.menuContext_);
+    // TODO(mtomasz): Prevent flickering somehow.
+    this.ui_.actionsSubmenu.setActionsModel(actionsModel);
+  }
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
+  onContextMenuShow_(event) {
+    this.menuContext_ = this.getContextFor_(event.element);
+    this.updateUI_();
+  }
 
   /**
    * @private
-   * @const
    */
-  this.directoryModel_ = directoryModel;
+  onSelectionChanged_() {
+    if (this.fileListActionsModel_) {
+      this.fileListActionsModel_.destroy();
+      this.fileListActionsModel_ = null;
+    }
+    this.updateUI_();
+  }
 
   /**
    * @private
-   * @const
    */
-  this.shortcutsModel_ = shortcutsModel;
+  onSelectionChangeThrottled_() {
+    assert(!this.fileListActionsModel_);
+    const selection = this.selectionHandler_.selection;
+
+    const entries = selection.entries;
+    if (!entries) {
+      return;
+    }
+
+    const actionsModel = new ActionsModel(
+        this.volumeManager_, this.metadataModel_, this.shortcutsModel_,
+        this.driveSyncHandler_, this.ui_, entries);
+
+    const initializeAndUpdateUI =
+        /** @type {function(Event=)} */ (opt_event => {
+          if (selection !== this.selectionHandler_.selection) {
+            return;
+          }
+          actionsModel.initialize().then(() => {
+            if (selection !== this.selectionHandler_.selection) {
+              return;
+            }
+            this.fileListActionsModel_ = actionsModel;
+            // Before updating the UI we need to ensure that this.menuContext_
+            // has a reasonable value or nothing will happen. We will save and
+            // restore the existing value.
+            const oldMenuContext = this.menuContext_;
+            if (this.menuContext_ === ActionsController.Context.UNKNOWN) {
+              // FILE_LIST should be a reasonable default.
+              this.menuContext_ = ActionsController.Context.FILE_LIST;
+            }
+            this.updateUI_();
+            this.menuContext_ = oldMenuContext;
+          });
+        });
+
+    actionsModel.addEventListener('invalidated', initializeAndUpdateUI);
+    initializeAndUpdateUI();
+  }
 
   /**
    * @private
-   * @const
    */
-  this.driveSyncHandler_ = driveSyncHandler;
+  onNavigationListSelectionChanged_() {
+    if (this.navigationListActionsModel_) {
+      this.navigationListActionsModel_.destroy();
+      this.navigationListActionsModel_ = null;
+    }
+    this.updateUI_();
+
+    const entry = this.ui_.directoryTree.selectedItem ?
+        (this.ui_.directoryTree.selectedItem.entry || null) :
+        null;
+    if (!entry) {
+      return;
+    }
+
+    const sequence = ++this.navigationListSequence_;
+    const actionsModel = new ActionsModel(
+        this.volumeManager_, this.metadataModel_, this.shortcutsModel_,
+        this.driveSyncHandler_, this.ui_, [entry]);
+
+    const initializeAndUpdateUI =
+        /** @type {function(Event=)} */ (opt_event => {
+          actionsModel.initialize().then(() => {
+            if (this.navigationListSequence_ !== sequence) {
+              return;
+            }
+            this.navigationListActionsModel_ = actionsModel;
+            this.updateUI_();
+          });
+        });
+
+    actionsModel.addEventListener('invalidated', initializeAndUpdateUI);
+    initializeAndUpdateUI();
+  }
 
   /**
-   * @private
-   * @const
+   * @param {!ActionsController.Context} context
+   * @return {ActionsModel} Actions model.
    */
-  this.selectionHandler_ = selectionHandler;
+  getActionsModelForContext(context) {
+    switch (context) {
+      case ActionsController.Context.FILE_LIST:
+        return this.fileListActionsModel_;
+
+      case ActionsController.Context.NAVIGATION_LIST:
+        return this.navigationListActionsModel_;
+
+      default:
+        return null;
+    }
+  }
 
   /**
-   * @private
-   * @const
+   * @param {EventTarget} target
+   * @return {ActionsModel} Actions model.
    */
-  this.ui_ = ui;
-
-  /**
-   * @private {ActionsModel}
-   */
-  this.fileListActionsModel_ = null;
-
-  /**
-   * @private {ActionsModel}
-   */
-  this.navigationListActionsModel_ = null;
-
-  /**
-   * @private {number}
-   */
-  this.navigationListSequence_ = 0;
-
-  /**
-   * @private {ActionsController.Context}
-   */
-  this.menuContext_ = ActionsController.Context.UNKNOWN;
-
-  this.ui_.directoryTree.addEventListener(
-      'change', this.onNavigationListSelectionChanged_.bind(this), true);
-  this.selectionHandler_.addEventListener(
-      FileSelectionHandler.EventType.CHANGE,
-      this.onSelectionChanged_.bind(this));
-  this.selectionHandler_.addEventListener(
-      FileSelectionHandler.EventType.CHANGE_THROTTLED,
-      this.onSelectionChangeThrottled_.bind(this));
-  cr.ui.contextMenuHandler.addEventListener(
-      'show', this.onContextMenuShow_.bind(this));
+  getActionsModelFor(target) {
+    const element = /** @type {Element} */ (target);
+    return this.getActionsModelForContext(this.getContextFor_(element));
+  }
 }
 
 /**
@@ -100,159 +258,3 @@
   NAVIGATION_LIST: 'navigation-list',
   UNKNOWN: 'unknown'
 };
-
-/**
- * @param {Element} element
- * @return {ActionsController.Context}
- * @private
- */
-ActionsController.prototype.getContextFor_ = function(element) {
-  // Element can be null, eg. when invoking a command via a keyboard shortcut.
-  // By default, all actions refer to the file list, so return FILE_LIST.
-  if (element === null) {
-    return ActionsController.Context.FILE_LIST;
-  }
-
-  if (this.ui_.listContainer.element.contains(element) ||
-      this.ui_.toolbar.contains(element)) {
-    return ActionsController.Context.FILE_LIST;
-  } else if (this.ui_.directoryTree.contains(element)) {
-    return ActionsController.Context.NAVIGATION_LIST;
-  } else {
-    return ActionsController.Context.UNKNOWN;
-  }
-};
-
-/**
- * @private
- */
-ActionsController.prototype.updateUI_ = function() {
-  const actionsModel = this.getActionsModelForContext(this.menuContext_);
-  // TODO(mtomasz): Prevent flickering somehow.
-  this.ui_.actionsSubmenu.setActionsModel(actionsModel);
-};
-
-/**
- * @param {!Event} event
- * @private
- */
-ActionsController.prototype.onContextMenuShow_ = function(event) {
-  this.menuContext_ = this.getContextFor_(event.element);
-  this.updateUI_();
-};
-
-/**
- * @private
- */
-ActionsController.prototype.onSelectionChanged_ = function() {
-  if (this.fileListActionsModel_) {
-    this.fileListActionsModel_.destroy();
-    this.fileListActionsModel_ = null;
-  }
-  this.updateUI_();
-};
-
-/**
- * @private
- */
-ActionsController.prototype.onSelectionChangeThrottled_ = function() {
-  assert(!this.fileListActionsModel_);
-  const selection = this.selectionHandler_.selection;
-
-  const entries = selection.entries;
-  if (!entries) {
-    return;
-  }
-
-  const actionsModel = new ActionsModel(
-      this.volumeManager_, this.metadataModel_, this.shortcutsModel_,
-      this.driveSyncHandler_, this.ui_, entries);
-
-  const initializeAndUpdateUI =
-      /** @type {function(Event=)} */ (opt_event => {
-        if (selection !== this.selectionHandler_.selection) {
-          return;
-        }
-        actionsModel.initialize().then(() => {
-          if (selection !== this.selectionHandler_.selection) {
-            return;
-          }
-          this.fileListActionsModel_ = actionsModel;
-          // Before updating the UI we need to ensure that this.menuContext_ has
-          // a reasonable value or nothing will happen. We will save and restore
-          // the existing value.
-          const oldMenuContext = this.menuContext_;
-          if (this.menuContext_ === ActionsController.Context.UNKNOWN) {
-            // FILE_LIST should be a reasonable default.
-            this.menuContext_ = ActionsController.Context.FILE_LIST;
-          }
-          this.updateUI_();
-          this.menuContext_ = oldMenuContext;
-        });
-      });
-
-  actionsModel.addEventListener('invalidated', initializeAndUpdateUI);
-  initializeAndUpdateUI();
-};
-
-/**
- * @private
- */
-ActionsController.prototype.onNavigationListSelectionChanged_ = function() {
-  if (this.navigationListActionsModel_) {
-    this.navigationListActionsModel_.destroy();
-    this.navigationListActionsModel_ = null;
-  }
-  this.updateUI_();
-
-  const entry = this.ui_.directoryTree.selectedItem ?
-      (this.ui_.directoryTree.selectedItem.entry || null) :
-      null;
-  if (!entry) {
-    return;
-  }
-
-  const sequence = ++this.navigationListSequence_;
-  const actionsModel = new ActionsModel(
-      this.volumeManager_, this.metadataModel_, this.shortcutsModel_,
-      this.driveSyncHandler_, this.ui_, [entry]);
-
-  const initializeAndUpdateUI =
-      /** @type {function(Event=)} */ (opt_event => {
-        actionsModel.initialize().then(() => {
-          if (this.navigationListSequence_ !== sequence) {
-            return;
-          }
-          this.navigationListActionsModel_ = actionsModel;
-          this.updateUI_();
-        });
-      });
-
-  actionsModel.addEventListener('invalidated', initializeAndUpdateUI);
-  initializeAndUpdateUI();
-};
-
-/**
- * @param {!ActionsController.Context} context
- * @return {ActionsModel} Actions model.
- */
-ActionsController.prototype.getActionsModelForContext = function(context) {
-  switch (context) {
-    case ActionsController.Context.FILE_LIST:
-      return this.fileListActionsModel_;
-
-    case ActionsController.Context.NAVIGATION_LIST:
-      return this.navigationListActionsModel_;
-
-    default:
-      return null;
-  }
-};
-/**
- * @param {EventTarget} target
- * @return {ActionsModel} Actions model.
- */
-ActionsController.prototype.getActionsModelFor = function(target) {
-  const element = /** @type {Element} */ (target);
-  return this.getActionsModelForContext(this.getContextFor_(element));
-};
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js
index 9f676723..5e4a466 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -6,24 +6,24 @@
  * A single action, that can be taken on a set of entries.
  * @interface
  */
-function Action() {}
+class Action {
+  /**
+   * Executes this action on the set of entries.
+   */
+  execute() {}
 
-/**
- * Executes this action on the set of entries.
- */
-Action.prototype.execute = () => {};
+  /**
+   * Checks whether this action can execute on the set of entries.
+   *
+   * @return {boolean} True if the function can execute, false if not.
+   */
+  canExecute() {}
 
-/**
- * Checks whether this action can execute on the set of entries.
- *
- * @return {boolean} True if the function can execute, false if not.
- */
-Action.prototype.canExecute = () => {};
-
-/**
- * @return {?string}
- */
-Action.prototype.getTitle = () => {};
+  /**
+   * @return {?string}
+   */
+  getTitle() {}
+}
 
 /**
  * @typedef {{
@@ -34,642 +34,811 @@
  */
 let ActionModelUI;
 
-/**
- * @param {!Entry} entry
- * @param {!MetadataModel} metadataModel
- * @param {!ActionModelUI} ui
- * @param {!VolumeManager} volumeManager
- * @implements {Action}
- * @constructor
- * @struct
- */
-function DriveShareAction(entry, metadataModel, volumeManager, ui) {
+/** @implements {Action} */
+class DriveShareAction {
   /**
-   * @private {!Entry}
-   * @const
+   * @param {!Entry} entry
+   * @param {!MetadataModel} metadataModel
+   * @param {!ActionModelUI} ui
+   * @param {!VolumeManager} volumeManager
    */
-  this.entry_ = entry;
+  constructor(entry, metadataModel, volumeManager, ui) {
+    /**
+     * @private {!Entry}
+     * @const
+     */
+    this.entry_ = entry;
+
+    /**
+     * @private {!MetadataModel}
+     * @const
+     */
+    this.metadataModel_ = metadataModel;
+
+    /**
+     * @private {!VolumeManager}
+     * @const
+     */
+    this.volumeManager_ = volumeManager;
+
+    /**
+     * @private {!ActionModelUI}
+     * @const
+     */
+    this.ui_ = ui;
+  }
 
   /**
-   * @private {!MetadataModel}
-   * @const
+   * @param {!Array<!Entry>} entries
+   * @param {!MetadataModel} metadataModel
+   * @param {!ActionModelUI} ui
+   * @param {!VolumeManager} volumeManager
+   * @return {DriveShareAction}
    */
-  this.metadataModel_ = metadataModel;
+  static create(entries, metadataModel, volumeManager, ui) {
+    if (entries.length !== 1) {
+      return null;
+    }
+    return new DriveShareAction(entries[0], metadataModel, volumeManager, ui);
+  }
 
   /**
-   * @private {!VolumeManager}
-   * @const
+   * @override
    */
-  this.volumeManager_ = volumeManager;
+  execute() {
+    // Open the Sharing dialog in a new window.
+    chrome.fileManagerPrivate.getEntryProperties(
+        [this.entry_], ['shareUrl'], results => {
+          if (chrome.runtime.lastError) {
+            console.error(chrome.runtime.lastError.message);
+            return;
+          }
+          if (results.length != 1) {
+            console.error(
+                'getEntryProperties for shareUrl should return 1 entry ' +
+                '(returned ' + results.length + ')');
+            return;
+          }
+          if (results[0].shareUrl === undefined) {
+            console.error('getEntryProperties shareUrl is undefined');
+            return;
+          }
+          util.visitURL(assert(results[0].shareUrl));
+        });
+  }
 
   /**
-   * @private {!ActionModelUI}
-   * @const
+   * @override
    */
-  this.ui_ = ui;
-}
+  canExecute() {
+    const metadata = this.metadataModel_.getCache([this.entry_], ['canShare']);
+    assert(metadata.length === 1);
+    const canShareItem = metadata[0].canShare !== false;
+    return this.volumeManager_.getDriveConnectionState().type !==
+        VolumeManagerCommon.DriveConnectionType.OFFLINE &&
+        (loadTimeData.getBoolean('DRIVE_FS_ENABLED') ||
+         !util.isTeamDriveRoot(this.entry_)) &&
+        canShareItem;
+  }
 
-/**
- * @param {!Array<!Entry>} entries
- * @param {!MetadataModel} metadataModel
- * @param {!ActionModelUI} ui
- * @param {!VolumeManager} volumeManager
- * @return {DriveShareAction}
- */
-DriveShareAction.create = (entries, metadataModel, volumeManager, ui) => {
-  if (entries.length !== 1) {
+  /**
+   * @return {?string}
+   */
+  getTitle() {
     return null;
   }
-  return new DriveShareAction(entries[0], metadataModel, volumeManager, ui);
-};
-
-/**
- * @override
- */
-DriveShareAction.prototype.execute = function() {
-  // Open the Sharing dialog in a new window.
-  chrome.fileManagerPrivate.getEntryProperties(
-      [this.entry_], ['shareUrl'], results => {
-        if (chrome.runtime.lastError) {
-          console.error(chrome.runtime.lastError.message);
-          return;
-        }
-        if (results.length != 1) {
-          console.error(
-              'getEntryProperties for shareUrl should return 1 entry ' +
-              '(returned ' + results.length + ')');
-          return;
-        }
-        if (results[0].shareUrl === undefined) {
-          console.error('getEntryProperties shareUrl is undefined');
-          return;
-        }
-        util.visitURL(assert(results[0].shareUrl));
-      });
-};
-
-/**
- * @override
- */
-DriveShareAction.prototype.canExecute = function() {
-  const metadata = this.metadataModel_.getCache([this.entry_], ['canShare']);
-  assert(metadata.length === 1);
-  const canShareItem = metadata[0].canShare !== false;
-  return this.volumeManager_.getDriveConnectionState().type !==
-      VolumeManagerCommon.DriveConnectionType.OFFLINE &&
-      (loadTimeData.getBoolean('DRIVE_FS_ENABLED') ||
-       !util.isTeamDriveRoot(this.entry_)) &&
-      canShareItem;
-};
-
-/**
- * @return {?string}
- */
-DriveShareAction.prototype.getTitle = () => {
-  return null;
-};
-
-/**
- * @param {!Array<!Entry>} entries
- * @param {!MetadataModel} metadataModel
- * @param {!DriveSyncHandler} driveSyncHandler
- * @param {!ActionModelUI} ui
- * @param {boolean} value
- * @param {function()} onExecute
- * @implements {Action}
- * @constructor
- * @struct
- */
-function DriveToggleOfflineAction(
-    entries, metadataModel, driveSyncHandler, ui, value, onExecute) {
-  /**
-   * @private {!Array<!Entry>}
-   * @const
-   */
-  this.entries_ = entries;
-
-  /**
-   * @private {!MetadataModel}
-   * @const
-   */
-  this.metadataModel_ = metadataModel;
-
-  /**
-   * @private {!DriveSyncHandler}
-   * @const
-   */
-  this.driveSyncHandler_ = driveSyncHandler;
-
-  /**
-   * @private {!ActionModelUI}
-   * @const
-   */
-  this.ui_ = ui;
-
-  /**
-   * @private {boolean}
-   * @const
-   */
-  this.value_ = value;
-
-  /**
-   * @private {function()}
-   * @const
-   */
-  this.onExecute_ = onExecute;
 }
 
-/**
- * @param {!Array<!Entry>} entries
- * @param {!MetadataModel} metadataModel
- * @param {!DriveSyncHandler} driveSyncHandler
- * @param {!ActionModelUI} ui
- * @param {boolean} value
- * @param {function()} onExecute
- * @return {DriveToggleOfflineAction}
- */
-DriveToggleOfflineAction.create =
-    (entries, metadataModel, driveSyncHandler, ui, value, onExecute) => {
-      if (!loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
-        if (entries.some((entry) => entry.isDirectory)) {
-          return null;
-        }
-      }
 
-      const actionableEntries = entries.filter(entry => {
-        if (entry.isDirectory && !loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
-          return false;
-        }
-        const metadata =
-            metadataModel.getCache([entry], ['hosted', 'pinned'])[0];
-        if (metadata.hosted) {
-          return false;
-        }
-        if (metadata.pinned === value) {
-          return false;
-        }
-        return true;
-      });
+/** @implements {Action} */
+class DriveToggleOfflineAction {
+  /**
+   * @param {!Array<!Entry>} entries
+   * @param {!MetadataModel} metadataModel
+   * @param {!DriveSyncHandler} driveSyncHandler
+   * @param {!ActionModelUI} ui
+   * @param {boolean} value
+   * @param {function()} onExecute
+   */
+  constructor(entries, metadataModel, driveSyncHandler, ui, value, onExecute) {
+    /**
+     * @private {!Array<!Entry>}
+     * @const
+     */
+    this.entries_ = entries;
 
-      if (actionableEntries.length === 0) {
-        return null;
-      }
+    /**
+     * @private {!MetadataModel}
+     * @const
+     */
+    this.metadataModel_ = metadataModel;
 
-      return new DriveToggleOfflineAction(
-          actionableEntries, metadataModel, driveSyncHandler, ui, value,
-          onExecute);
-    };
+    /**
+     * @private {!DriveSyncHandler}
+     * @const
+     */
+    this.driveSyncHandler_ = driveSyncHandler;
 
-/**
- * @override
- */
-DriveToggleOfflineAction.prototype.execute = function() {
-  const entries = this.entries_;
-  if (entries.length == 0) {
-    return;
+    /**
+     * @private {!ActionModelUI}
+     * @const
+     */
+    this.ui_ = ui;
+
+    /**
+     * @private {boolean}
+     * @const
+     */
+    this.value_ = value;
+
+    /**
+     * @private {function()}
+     * @const
+     */
+    this.onExecute_ = onExecute;
   }
 
-  let currentEntry;
-  let error = false;
-
-  const steps = {
-    // Pick an entry and pin it.
-    start: () => {
-      // Check if all the entries are pinned or not.
-      if (entries.length === 0) {
-        this.onExecute_();
-        return;
+  /**
+   * @param {!Array<!Entry>} entries
+   * @param {!MetadataModel} metadataModel
+   * @param {!DriveSyncHandler} driveSyncHandler
+   * @param {!ActionModelUI} ui
+   * @param {boolean} value
+   * @param {function()} onExecute
+   * @return {DriveToggleOfflineAction}
+   */
+  static create(
+      entries, metadataModel, driveSyncHandler, ui, value, onExecute) {
+    if (!loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
+      if (entries.some((entry) => entry.isDirectory)) {
+        return null;
       }
-      currentEntry = entries.shift();
-      chrome.fileManagerPrivate.pinDriveFile(
-          currentEntry, this.value_, steps.entryPinned);
-    },
-
-    // Check the result of pinning.
-    entryPinned: () => {
-      error = !!chrome.runtime.lastError;
-      if (error && this.value_) {
-        this.metadataModel_.get([currentEntry], ['size']).then(results => {
-          steps.showError(results[0].size);
-        });
-        return;
-      }
-      this.metadataModel_.notifyEntriesChanged([currentEntry]);
-      this.metadataModel_.get([currentEntry], ['pinned']).then(steps.updateUI);
-    },
-
-    // Update the user interface according to the cache state.
-    updateUI: () => {
-      this.ui_.listContainer.currentView.updateListItemsMetadata(
-          'external', [currentEntry]);
-      if (!error) {
-        steps.start();
-      }
-    },
-
-    // Show an error.
-    showError: size => {
-      this.ui_.alertDialog.showHtml(
-          str('DRIVE_OUT_OF_SPACE_HEADER'),
-          strf(
-              'DRIVE_OUT_OF_SPACE_MESSAGE', unescape(currentEntry.name),
-              util.bytesToString(size)),
-          null, null, null);
     }
-  };
-  steps.start();
 
-  if (this.value_ && this.driveSyncHandler_.isSyncSuppressed()) {
-    this.driveSyncHandler_.showDisabledMobileSyncNotification();
+    const actionableEntries = entries.filter(entry => {
+      if (entry.isDirectory && !loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
+        return false;
+      }
+      const metadata = metadataModel.getCache([entry], ['hosted', 'pinned'])[0];
+      if (metadata.hosted) {
+        return false;
+      }
+      if (metadata.pinned === value) {
+        return false;
+      }
+      return true;
+    });
+
+    if (actionableEntries.length === 0) {
+      return null;
+    }
+
+    return new DriveToggleOfflineAction(
+        actionableEntries, metadataModel, driveSyncHandler, ui, value,
+        onExecute);
   }
-};
-
-/**
- * @override
- */
-DriveToggleOfflineAction.prototype.canExecute = () => {
-  return true;
-};
-
-/**
- * @return {?string}
- */
-DriveToggleOfflineAction.prototype.getTitle = () => {
-  return null;
-};
-
-/**
- * @param {!Entry} entry
- * @param {!FolderShortcutsDataModel} shortcutsModel
- * @param {function()} onExecute
- * @implements {Action}
- * @constructor
- * @struct
- */
-function DriveCreateFolderShortcutAction(entry, shortcutsModel, onExecute) {
-  /**
-   * @private {!Entry}
-   * @const
-   */
-  this.entry_ = entry;
 
   /**
-   * @private {!FolderShortcutsDataModel}
-   * @const
+   * @override
    */
-  this.shortcutsModel_ = shortcutsModel;
+  execute() {
+    const entries = this.entries_;
+    if (entries.length == 0) {
+      return;
+    }
+
+    let currentEntry;
+    let error = false;
+
+    const steps = {
+      // Pick an entry and pin it.
+      start: () => {
+        // Check if all the entries are pinned or not.
+        if (entries.length === 0) {
+          this.onExecute_();
+          return;
+        }
+        currentEntry = entries.shift();
+        chrome.fileManagerPrivate.pinDriveFile(
+            currentEntry, this.value_, steps.entryPinned);
+      },
+
+      // Check the result of pinning.
+      entryPinned: () => {
+        error = !!chrome.runtime.lastError;
+        if (error && this.value_) {
+          this.metadataModel_.get([currentEntry], ['size']).then(results => {
+            steps.showError(results[0].size);
+          });
+          return;
+        }
+        this.metadataModel_.notifyEntriesChanged([currentEntry]);
+        this.metadataModel_.get([currentEntry], ['pinned'])
+            .then(steps.updateUI);
+      },
+
+      // Update the user interface according to the cache state.
+      updateUI: () => {
+        this.ui_.listContainer.currentView.updateListItemsMetadata(
+            'external', [currentEntry]);
+        if (!error) {
+          steps.start();
+        }
+      },
+
+      // Show an error.
+      showError: size => {
+        this.ui_.alertDialog.showHtml(
+            str('DRIVE_OUT_OF_SPACE_HEADER'),
+            strf(
+                'DRIVE_OUT_OF_SPACE_MESSAGE', unescape(currentEntry.name),
+                util.bytesToString(size)),
+            null, null, null);
+      }
+    };
+    steps.start();
+
+    if (this.value_ && this.driveSyncHandler_.isSyncSuppressed()) {
+      this.driveSyncHandler_.showDisabledMobileSyncNotification();
+    }
+  }
 
   /**
-   * @private {function()}
-   * @const
+   * @override
    */
-  this.onExecute_ = onExecute;
+  canExecute() {
+    return true;
+  }
+
+  /**
+   * @return {?string}
+   */
+  getTitle() {
+    return null;
+  }
 }
 
-/**
- * @param {!Array<!Entry>} entries
- * @param {!VolumeManager} volumeManager
- * @param {!FolderShortcutsDataModel} shortcutsModel
- * @param {function()} onExecute
- * @return {DriveCreateFolderShortcutAction}
- */
-DriveCreateFolderShortcutAction.create =
-    (entries, volumeManager, shortcutsModel, onExecute) => {
-      if (entries.length !== 1 || entries[0].isFile) {
-        return null;
-      }
-      const locationInfo = volumeManager.getLocationInfo(entries[0]);
-      if (!locationInfo || locationInfo.isSpecialSearchRoot ||
-          locationInfo.isRootEntry) {
-        return null;
-      }
-      return new DriveCreateFolderShortcutAction(
-          entries[0], shortcutsModel, onExecute);
-    };
 
-/**
- * @override
- */
-DriveCreateFolderShortcutAction.prototype.execute = function() {
-  this.shortcutsModel_.add(this.entry_);
-  this.onExecute_();
-};
-
-/**
- * @override
- */
-DriveCreateFolderShortcutAction.prototype.canExecute = function() {
-  return !this.shortcutsModel_.exists(this.entry_);
-};
-
-/**
- * @return {?string}
- */
-DriveCreateFolderShortcutAction.prototype.getTitle = () => {
-  return null;
-};
-
-/**
- * @param {!Entry} entry
- * @param {!FolderShortcutsDataModel} shortcutsModel
- * @param {function()} onExecute
- * @implements {Action}
- * @constructor
- * @struct
- */
-function DriveRemoveFolderShortcutAction(entry, shortcutsModel, onExecute) {
+/** @implements {Action} */
+class DriveCreateFolderShortcutAction {
   /**
-   * @private {!Entry}
-   * @const
+   * @param {!Entry} entry
+   * @param {!FolderShortcutsDataModel} shortcutsModel
+   * @param {function()} onExecute
    */
-  this.entry_ = entry;
+  constructor(entry, shortcutsModel, onExecute) {
+    /**
+     * @private {!Entry}
+     * @const
+     */
+    this.entry_ = entry;
+
+    /**
+     * @private {!FolderShortcutsDataModel}
+     * @const
+     */
+    this.shortcutsModel_ = shortcutsModel;
+
+    /**
+     * @private {function()}
+     * @const
+     */
+    this.onExecute_ = onExecute;
+  }
 
   /**
-   * @private {!FolderShortcutsDataModel}
-   * @const
+   * @param {!Array<!Entry>} entries
+   * @param {!VolumeManager} volumeManager
+   * @param {!FolderShortcutsDataModel} shortcutsModel
+   * @param {function()} onExecute
+   * @return {DriveCreateFolderShortcutAction}
    */
-  this.shortcutsModel_ = shortcutsModel;
+  static create(entries, volumeManager, shortcutsModel, onExecute) {
+    if (entries.length !== 1 || entries[0].isFile) {
+      return null;
+    }
+    const locationInfo = volumeManager.getLocationInfo(entries[0]);
+    if (!locationInfo || locationInfo.isSpecialSearchRoot ||
+        locationInfo.isRootEntry) {
+      return null;
+    }
+    return new DriveCreateFolderShortcutAction(
+        entries[0], shortcutsModel, onExecute);
+  }
 
   /**
-   * @private {function()}
-   * @const
+   * @override
    */
-  this.onExecute_ = onExecute;
+  execute() {
+    this.shortcutsModel_.add(this.entry_);
+    this.onExecute_();
+  }
+
+  /**
+   * @override
+   */
+  canExecute() {
+    return !this.shortcutsModel_.exists(this.entry_);
+  }
+
+  /**
+   * @return {?string}
+   */
+  getTitle() {
+    return null;
+  }
 }
 
-/**
- * @param {!Array<!Entry>} entries
- * @param {!FolderShortcutsDataModel} shortcutsModel
- * @param {function()} onExecute
- * @return {DriveRemoveFolderShortcutAction}
- */
-DriveRemoveFolderShortcutAction.create =
-    (entries, shortcutsModel, onExecute) => {
-      if (entries.length !== 1 || entries[0].isFile ||
-          !shortcutsModel.exists(entries[0])) {
-        return null;
-      }
-      return new DriveRemoveFolderShortcutAction(
-          entries[0], shortcutsModel, onExecute);
-    };
 
-/**
- * @override
- */
-DriveRemoveFolderShortcutAction.prototype.execute = function() {
-  this.shortcutsModel_.remove(this.entry_);
-  this.onExecute_();
-};
+/** @implements {Action} */
+class DriveRemoveFolderShortcutAction {
+  /**
+   * @param {!Entry} entry
+   * @param {!FolderShortcutsDataModel} shortcutsModel
+   * @param {function()} onExecute
+   */
+  constructor(entry, shortcutsModel, onExecute) {
+    /**
+     * @private {!Entry}
+     * @const
+     */
+    this.entry_ = entry;
 
-/**
- * @override
- */
-DriveRemoveFolderShortcutAction.prototype.canExecute = function() {
-  return this.shortcutsModel_.exists(this.entry_);
-};
+    /**
+     * @private {!FolderShortcutsDataModel}
+     * @const
+     */
+    this.shortcutsModel_ = shortcutsModel;
 
-/**
- * @return {?string}
- */
-DriveRemoveFolderShortcutAction.prototype.getTitle = () => {
-  return null;
-};
+    /**
+     * @private {function()}
+     * @const
+     */
+    this.onExecute_ = onExecute;
+  }
+
+  /**
+   * @param {!Array<!Entry>} entries
+   * @param {!FolderShortcutsDataModel} shortcutsModel
+   * @param {function()} onExecute
+   * @return {DriveRemoveFolderShortcutAction}
+   */
+  static create(entries, shortcutsModel, onExecute) {
+    if (entries.length !== 1 || entries[0].isFile ||
+        !shortcutsModel.exists(entries[0])) {
+      return null;
+    }
+    return new DriveRemoveFolderShortcutAction(
+        entries[0], shortcutsModel, onExecute);
+  }
+
+  /**
+   * @override
+   */
+  execute() {
+    this.shortcutsModel_.remove(this.entry_);
+    this.onExecute_();
+  }
+
+  /**
+   * @override
+   */
+  canExecute() {
+    return this.shortcutsModel_.exists(this.entry_);
+  }
+
+  /**
+   * @return {?string}
+   */
+  getTitle() {
+    return null;
+  }
+}
 
 
 /**
  * Opens the entry in Drive Web for the user to manage permissions etc.
  *
- * @param {!Entry} entry The entry to open the 'Manage' page for.
- * @param {!ActionModelUI} ui
- * @param {!VolumeManager} volumeManager
  * @implements {Action}
- * @constructor
- * @struct
  */
-function DriveManageAction(entry, volumeManager, ui) {
+class DriveManageAction {
   /**
-   * The entry to open the 'Manage' page for.
-   *
-   * @private {!Entry}
-   * @const
+   * @param {!Entry} entry The entry to open the 'Manage' page for.
+   * @param {!ActionModelUI} ui
+   * @param {!VolumeManager} volumeManager
    */
-  this.entry_ = entry;
+  constructor(entry, volumeManager, ui) {
+    /**
+     * The entry to open the 'Manage' page for.
+     *
+     * @private {!Entry}
+     * @const
+     */
+    this.entry_ = entry;
 
-  /**
-   * @private {!VolumeManager}
-   * @const
-   */
-  this.volumeManager_ = volumeManager;
+    /**
+     * @private {!VolumeManager}
+     * @const
+     */
+    this.volumeManager_ = volumeManager;
 
-  /**
-   * @private {!ActionModelUI}
-   * @const
-   */
-  this.ui_ = ui;
-}
-
-/**
- * Creates a new DriveManageAction object.
- * |entries| must contain only a single entry.
- *
- * @param {!Array<!Entry>} entries
- * @param {!ActionModelUI} ui
- * @param {!VolumeManager} volumeManager
- * @return {DriveManageAction}
- */
-DriveManageAction.create = (entries, volumeManager, ui) => {
-  if (entries.length !== 1) {
-    return null;
+    /**
+     * @private {!ActionModelUI}
+     * @const
+     */
+    this.ui_ = ui;
   }
 
-  return new DriveManageAction(entries[0], volumeManager, ui);
-};
+  /**
+   * Creates a new DriveManageAction object.
+   * |entries| must contain only a single entry.
+   *
+   * @param {!Array<!Entry>} entries
+   * @param {!ActionModelUI} ui
+   * @param {!VolumeManager} volumeManager
+   * @return {DriveManageAction}
+   */
+  static create(entries, volumeManager, ui) {
+    if (entries.length !== 1) {
+      return null;
+    }
 
-/**
- * @override
- */
-DriveManageAction.prototype.execute = function() {
-  chrome.fileManagerPrivate.getEntryProperties(
-      [this.entry_], ['alternateUrl'], results => {
-        if (chrome.runtime.lastError) {
-          console.error(chrome.runtime.lastError.message);
-          return;
-        }
-        if (results.length != 1) {
-          console.error(
-              'getEntryProperties for alternateUrl should return 1 entry ' +
-              '(returned ' + results.length + ')');
-          return;
-        }
-        if (results[0].alternateUrl === undefined) {
-          console.error('getEntryProperties alternateUrl is undefined');
-          return;
-        }
-        util.visitURL(assert(results[0].alternateUrl));
-      });
-};
+    return new DriveManageAction(entries[0], volumeManager, ui);
+  }
 
-/**
- * @override
- */
-DriveManageAction.prototype.canExecute = function() {
-  return this.volumeManager_.getDriveConnectionState().type !==
-      VolumeManagerCommon.DriveConnectionType.OFFLINE &&
-      (loadTimeData.getBoolean('DRIVE_FS_ENABLED') ||
-       !util.isTeamDriveRoot(this.entry_));
-};
+  /**
+   * @override
+   */
+  execute() {
+    chrome.fileManagerPrivate.getEntryProperties(
+        [this.entry_], ['alternateUrl'], results => {
+          if (chrome.runtime.lastError) {
+            console.error(chrome.runtime.lastError.message);
+            return;
+          }
+          if (results.length != 1) {
+            console.error(
+                'getEntryProperties for alternateUrl should return 1 entry ' +
+                '(returned ' + results.length + ')');
+            return;
+          }
+          if (results[0].alternateUrl === undefined) {
+            console.error('getEntryProperties alternateUrl is undefined');
+            return;
+          }
+          util.visitURL(assert(results[0].alternateUrl));
+        });
+  }
 
-/**
- * @return {?string}
- */
-DriveManageAction.prototype.getTitle = () => {
-  return null;
-};
+  /**
+   * @override
+   */
+  canExecute() {
+    return this.volumeManager_.getDriveConnectionState().type !==
+        VolumeManagerCommon.DriveConnectionType.OFFLINE &&
+        (loadTimeData.getBoolean('DRIVE_FS_ENABLED') ||
+         !util.isTeamDriveRoot(this.entry_));
+  }
+
+  /**
+   * @return {?string}
+   */
+  getTitle() {
+    return null;
+  }
+}
 
 
 /**
  * A custom action set by the FSP API.
  *
- * @param {!Array<!Entry>} entries
- * @param {string} id
- * @param {?string} title
- * @param {function()} onExecute
  * @implements {Action}
- * @constructor
- * @struct
  */
-function CustomAction(entries, id, title, onExecute) {
+class CustomAction {
   /**
-   * @private {!Array<!Entry>}
-   * @const
+   * @param {!Array<!Entry>} entries
+   * @param {string} id
+   * @param {?string} title
+   * @param {function()} onExecute
    */
-  this.entries_ = entries;
+  constructor(entries, id, title, onExecute) {
+    /**
+     * @private {!Array<!Entry>}
+     * @const
+     */
+    this.entries_ = entries;
+
+    /**
+     * @private {string}
+     * @const
+     */
+    this.id_ = id;
+
+    /**
+     * @private {?string}
+     * @const
+     */
+    this.title_ = title;
+
+    /**
+     * @private {function()}
+     * @const
+     */
+    this.onExecute_ = onExecute;
+  }
 
   /**
-   * @private {string}
-   * @const
+   * @override
    */
-  this.id_ = id;
+  execute() {
+    chrome.fileManagerPrivate.executeCustomAction(
+        this.entries_, this.id_, () => {
+          if (chrome.runtime.lastError) {
+            console.error(
+                'Failed to execute a custom action because of: ' +
+                chrome.runtime.lastError.message);
+          }
+          this.onExecute_();
+        });
+  }
 
   /**
-   * @private {?string}
-   * @const
+   * @override
    */
-  this.title_ = title;
+  canExecute() {
+    return true;  // Custom actions are always executable.
+  }
 
   /**
-   * @private {function()}
-   * @const
+   * @override
    */
-  this.onExecute_ = onExecute;
+  getTitle() {
+    return this.title_;
+  }
 }
 
 /**
- * @override
- */
-CustomAction.prototype.execute = function() {
-  chrome.fileManagerPrivate.executeCustomAction(this.entries_, this.id_, () => {
-    if (chrome.runtime.lastError) {
-      console.error(
-          'Failed to execute a custom action because of: ' +
-          chrome.runtime.lastError.message);
-    }
-    this.onExecute_();
-  });
-};
-
-/**
- * @override
- */
-CustomAction.prototype.canExecute = () => {
-  return true;  // Custom actions are always executable.
-};
-
-/**
- * @override
- */
-CustomAction.prototype.getTitle = function() {
-  return this.title_;
-};
-
-/**
  * Represents a set of actions for a set of entries. Includes actions set
  * locally in JS, as well as those retrieved from the FSP API.
- *
- * @param {!VolumeManager} volumeManager
- * @param {!MetadataModel} metadataModel
- * @param {!FolderShortcutsDataModel} shortcutsModel
- * @param {!DriveSyncHandler} driveSyncHandler
- * @param {!ActionModelUI} ui
- * @param {!Array<!Entry>} entries
- * @constructor
- * @extends {cr.EventTarget}
- * @struct
  */
-function ActionsModel(
-    volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui,
-    entries) {
+class ActionsModel extends cr.EventTarget {
   /**
-   * @private {!VolumeManager}
-   * @const
+   * @param {!VolumeManager} volumeManager
+   * @param {!MetadataModel} metadataModel
+   * @param {!FolderShortcutsDataModel} shortcutsModel
+   * @param {!DriveSyncHandler} driveSyncHandler
+   * @param {!ActionModelUI} ui
+   * @param {!Array<!Entry>} entries
    */
-  this.volumeManager_ = volumeManager;
+  constructor(
+      volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui,
+      entries) {
+    super();
+
+    /**
+     * @private {!VolumeManager}
+     * @const
+     */
+    this.volumeManager_ = volumeManager;
+
+    /**
+     * @private {!MetadataModel}
+     * @const
+     */
+    this.metadataModel_ = metadataModel;
+
+    /**
+     * @private {!FolderShortcutsDataModel}
+     * @const
+     */
+    this.shortcutsModel_ = shortcutsModel;
+
+    /**
+     * @private {!DriveSyncHandler}
+     * @const
+     */
+    this.driveSyncHandler_ = driveSyncHandler;
+
+    /**
+     * @private {!ActionModelUI}
+     * @const
+     */
+    this.ui_ = ui;
+
+    /**
+     * @private {!Array<!Entry>}
+     * @const
+     */
+    this.entries_ = entries;
+
+    /**
+     * @private {!Object<!Action>}
+     */
+    this.actions_ = {};
+
+    /**
+     * @private {?function()}
+     */
+    this.initializePromiseReject_ = null;
+
+    /**
+     * @private {Promise}
+     */
+    this.initializePromise_ = null;
+
+    /**
+     * @private {boolean}
+     */
+    this.destroyed_ = false;
+  }
 
   /**
-   * @private {!MetadataModel}
-   * @const
+   * Initializes the ActionsModel, including populating the list of available
+   * actions for the given entries.
+   * @return {!Promise}
    */
-  this.metadataModel_ = metadataModel;
+  initialize() {
+    if (this.initializePromise_) {
+      return this.initializePromise_;
+    }
+
+    this.initializePromise_ =
+        new Promise((fulfill, reject) => {
+          if (this.destroyed_) {
+            reject();
+            return;
+          }
+          this.initializePromiseReject_ = reject;
+
+          const volumeInfo = this.entries_.length >= 1 &&
+              this.volumeManager_.getVolumeInfo(this.entries_[0]);
+          if (!volumeInfo) {
+            fulfill({});
+            return;
+          }
+          // All entries need to be on the same volume to execute ActionsModel
+          // commands.
+          // TODO(sashab): Move this to util.js.
+          for (let i = 1; i < this.entries_.length; i++) {
+            const volumeInfoToCompare =
+                this.volumeManager_.getVolumeInfo(this.entries_[i]);
+            if (!volumeInfoToCompare ||
+                volumeInfoToCompare.volumeId != volumeInfo.volumeId) {
+              fulfill({});
+              return;
+            }
+          }
+
+          const actions = {};
+          switch (volumeInfo.volumeType) {
+            // For Drive, actions are constructed directly in the Files app
+            // code.
+            case VolumeManagerCommon.VolumeType.DRIVE:
+              const shareAction = DriveShareAction.create(
+                  this.entries_, this.metadataModel_, this.volumeManager_,
+                  this.ui_);
+              if (shareAction) {
+                actions[ActionsModel.CommonActionId.SHARE] = shareAction;
+              }
+
+              const saveForOfflineAction = DriveToggleOfflineAction.create(
+                  this.entries_, this.metadataModel_, this.driveSyncHandler_,
+                  this.ui_, true, this.invalidate_.bind(this));
+              if (saveForOfflineAction) {
+                actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE] =
+                    saveForOfflineAction;
+              }
+
+              const offlineNotNecessaryAction = DriveToggleOfflineAction.create(
+                  this.entries_, this.metadataModel_, this.driveSyncHandler_,
+                  this.ui_, false, this.invalidate_.bind(this));
+              if (offlineNotNecessaryAction) {
+                actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY] =
+                    offlineNotNecessaryAction;
+              }
+
+              const createFolderShortcutAction =
+                  DriveCreateFolderShortcutAction.create(
+                      this.entries_, this.volumeManager_, this.shortcutsModel_,
+                      this.invalidate_.bind(this));
+              if (createFolderShortcutAction) {
+                actions[ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT] =
+                    createFolderShortcutAction;
+              }
+
+              const removeFolderShortcutAction =
+                  DriveRemoveFolderShortcutAction.create(
+                      this.entries_, this.shortcutsModel_,
+                      this.invalidate_.bind(this));
+              if (removeFolderShortcutAction) {
+                actions[ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT] =
+                    removeFolderShortcutAction;
+              }
+
+              const manageInDriveAction = DriveManageAction.create(
+                  this.entries_, this.volumeManager_, this.ui_);
+              if (manageInDriveAction) {
+                actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE] =
+                    manageInDriveAction;
+              }
+
+              fulfill(actions);
+              break;
+
+            // For FSP, fetch custom actions via an API.
+            case VolumeManagerCommon.VolumeType.PROVIDED:
+              chrome.fileManagerPrivate.getCustomActions(
+                  this.entries_, customActions => {
+                    if (chrome.runtime.lastError) {
+                      console.error(
+                          'Failed to fetch custom actions because of: ' +
+                          chrome.runtime.lastError.message);
+                    } else {
+                      customActions.forEach(action => {
+                        actions[action.id] = new CustomAction(
+                            this.entries_, action.id, action.title || null,
+                            this.invalidate_.bind(this));
+                      });
+                    }
+                    fulfill(actions);
+                  });
+              break;
+
+            default:
+              fulfill(actions);
+          }
+        }).then(actions => {
+          this.actions_ = actions;
+        });
+
+    return this.initializePromise_;
+  }
 
   /**
-   * @private {!FolderShortcutsDataModel}
-   * @const
+   * @return {!Object<!Action>}
    */
-  this.shortcutsModel_ = shortcutsModel;
+  getActions() {
+    return this.actions_;
+  }
 
   /**
-   * @private {!DriveSyncHandler}
-   * @const
+   * @param {string} id
+   * @return {Action}
    */
-  this.driveSyncHandler_ = driveSyncHandler;
+  getAction(id) {
+    return this.actions_[id] || null;
+  }
 
   /**
-   * @private {!ActionModelUI}
-   * @const
+   * Destroys the model and cancels initialization if in progress.
    */
-  this.ui_ = ui;
+  destroy() {
+    this.destroyed_ = true;
+    if (this.initializePromiseReject_ !== null) {
+      const reject = this.initializePromiseReject_;
+      this.initializePromiseReject_ = null;
+      reject();
+    }
+  }
 
   /**
-   * @private {!Array<!Entry>}
-   * @const
+   * Invalidates the current actions model by emitting an invalidation event.
+   * The model has to be initialized again, as the list of actions might have
+   * changed.
+   *
+   * @private
    */
-  this.entries_ = entries;
-
-  /**
-   * @private {!Object<!Action>}
-   */
-  this.actions_ = {};
-
-  /**
-   * @private {?function()}
-   */
-  this.initializePromiseReject_ = null;
-
-  /**
-   * @private {Promise}
-   */
-  this.initializePromise_ = null;
-
-  /**
-   * @private {boolean}
-   */
-  this.destroyed_ = false;
+  invalidate_() {
+    if (this.initializePromiseReject_ !== null) {
+      const reject = this.initializePromiseReject_;
+      this.initializePromiseReject_ = null;
+      this.initializePromise_ = null;
+      reject();
+    }
+    cr.dispatchSimpleEvent(this, 'invalidated', true);
+  }
 }
 
-ActionsModel.prototype = {
-  __proto__: cr.EventTarget.prototype
-};
-
 /**
  * List of common actions, used both internally and externally (custom actions).
  * Keep in sync with file_system_provider.idl.
@@ -689,168 +858,3 @@
   REMOVE_FOLDER_SHORTCUT: 'remove-folder-shortcut',
   MANAGE_IN_DRIVE: 'manage-in-drive'
 };
-
-/**
- * Initializes the ActionsModel, including populating the list of available
- * actions for the given entries.
- * @return {!Promise}
- */
-ActionsModel.prototype.initialize = function() {
-  if (this.initializePromise_) {
-    return this.initializePromise_;
-  }
-
-  this.initializePromise_ =
-      new Promise((fulfill, reject) => {
-        if (this.destroyed_) {
-          reject();
-          return;
-        }
-        this.initializePromiseReject_ = reject;
-
-        const volumeInfo = this.entries_.length >= 1 &&
-            this.volumeManager_.getVolumeInfo(this.entries_[0]);
-        if (!volumeInfo) {
-          fulfill({});
-          return;
-        }
-        // All entries need to be on the same volume to execute ActionsModel
-        // commands.
-        // TODO(sashab): Move this to util.js.
-        for (let i = 1; i < this.entries_.length; i++) {
-          const volumeInfoToCompare =
-              this.volumeManager_.getVolumeInfo(this.entries_[i]);
-          if (!volumeInfoToCompare ||
-              volumeInfoToCompare.volumeId != volumeInfo.volumeId) {
-            fulfill({});
-            return;
-          }
-        }
-
-        const actions = {};
-        switch (volumeInfo.volumeType) {
-          // For Drive, actions are constructed directly in the Files app code.
-          case VolumeManagerCommon.VolumeType.DRIVE:
-            const shareAction = DriveShareAction.create(
-                this.entries_, this.metadataModel_, this.volumeManager_,
-                this.ui_);
-            if (shareAction) {
-              actions[ActionsModel.CommonActionId.SHARE] = shareAction;
-            }
-
-            const saveForOfflineAction = DriveToggleOfflineAction.create(
-                this.entries_, this.metadataModel_, this.driveSyncHandler_,
-                this.ui_, true, this.invalidate_.bind(this));
-            if (saveForOfflineAction) {
-              actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE] =
-                  saveForOfflineAction;
-            }
-
-            const offlineNotNecessaryAction = DriveToggleOfflineAction.create(
-                this.entries_, this.metadataModel_, this.driveSyncHandler_,
-                this.ui_, false, this.invalidate_.bind(this));
-            if (offlineNotNecessaryAction) {
-              actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY] =
-                  offlineNotNecessaryAction;
-            }
-
-            const createFolderShortcutAction =
-                DriveCreateFolderShortcutAction.create(
-                    this.entries_, this.volumeManager_, this.shortcutsModel_,
-                    this.invalidate_.bind(this));
-            if (createFolderShortcutAction) {
-              actions[ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT] =
-                  createFolderShortcutAction;
-            }
-
-            const removeFolderShortcutAction =
-                DriveRemoveFolderShortcutAction.create(
-                    this.entries_, this.shortcutsModel_,
-                    this.invalidate_.bind(this));
-            if (removeFolderShortcutAction) {
-              actions[ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT] =
-                  removeFolderShortcutAction;
-            }
-
-            const manageInDriveAction = DriveManageAction.create(
-                this.entries_, this.volumeManager_, this.ui_);
-            if (manageInDriveAction) {
-              actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE] =
-                  manageInDriveAction;
-            }
-
-            fulfill(actions);
-            break;
-
-          // For FSP, fetch custom actions via an API.
-          case VolumeManagerCommon.VolumeType.PROVIDED:
-            chrome.fileManagerPrivate.getCustomActions(
-                this.entries_, customActions => {
-                  if (chrome.runtime.lastError) {
-                    console.error(
-                        'Failed to fetch custom actions because of: ' +
-                        chrome.runtime.lastError.message);
-                  } else {
-                    customActions.forEach(action => {
-                      actions[action.id] = new CustomAction(
-                          this.entries_, action.id, action.title || null,
-                          this.invalidate_.bind(this));
-                    });
-                  }
-                  fulfill(actions);
-                });
-            break;
-
-          default:
-            fulfill(actions);
-        }
-      }).then(actions => {
-        this.actions_ = actions;
-      });
-
-  return this.initializePromise_;
-};
-
-/**
- * @return {!Object<!Action>}
- */
-ActionsModel.prototype.getActions = function() {
-  return this.actions_;
-};
-
-/**
- * @param {string} id
- * @return {Action}
- */
-ActionsModel.prototype.getAction = function(id) {
-  return this.actions_[id] || null;
-};
-
-/**
- * Destroys the model and cancels initialization if in progress.
- */
-ActionsModel.prototype.destroy = function() {
-  this.destroyed_ = true;
-  if (this.initializePromiseReject_ !== null) {
-    const reject = this.initializePromiseReject_;
-    this.initializePromiseReject_ = null;
-    reject();
-  }
-};
-
-/**
- * Invalidates the current actions model by emitting an invalidation event.
- * The model has to be initialized again, as the list of actions might have
- * changed.
- *
- * @private
- */
-ActionsModel.prototype.invalidate_ = function() {
-  if (this.initializePromiseReject_ !== null) {
-    const reject = this.initializePromiseReject_;
-    this.initializePromiseReject_ = null;
-    this.initializePromise_ = null;
-    reject();
-  }
-  cr.dispatchSimpleEvent(this, 'invalidated', true);
-};
diff --git a/ui/file_manager/file_manager/foreground/js/file_watcher.js b/ui/file_manager/file_manager/foreground/js/file_watcher.js
index a393db2b..bd5d55f 100644
--- a/ui/file_manager/file_manager/foreground/js/file_watcher.js
+++ b/ui/file_manager/file_manager/foreground/js/file_watcher.js
@@ -2,153 +2,147 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/**
- * Watches for changes in the tracked directory.
- *
- * @extends {cr.EventTarget}
- * @constructor
- */
-function FileWatcher() {
-  this.queue_ = new AsyncUtil.Queue();
-  this.watchedDirectoryEntry_ = null;
+/** Watches for changes in the tracked directory. */
+class FileWatcher extends cr.EventTarget {
+  constructor() {
+    super();
 
-  this.onDirectoryChangedBound_ = this.onDirectoryChanged_.bind(this);
-  chrome.fileManagerPrivate.onDirectoryChanged.addListener(
-      this.onDirectoryChangedBound_);
-}
+    this.queue_ = new AsyncUtil.Queue();
+    this.watchedDirectoryEntry_ = null;
 
-/**
- * FileWatcher extends cr.EventTarget.
- */
-FileWatcher.prototype.__proto__ = cr.EventTarget.prototype;
-
-/**
- * Stops watching (must be called before page unload).
- */
-FileWatcher.prototype.dispose = function() {
-  chrome.fileManagerPrivate.onDirectoryChanged.removeListener(
-      this.onDirectoryChangedBound_);
-  if (this.watchedDirectoryEntry_) {
-    this.resetWatchedEntry_();
+    this.onDirectoryChangedBound_ = this.onDirectoryChanged_.bind(this);
+    chrome.fileManagerPrivate.onDirectoryChanged.addListener(
+        this.onDirectoryChangedBound_);
   }
-};
 
-/**
- * Called when a file in the watched directory is changed.
- * @param {chrome.fileManagerPrivate.FileWatchEvent} event Change event.
- * @private
- */
-FileWatcher.prototype.onDirectoryChanged_ = function(event) {
-  const fireWatcherDirectoryChanged = changedFiles => {
-    const e = new Event('watcher-directory-changed');
-
-    if (changedFiles) {
-      e.changedFiles = changedFiles;
-    }
-
-    this.dispatchEvent(e);
-  };
-
-  if (this.watchedDirectoryEntry_) {
-    const eventURL = event.entry.toURL();
-    const watchedDirURL = this.watchedDirectoryEntry_.toURL();
-
-    if (eventURL === watchedDirURL) {
-      fireWatcherDirectoryChanged(event.changedFiles);
-    } else if (watchedDirURL.match(new RegExp('^' + eventURL))) {
-      // When watched directory is deleted by the change in parent directory,
-      // notify it as watcher directory changed.
-      this.watchedDirectoryEntry_.getDirectory(
-          this.watchedDirectoryEntry_.fullPath, {create: false}, null, () => {
-            fireWatcherDirectoryChanged(null);
-          });
+  /**
+   * Stops watching (must be called before page unload).
+   */
+  dispose() {
+    chrome.fileManagerPrivate.onDirectoryChanged.removeListener(
+        this.onDirectoryChangedBound_);
+    if (this.watchedDirectoryEntry_) {
+      this.resetWatchedEntry_();
     }
   }
-};
 
-/**
- * Changes the watched directory. In case of a fake entry, the watch is
- * just released, since there is no reason to track a fake directory.
- *
- * @param {!DirectoryEntry|!FilesAppEntry} entry Directory entry to be tracked,
- *     or the fake entry.
- * @return {!Promise}
- */
-FileWatcher.prototype.changeWatchedDirectory = function(entry) {
-  if (!util.isFakeEntry(entry)) {
-    return this.changeWatchedEntry_(/** @type {!DirectoryEntry} */ (entry));
-  } else {
-    return this.resetWatchedEntry_();
-  }
-};
+  /**
+   * Called when a file in the watched directory is changed.
+   * @param {chrome.fileManagerPrivate.FileWatchEvent} event Change event.
+   * @private
+   */
+  onDirectoryChanged_(event) {
+    const fireWatcherDirectoryChanged = changedFiles => {
+      const e = new Event('watcher-directory-changed');
 
-/**
- * Resets the watched entry. It's a best effort method.
- * @return {!Promise}
- * @private
- */
-FileWatcher.prototype.resetWatchedEntry_ = function() {
-  // Run the tasks in the queue to avoid races.
-  return new Promise((fulfill, reject) => {
-    this.queue_.run(callback => {
-      // Release the watched directory.
-      if (this.watchedDirectoryEntry_) {
-        chrome.fileManagerPrivate.removeFileWatch(
-            this.watchedDirectoryEntry_, result => {
-              if (chrome.runtime.lastError) {
-                console.error(
-                    'Failed to remove the watcher because of: ' +
-                    chrome.runtime.lastError.message);
-              }
-              // Even on error reset the watcher locally, so at least the
-              // notifications are discarded.
-              this.watchedDirectoryEntry_ = null;
-              fulfill();
-              callback();
-            });
-      } else {
-        fulfill();
-        callback();
+      if (changedFiles) {
+        e.changedFiles = changedFiles;
       }
-    });
-  });
-};
 
-/**
- * Sets the watched entry to the passed directory. It's a best effort method.
- * @param {!DirectoryEntry} entry Directory to be watched.
- * @return {!Promise}
- * @private
- */
-FileWatcher.prototype.changeWatchedEntry_ = function(entry) {
-  return new Promise((fulfill, reject) => {
-    const setEntryClosure = () => {
-      // Run the tasks in the queue to avoid races.
-      this.queue_.run(callback => {
-        chrome.fileManagerPrivate.addFileWatch(entry, result => {
-          if (chrome.runtime.lastError) {
-            // Most probably setting the watcher is not supported on the
-            // file system type.
-            console.info('File watchers not supported for: ' + entry.toURL());
-            this.watchedDirectoryEntry_ = null;
-            fulfill();
-          } else {
-            this.watchedDirectoryEntry_ = assert(entry);
-            fulfill();
-          }
-          callback();
-        });
-      });
+      this.dispatchEvent(e);
     };
 
-    // Reset the watched directory first, then set the new watched directory.
-    return this.resetWatchedEntry_().then(setEntryClosure);
-  });
-};
+    if (this.watchedDirectoryEntry_) {
+      const eventURL = event.entry.toURL();
+      const watchedDirURL = this.watchedDirectoryEntry_.toURL();
 
-/**
- * @return {DirectoryEntry} Current watched directory entry.
- */
-FileWatcher.prototype.getWatchedDirectoryEntry = function() {
-  return this.watchedDirectoryEntry_;
-};
+      if (eventURL === watchedDirURL) {
+        fireWatcherDirectoryChanged(event.changedFiles);
+      } else if (watchedDirURL.match(new RegExp('^' + eventURL))) {
+        // When watched directory is deleted by the change in parent directory,
+        // notify it as watcher directory changed.
+        this.watchedDirectoryEntry_.getDirectory(
+            this.watchedDirectoryEntry_.fullPath, {create: false}, null, () => {
+              fireWatcherDirectoryChanged(null);
+            });
+      }
+    }
+  }
+
+  /**
+   * Changes the watched directory. In case of a fake entry, the watch is
+   * just released, since there is no reason to track a fake directory.
+   *
+   * @param {!DirectoryEntry|!FilesAppEntry} entry Directory entry to be
+   *     tracked, or the fake entry.
+   * @return {!Promise}
+   */
+  changeWatchedDirectory(entry) {
+    if (!util.isFakeEntry(entry)) {
+      return this.changeWatchedEntry_(/** @type {!DirectoryEntry} */ (entry));
+    } else {
+      return this.resetWatchedEntry_();
+    }
+  }
+
+  /**
+   * Resets the watched entry. It's a best effort method.
+   * @return {!Promise}
+   * @private
+   */
+  resetWatchedEntry_() {
+    // Run the tasks in the queue to avoid races.
+    return new Promise((fulfill, reject) => {
+      this.queue_.run(callback => {
+        // Release the watched directory.
+        if (this.watchedDirectoryEntry_) {
+          chrome.fileManagerPrivate.removeFileWatch(
+              this.watchedDirectoryEntry_, result => {
+                if (chrome.runtime.lastError) {
+                  console.error(
+                      'Failed to remove the watcher because of: ' +
+                      chrome.runtime.lastError.message);
+                }
+                // Even on error reset the watcher locally, so at least the
+                // notifications are discarded.
+                this.watchedDirectoryEntry_ = null;
+                fulfill();
+                callback();
+              });
+        } else {
+          fulfill();
+          callback();
+        }
+      });
+    });
+  }
+
+  /**
+   * Sets the watched entry to the passed directory. It's a best effort method.
+   * @param {!DirectoryEntry} entry Directory to be watched.
+   * @return {!Promise}
+   * @private
+   */
+  changeWatchedEntry_(entry) {
+    return new Promise((fulfill, reject) => {
+      const setEntryClosure = () => {
+        // Run the tasks in the queue to avoid races.
+        this.queue_.run(callback => {
+          chrome.fileManagerPrivate.addFileWatch(entry, result => {
+            if (chrome.runtime.lastError) {
+              // Most probably setting the watcher is not supported on the
+              // file system type.
+              console.info('File watchers not supported for: ' + entry.toURL());
+              this.watchedDirectoryEntry_ = null;
+              fulfill();
+            } else {
+              this.watchedDirectoryEntry_ = assert(entry);
+              fulfill();
+            }
+            callback();
+          });
+        });
+      };
+
+      // Reset the watched directory first, then set the new watched directory.
+      return this.resetWatchedEntry_().then(setEntryClosure);
+    });
+  }
+
+  /**
+   * @return {DirectoryEntry} Current watched directory entry.
+   */
+  getWatchedDirectoryEntry() {
+    return this.watchedDirectoryEntry_;
+  }
+}
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index d9bb438..d9f20a20 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -2,493 +2,492 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/**
- * @param {DialogType} dialogType
- * @param {!VolumeManager} volumeManager
- * @param {!FileManagerUI} ui
- * @param {!MetadataModel} metadataModel
- * @param {!DirectoryModel} directoryModel
- * @param {!FileSelectionHandler} selectionHandler
- * @param {!MetadataUpdateController} metadataUpdateController
- * @param {!NamingController} namingController
- * @param {!Crostini} crostini
- * @constructor
- * @struct
- */
-function TaskController(
-    dialogType, volumeManager, ui, metadataModel, directoryModel,
-    selectionHandler, metadataUpdateController, namingController, crostini) {
+class TaskController {
   /**
-   * @private {DialogType}
-   * @const
+   * @param {DialogType} dialogType
+   * @param {!VolumeManager} volumeManager
+   * @param {!FileManagerUI} ui
+   * @param {!MetadataModel} metadataModel
+   * @param {!DirectoryModel} directoryModel
+   * @param {!FileSelectionHandler} selectionHandler
+   * @param {!MetadataUpdateController} metadataUpdateController
+   * @param {!NamingController} namingController
+   * @param {!Crostini} crostini
    */
-  this.dialogType_ = dialogType;
+  constructor(
+      dialogType, volumeManager, ui, metadataModel, directoryModel,
+      selectionHandler, metadataUpdateController, namingController, crostini) {
+    /**
+     * @private {DialogType}
+     * @const
+     */
+    this.dialogType_ = dialogType;
 
-  /**
-   * @private {!VolumeManager}
-   * @const
-   */
-  this.volumeManager_ = volumeManager;
+    /**
+     * @private {!VolumeManager}
+     * @const
+     */
+    this.volumeManager_ = volumeManager;
 
-  /**
-   * @private {!FileManagerUI}
-   * @const
-   */
-  this.ui_ = ui;
+    /**
+     * @private {!FileManagerUI}
+     * @const
+     */
+    this.ui_ = ui;
 
-  /**
-   * @private {!MetadataModel}
-   * @const
-   */
-  this.metadataModel_ = metadataModel;
+    /**
+     * @private {!MetadataModel}
+     * @const
+     */
+    this.metadataModel_ = metadataModel;
 
-  /**
-   * @private {!DirectoryModel}
-   * @const
-   */
-  this.directoryModel_ = directoryModel;
+    /**
+     * @private {!DirectoryModel}
+     * @const
+     */
+    this.directoryModel_ = directoryModel;
 
-  /**
-   * @private {!FileSelectionHandler}
-   * @const
-   */
-  this.selectionHandler_ = selectionHandler;
+    /**
+     * @private {!FileSelectionHandler}
+     * @const
+     */
+    this.selectionHandler_ = selectionHandler;
 
-  /**
-   * @type {!MetadataUpdateController}
-   * @const
-   * @private
-   */
-  this.metadataUpdateController_ = metadataUpdateController;
+    /**
+     * @type {!MetadataUpdateController}
+     * @const
+     * @private
+     */
+    this.metadataUpdateController_ = metadataUpdateController;
 
-  /**
-   * @private {!NamingController}
-   * @const
-   */
-  this.namingController_ = namingController;
+    /**
+     * @private {!NamingController}
+     * @const
+     */
+    this.namingController_ = namingController;
 
-  /**
-   * @type {!Crostini}
-   * @const
-   * @private
-   */
-  this.crostini_ = crostini;
+    /**
+     * @type {!Crostini}
+     * @const
+     * @private
+     */
+    this.crostini_ = crostini;
 
-  /**
-   * @type {!TaskHistory}
-   * @const
-   * @private
-   */
-  this.taskHistory_ = new TaskHistory();
+    /**
+     * @type {!TaskHistory}
+     * @const
+     * @private
+     */
+    this.taskHistory_ = new TaskHistory();
 
-  /**
-   * @private {boolean}
-   */
-  this.canExecuteDefaultTask_ = false;
+    /**
+     * @private {boolean}
+     */
+    this.canExecuteDefaultTask_ = false;
 
-  /**
-   * @private {boolean}
-   */
-  this.canExecuteOpenActions_ = false;
+    /**
+     * @private {boolean}
+     */
+    this.canExecuteOpenActions_ = false;
 
-  /**
-   * @private {boolean}
-   */
-  this.canExecuteMoreActions_ = false;
+    /**
+     * @private {boolean}
+     */
+    this.canExecuteMoreActions_ = false;
 
-  /**
-   * @private {!cr.ui.Command}
-   * @const
-   */
-  this.defaultTaskCommand_ =
-      assertInstanceof(document.querySelector('#default-task'), cr.ui.Command);
+    /**
+     * @private {!cr.ui.Command}
+     * @const
+     */
+    this.defaultTaskCommand_ = assertInstanceof(
+        document.querySelector('#default-task'), cr.ui.Command);
 
-  /**
-   * More actions command that uses #open-with as selector due to the open-with
-   * command used previously for the same task.
-   * @private {!cr.ui.Command}
-   * @const
-   */
-  this.openWithCommand_ =
-      assertInstanceof(document.querySelector('#open-with'), cr.ui.Command);
+    /**
+     * More actions command that uses #open-with as selector due to the
+     * open-with command used previously for the same task.
+     * @private {!cr.ui.Command}
+     * @const
+     */
+    this.openWithCommand_ =
+        assertInstanceof(document.querySelector('#open-with'), cr.ui.Command);
 
-  /**
-   * More actions command that uses #open-with as selector due to the open-with
-   * command used previously for the same task.
-   * @private {!cr.ui.Command}
-   * @const
-   */
-  this.moreActionsCommand_ =
-      assertInstanceof(document.querySelector('#more-actions'), cr.ui.Command);
+    /**
+     * More actions command that uses #open-with as selector due to the
+     * open-with command used previously for the same task.
+     * @private {!cr.ui.Command}
+     * @const
+     */
+    this.moreActionsCommand_ = assertInstanceof(
+        document.querySelector('#more-actions'), cr.ui.Command);
 
-  /**
-   * Show sub menu command that uses #show-submenu as selector.
-   * @private {!cr.ui.Command}
-   * @const
-   */
-  this.showSubMenuCommand_ =
-      assertInstanceof(document.querySelector('#show-submenu'), cr.ui.Command);
+    /**
+     * Show sub menu command that uses #show-submenu as selector.
+     * @private {!cr.ui.Command}
+     * @const
+     */
+    this.showSubMenuCommand_ = assertInstanceof(
+        document.querySelector('#show-submenu'), cr.ui.Command);
 
-  /**
-   * @private {Promise<!FileTasks>}
-   */
-  this.tasks_ = null;
+    /**
+     * @private {Promise<!FileTasks>}
+     */
+    this.tasks_ = null;
 
-  /**
-   * Entries that are used to generate FileTasks returned by this.tasks_.
-   * @private {!Array<!Entry>}
-   */
-  this.tasksEntries_ = [];
+    /**
+     * Entries that are used to generate FileTasks returned by this.tasks_.
+     * @private {!Array<!Entry>}
+     */
+    this.tasksEntries_ = [];
 
-  /**
-   * Selected entries from the last time onSelectionChanged_ was called.
-   * @private {!Array<!Entry>}
-   */
-  this.lastSelectedEntries_ = [];
+    /**
+     * Selected entries from the last time onSelectionChanged_ was called.
+     * @private {!Array<!Entry>}
+     */
+    this.lastSelectedEntries_ = [];
 
-  ui.taskMenuButton.addEventListener(
-      'select', this.onTaskItemClicked_.bind(this));
-  ui.shareMenuButton.menu.addEventListener(
-      'activate', this.onTaskItemClicked_.bind(this));
-  ui.shareSubMenu.addEventListener(
-      'activate', this.onTaskItemClicked_.bind(this));
-  this.selectionHandler_.addEventListener(
-      FileSelectionHandler.EventType.CHANGE,
-      this.onSelectionChanged_.bind(this));
-  this.selectionHandler_.addEventListener(
-      FileSelectionHandler.EventType.CHANGE_THROTTLED,
-      this.updateTasks_.bind(this));
-  this.taskHistory_.addEventListener(
-      TaskHistory.EventType.UPDATE, this.updateTasks_.bind(this));
-  chrome.fileManagerPrivate.onAppsUpdated.addListener(
-      this.updateTasks_.bind(this));
-}
-
-/**
- * Task combobox handler.
- *
- * @param {Object} event Event containing task which was clicked.
- * @private
- */
-TaskController.prototype.onTaskItemClicked_ = function(event) {
-  // If the clicked target has an associated command, the click event should not
-  // be handled here since it is handled as a command.
-  if (event.target && event.target.command) {
-    return;
+    ui.taskMenuButton.addEventListener(
+        'select', this.onTaskItemClicked_.bind(this));
+    ui.shareMenuButton.menu.addEventListener(
+        'activate', this.onTaskItemClicked_.bind(this));
+    ui.shareSubMenu.addEventListener(
+        'activate', this.onTaskItemClicked_.bind(this));
+    this.selectionHandler_.addEventListener(
+        FileSelectionHandler.EventType.CHANGE,
+        this.onSelectionChanged_.bind(this));
+    this.selectionHandler_.addEventListener(
+        FileSelectionHandler.EventType.CHANGE_THROTTLED,
+        this.updateTasks_.bind(this));
+    this.taskHistory_.addEventListener(
+        TaskHistory.EventType.UPDATE, this.updateTasks_.bind(this));
+    chrome.fileManagerPrivate.onAppsUpdated.addListener(
+        this.updateTasks_.bind(this));
   }
 
-  // 'select' event from ComboButton has the item as event.item.
-  // 'activate' event from cr.ui.MenuButton has the item as event.target.data.
-  const item = event.item || event.target.data;
-  this.getFileTasks()
-      .then(tasks => {
-        switch (item.type) {
-          case FileTasks.TaskMenuButtonItemType.ShowMenu:
-            this.ui_.taskMenuButton.showMenu(false);
-            break;
-          case FileTasks.TaskMenuButtonItemType.RunTask:
-            tasks.execute(item.task);
-            break;
-          case FileTasks.TaskMenuButtonItemType.ChangeDefaultTask:
-            const selection = this.selectionHandler_.selection;
-            const extensions = [];
-
-            for (let i = 0; i < selection.entries.length; i++) {
-              const match = /\.(\w+)$/g.exec(selection.entries[i].toURL());
-              if (match) {
-                const ext = match[1].toUpperCase();
-                if (extensions.indexOf(ext) == -1) {
-                  extensions.push(ext);
-                }
-              }
-            }
-
-            let format = '';
-
-            if (extensions.length == 1) {
-              format = extensions[0];
-            }
-
-            // Change default was clicked. We should open "change default"
-            // dialog.
-            tasks.showTaskPicker(
-                this.ui_.defaultTaskPicker,
-                loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM'),
-                strf('CHANGE_DEFAULT_CAPTION', format),
-                this.changeDefaultTask_.bind(this, selection),
-                FileTasks.TaskPickerType.ChangeDefault);
-            break;
-          default:
-            assertNotReached('Unknown task.');
-        }
-      })
-      .catch(error => {
-        if (error) {
-          console.error(error.stack || error);
-        }
-      });
-};
-
-/**
- * Sets the given task as default, when this task is applicable.
- *
- * @param {!FileSelection} selection File selection.
- * @param {Object} task Task to set as default.
- * @private
- */
-TaskController.prototype.changeDefaultTask_ = function(selection, task) {
-  const entries = selection.entries;
-
-  Promise.all(entries.map((entry) => this.getMimeType_(entry)))
-      .then(mimeTypes => {
-        chrome.fileManagerPrivate.setDefaultTask(
-            task.taskId, entries, mimeTypes, util.checkAPIError);
-        this.metadataUpdateController_.refreshCurrentDirectoryMetadata();
-
-        // Update task menu button unless the task button was updated other
-        // selection.
-        if (this.selectionHandler_.selection === selection) {
-          this.tasks_ = null;
-          this.getFileTasks()
-              .then(tasks => {
-                tasks.display(
-                    this.ui_.taskMenuButton, this.ui_.shareMenuButton);
-              })
-              .catch(error => {
-                if (error) {
-                  console.error(error.stack || error);
-                }
-              });
-        }
-        this.selectionHandler_.onFileSelectionChanged();
-      });
-};
-
-/**
- * Executes default task.
- */
-TaskController.prototype.executeDefaultTask = function() {
-  this.getFileTasks()
-      .then(tasks => {
-        const task = {
-          taskId: /** @type {string} */ (
-              this.ui_.fileContextMenu.defaultTaskMenuItem.taskId),
-          title: /** @type {string} */ (
-              this.ui_.fileContextMenu.defaultTaskMenuItem.label),
-        };
-        tasks.execute(task);
-      })
-      .catch(error => {
-        if (error) {
-          console.error(error.stack || error);
-        }
-      });
-};
-
-/**
- * Get MIME type for an entry. This method first tries to obtain the MIME type
- * from metadata. If it fails, this falls back to obtain the MIME type from its
- * content or name.
- *
- * @param {!Entry} entry An entry to obtain its mime type.
- * @return {!Promise}
- * @private
- */
-TaskController.prototype.getMimeType_ = function(entry) {
-  return this.metadataModel_.get([entry], ['contentMimeType'])
-      .then(properties => {
-        if (properties[0].contentMimeType) {
-          return properties[0].contentMimeType;
-        }
-        return new Promise((fulfill, reject) => {
-          chrome.fileManagerPrivate.getMimeType(entry, mimeType => {
-            if (!chrome.runtime.lastError) {
-              fulfill(mimeType);
-            } else {
-              reject(chrome.runtime.lastError);
-            }
-          });
-        });
-      });
-};
-
-/**
- * Handles change of selection and clears context menu.
- * @private
- */
-TaskController.prototype.onSelectionChanged_ = function() {
-  const selection = this.selectionHandler_.selection;
-  // Caller of update context menu task items.
-  // FileSelectionHandler.EventType.CHANGE
-  if (this.dialogType_ === DialogType.FULL_PAGE &&
-      (selection.directoryCount > 0 || selection.fileCount > 0)) {
-    // Compare entries while ignoring changes inside directories.
-    if (!util.isSameEntries(this.lastSelectedEntries_, selection.entries)) {
-      // Update the context menu if selection changed.
-      this.updateContextMenuTaskItems_([], []);
+  /**
+   * Task combobox handler.
+   *
+   * @param {Object} event Event containing task which was clicked.
+   * @private
+   */
+  onTaskItemClicked_(event) {
+    // If the clicked target has an associated command, the click event should
+    // not be handled here since it is handled as a command.
+    if (event.target && event.target.command) {
+      return;
     }
-  } else {
-    // Update context menu.
-    this.updateContextMenuTaskItems_([], []);
-  }
-  this.lastSelectedEntries_ = selection.entries;
-};
 
-/**
- * Updates available tasks opened from context menu or the open button.
- * @private
- */
-TaskController.prototype.updateTasks_ = function() {
-  const selection = this.selectionHandler_.selection;
-  if (this.dialogType_ === DialogType.FULL_PAGE &&
-      (selection.directoryCount > 0 || selection.fileCount > 0)) {
+    // 'select' event from ComboButton has the item as event.item.
+    // 'activate' event from cr.ui.MenuButton has the item as event.target.data.
+    const item = event.item || event.target.data;
     this.getFileTasks()
         .then(tasks => {
-          tasks.display(this.ui_.taskMenuButton, this.ui_.shareMenuButton);
-          this.updateContextMenuTaskItems_(
-              tasks.getOpenTaskItems(), tasks.getNonOpenTaskItems());
+          switch (item.type) {
+            case FileTasks.TaskMenuButtonItemType.ShowMenu:
+              this.ui_.taskMenuButton.showMenu(false);
+              break;
+            case FileTasks.TaskMenuButtonItemType.RunTask:
+              tasks.execute(item.task);
+              break;
+            case FileTasks.TaskMenuButtonItemType.ChangeDefaultTask:
+              const selection = this.selectionHandler_.selection;
+              const extensions = [];
+
+              for (let i = 0; i < selection.entries.length; i++) {
+                const match = /\.(\w+)$/g.exec(selection.entries[i].toURL());
+                if (match) {
+                  const ext = match[1].toUpperCase();
+                  if (extensions.indexOf(ext) == -1) {
+                    extensions.push(ext);
+                  }
+                }
+              }
+
+              let format = '';
+
+              if (extensions.length == 1) {
+                format = extensions[0];
+              }
+
+              // Change default was clicked. We should open "change default"
+              // dialog.
+              tasks.showTaskPicker(
+                  this.ui_.defaultTaskPicker,
+                  loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM'),
+                  strf('CHANGE_DEFAULT_CAPTION', format),
+                  this.changeDefaultTask_.bind(this, selection),
+                  FileTasks.TaskPickerType.ChangeDefault);
+              break;
+            default:
+              assertNotReached('Unknown task.');
+          }
         })
         .catch(error => {
           if (error) {
             console.error(error.stack || error);
           }
         });
-  } else {
-    this.ui_.taskMenuButton.hidden = true;
-    this.ui_.shareMenuButton.hidden = true;
   }
-};
 
-/**
- * @return {!Promise<!FileTasks>}
- * @public
- */
-TaskController.prototype.getFileTasks = function() {
-  const selection = this.selectionHandler_.selection;
-  if (this.tasks_ &&
-      util.isSameEntries(this.tasksEntries_, selection.entries)) {
+  /**
+   * Sets the given task as default, when this task is applicable.
+   *
+   * @param {!FileSelection} selection File selection.
+   * @param {Object} task Task to set as default.
+   * @private
+   */
+  changeDefaultTask_(selection, task) {
+    const entries = selection.entries;
+
+    Promise.all(entries.map((entry) => this.getMimeType_(entry)))
+        .then(mimeTypes => {
+          chrome.fileManagerPrivate.setDefaultTask(
+              task.taskId, entries, mimeTypes, util.checkAPIError);
+          this.metadataUpdateController_.refreshCurrentDirectoryMetadata();
+
+          // Update task menu button unless the task button was updated other
+          // selection.
+          if (this.selectionHandler_.selection === selection) {
+            this.tasks_ = null;
+            this.getFileTasks()
+                .then(tasks => {
+                  tasks.display(
+                      this.ui_.taskMenuButton, this.ui_.shareMenuButton);
+                })
+                .catch(error => {
+                  if (error) {
+                    console.error(error.stack || error);
+                  }
+                });
+          }
+          this.selectionHandler_.onFileSelectionChanged();
+        });
+  }
+
+  /**
+   * Executes default task.
+   */
+  executeDefaultTask() {
+    this.getFileTasks()
+        .then(tasks => {
+          const task = {
+            taskId: /** @type {string} */ (
+                this.ui_.fileContextMenu.defaultTaskMenuItem.taskId),
+            title: /** @type {string} */ (
+                this.ui_.fileContextMenu.defaultTaskMenuItem.label),
+          };
+          tasks.execute(task);
+        })
+        .catch(error => {
+          if (error) {
+            console.error(error.stack || error);
+          }
+        });
+  }
+
+  /**
+   * Get MIME type for an entry. This method first tries to obtain the MIME type
+   * from metadata. If it fails, this falls back to obtain the MIME type from
+   * its content or name.
+   *
+   * @param {!Entry} entry An entry to obtain its mime type.
+   * @return {!Promise}
+   * @private
+   */
+  getMimeType_(entry) {
+    return this.metadataModel_.get([entry], ['contentMimeType'])
+        .then(properties => {
+          if (properties[0].contentMimeType) {
+            return properties[0].contentMimeType;
+          }
+          return new Promise((fulfill, reject) => {
+            chrome.fileManagerPrivate.getMimeType(entry, mimeType => {
+              if (!chrome.runtime.lastError) {
+                fulfill(mimeType);
+              } else {
+                reject(chrome.runtime.lastError);
+              }
+            });
+          });
+        });
+  }
+
+  /**
+   * Handles change of selection and clears context menu.
+   * @private
+   */
+  onSelectionChanged_() {
+    const selection = this.selectionHandler_.selection;
+    // Caller of update context menu task items.
+    // FileSelectionHandler.EventType.CHANGE
+    if (this.dialogType_ === DialogType.FULL_PAGE &&
+        (selection.directoryCount > 0 || selection.fileCount > 0)) {
+      // Compare entries while ignoring changes inside directories.
+      if (!util.isSameEntries(this.lastSelectedEntries_, selection.entries)) {
+        // Update the context menu if selection changed.
+        this.updateContextMenuTaskItems_([], []);
+      }
+    } else {
+      // Update context menu.
+      this.updateContextMenuTaskItems_([], []);
+    }
+    this.lastSelectedEntries_ = selection.entries;
+  }
+
+  /**
+   * Updates available tasks opened from context menu or the open button.
+   * @private
+   */
+  updateTasks_() {
+    const selection = this.selectionHandler_.selection;
+    if (this.dialogType_ === DialogType.FULL_PAGE &&
+        (selection.directoryCount > 0 || selection.fileCount > 0)) {
+      this.getFileTasks()
+          .then(tasks => {
+            tasks.display(this.ui_.taskMenuButton, this.ui_.shareMenuButton);
+            this.updateContextMenuTaskItems_(
+                tasks.getOpenTaskItems(), tasks.getNonOpenTaskItems());
+          })
+          .catch(error => {
+            if (error) {
+              console.error(error.stack || error);
+            }
+          });
+    } else {
+      this.ui_.taskMenuButton.hidden = true;
+      this.ui_.shareMenuButton.hidden = true;
+    }
+  }
+
+  /**
+   * @return {!Promise<!FileTasks>}
+   * @public
+   */
+  getFileTasks() {
+    const selection = this.selectionHandler_.selection;
+    if (this.tasks_ &&
+        util.isSameEntries(this.tasksEntries_, selection.entries)) {
+      return this.tasks_;
+    }
+    this.tasksEntries_ = selection.entries;
+    this.tasks_ = selection.computeAdditional(this.metadataModel_).then(() => {
+      if (this.selectionHandler_.selection !== selection) {
+        if (util.isSameEntries(this.tasksEntries_, selection.entries)) {
+          this.tasks_ = null;
+        }
+        return Promise.reject();
+      }
+      return FileTasks
+          .create(
+              this.volumeManager_, this.metadataModel_, this.directoryModel_,
+              this.ui_, selection.entries, assert(selection.mimeTypes),
+              this.taskHistory_, this.namingController_, this.crostini_)
+          .then(tasks => {
+            if (this.selectionHandler_.selection !== selection) {
+              if (util.isSameEntries(this.tasksEntries_, selection.entries)) {
+                this.tasks_ = null;
+              }
+              return Promise.reject();
+            }
+            return tasks;
+          });
+    });
     return this.tasks_;
   }
-  this.tasksEntries_ = selection.entries;
-  this.tasks_ = selection.computeAdditional(this.metadataModel_).then(() => {
-    if (this.selectionHandler_.selection !== selection) {
-      if (util.isSameEntries(this.tasksEntries_, selection.entries)) {
-        this.tasks_ = null;
-      }
-      return Promise.reject();
-    }
-    return FileTasks
-        .create(
-            this.volumeManager_, this.metadataModel_, this.directoryModel_,
-            this.ui_, selection.entries, assert(selection.mimeTypes),
-            this.taskHistory_, this.namingController_, this.crostini_)
-        .then(tasks => {
-          if (this.selectionHandler_.selection !== selection) {
-            if (util.isSameEntries(this.tasksEntries_, selection.entries)) {
-              this.tasks_ = null;
-            }
-            return Promise.reject();
-          }
-          return tasks;
-        });
-  });
-  return this.tasks_;
-};
 
-/**
- * Returns whether default task command can be executed or not.
- * @return {boolean} True if default task command is executable.
- */
-TaskController.prototype.canExecuteDefaultTask = function() {
-  return this.canExecuteDefaultTask_;
-};
-
-/**
- * Returns whether open with command can be executed or not.
- * @return {boolean} True if open with command is executable.
- */
-TaskController.prototype.canExecuteOpenActions = function() {
-  return this.canExecuteOpenActions_;
-};
-
-/**
- * Returns whether open with command can be executed or not.
- * @return {boolean} True if open with command is executable.
- */
-TaskController.prototype.canExecuteMoreActions = function() {
-  return this.canExecuteMoreActions_;
-};
-
-/**
- * Returns whether show sub-menu command can be executed or not.
- * @return {boolean} True if show-submenu command is executable.
- */
-TaskController.prototype.canExecuteShowOverflow = function() {
-  // TODO (adanilo@) extend this for general sub-menu case
-  return this.ui_.shareMenuButton.overflow.firstChild !== null;
-};
-
-/**
- * Updates tasks menu item to match passed task items.
- *
- * @param {!Array<!chrome.fileManagerPrivate.FileTask>} openTasks List of OPEN
- *     tasks.
- * @param {!Array<!chrome.fileManagerPrivate.FileTask>} nonOpenTasks List of
- *     non-OPEN tasks.
- * @private
- */
-TaskController.prototype.updateContextMenuTaskItems_ = function(
-    openTasks, nonOpenTasks) {
-  const defaultTask = FileTasks.getDefaultTask(openTasks, this.taskHistory_);
-  if (defaultTask) {
-    if (defaultTask.iconType) {
-      this.ui_.fileContextMenu.defaultTaskMenuItem.style.backgroundImage = '';
-      this.ui_.fileContextMenu.defaultTaskMenuItem.setAttribute(
-          'file-type-icon', defaultTask.iconType);
-    } else if (defaultTask.iconUrl) {
-      this.ui_.fileContextMenu.defaultTaskMenuItem.style.backgroundImage =
-          'url(' + defaultTask.iconUrl + ')';
-    } else {
-      this.ui_.fileContextMenu.defaultTaskMenuItem.style.backgroundImage = '';
-    }
-
-    if (defaultTask.taskId === FileTasks.ZIP_ARCHIVER_UNZIP_TASK_ID) {
-      this.ui_.fileContextMenu.defaultTaskMenuItem.label = str('TASK_OPEN');
-    } else {
-      this.ui_.fileContextMenu.defaultTaskMenuItem.label =
-          defaultTask.label || defaultTask.title;
-    }
-
-    this.ui_.fileContextMenu.defaultTaskMenuItem.disabled =
-        !!defaultTask.disabled;
-    this.ui_.fileContextMenu.defaultTaskMenuItem.taskId = defaultTask.taskId;
+  /**
+   * Returns whether default task command can be executed or not.
+   * @return {boolean} True if default task command is executable.
+   */
+  canExecuteDefaultTask() {
+    return this.canExecuteDefaultTask_;
   }
 
-  this.canExecuteDefaultTask_ = defaultTask != null;
-  this.defaultTaskCommand_.canExecuteChange(this.ui_.listContainer.element);
+  /**
+   * Returns whether open with command can be executed or not.
+   * @return {boolean} True if open with command is executable.
+   */
+  canExecuteOpenActions() {
+    return this.canExecuteOpenActions_;
+  }
 
-  this.canExecuteOpenActions_ = openTasks.length > 1;
-  this.openWithCommand_.canExecuteChange(this.ui_.listContainer.element);
+  /**
+   * Returns whether open with command can be executed or not.
+   * @return {boolean} True if open with command is executable.
+   */
+  canExecuteMoreActions() {
+    return this.canExecuteMoreActions_;
+  }
 
-  this.canExecuteMoreActions_ = nonOpenTasks.length >= 1;
-  this.moreActionsCommand_.canExecuteChange(this.ui_.listContainer.element);
+  /**
+   * Returns whether show sub-menu command can be executed or not.
+   * @return {boolean} True if show-submenu command is executable.
+   */
+  canExecuteShowOverflow() {
+    // TODO (adanilo@) extend this for general sub-menu case
+    return this.ui_.shareMenuButton.overflow.firstChild !== null;
+  }
 
-  this.ui_.fileContextMenu.tasksSeparator.hidden =
-      openTasks.length === 0 && nonOpenTasks.length == 0;
-};
+  /**
+   * Updates tasks menu item to match passed task items.
+   *
+   * @param {!Array<!chrome.fileManagerPrivate.FileTask>} openTasks List of OPEN
+   *     tasks.
+   * @param {!Array<!chrome.fileManagerPrivate.FileTask>} nonOpenTasks List of
+   *     non-OPEN tasks.
+   * @private
+   */
+  updateContextMenuTaskItems_(openTasks, nonOpenTasks) {
+    const defaultTask = FileTasks.getDefaultTask(openTasks, this.taskHistory_);
+    if (defaultTask) {
+      if (defaultTask.iconType) {
+        this.ui_.fileContextMenu.defaultTaskMenuItem.style.backgroundImage = '';
+        this.ui_.fileContextMenu.defaultTaskMenuItem.setAttribute(
+            'file-type-icon', defaultTask.iconType);
+      } else if (defaultTask.iconUrl) {
+        this.ui_.fileContextMenu.defaultTaskMenuItem.style.backgroundImage =
+            'url(' + defaultTask.iconUrl + ')';
+      } else {
+        this.ui_.fileContextMenu.defaultTaskMenuItem.style.backgroundImage = '';
+      }
 
-/**
- * @param {FileEntry} entry
- */
-TaskController.prototype.executeEntryTask = function(entry) {
-  this.metadataModel_.get([entry], ['contentMimeType']).then(props => {
-    FileTasks
-        .create(
-            this.volumeManager_, this.metadataModel_, this.directoryModel_,
-            this.ui_, [entry], [props[0].contentMimeType || null],
-            this.taskHistory_, this.namingController_, this.crostini_)
-        .then(tasks => {
-          tasks.executeDefault();
-        });
-  });
-};
+      if (defaultTask.taskId === FileTasks.ZIP_ARCHIVER_UNZIP_TASK_ID) {
+        this.ui_.fileContextMenu.defaultTaskMenuItem.label = str('TASK_OPEN');
+      } else {
+        this.ui_.fileContextMenu.defaultTaskMenuItem.label =
+            defaultTask.label || defaultTask.title;
+      }
+
+      this.ui_.fileContextMenu.defaultTaskMenuItem.disabled =
+          !!defaultTask.disabled;
+      this.ui_.fileContextMenu.defaultTaskMenuItem.taskId = defaultTask.taskId;
+    }
+
+    this.canExecuteDefaultTask_ = defaultTask != null;
+    this.defaultTaskCommand_.canExecuteChange(this.ui_.listContainer.element);
+
+    this.canExecuteOpenActions_ = openTasks.length > 1;
+    this.openWithCommand_.canExecuteChange(this.ui_.listContainer.element);
+
+    this.canExecuteMoreActions_ = nonOpenTasks.length >= 1;
+    this.moreActionsCommand_.canExecuteChange(this.ui_.listContainer.element);
+
+    this.ui_.fileContextMenu.tasksSeparator.hidden =
+        openTasks.length === 0 && nonOpenTasks.length == 0;
+  }
+
+  /**
+   * @param {FileEntry} entry
+   */
+  executeEntryTask(entry) {
+    this.metadataModel_.get([entry], ['contentMimeType']).then(props => {
+      FileTasks
+          .create(
+              this.volumeManager_, this.metadataModel_, this.directoryModel_,
+              this.ui_, [entry], [props[0].contentMimeType || null],
+              this.taskHistory_, this.namingController_, this.crostini_)
+          .then(tasks => {
+            tasks.executeDefault();
+          });
+    });
+  }
+}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.js b/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.js
index 4381ef2..b8572df 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.js
@@ -2,118 +2,116 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/**
- * @param {!cr.ui.Menu} menu
- * @constructor
- * @struct
- */
-function ActionsSubmenu(menu) {
-  /**
-   * @private {!cr.ui.Menu}
-   * @const
-   */
-  this.menu_ = menu;
+class ActionsSubmenu {
+  /** @param {!cr.ui.Menu} menu */
+  constructor(menu) {
+    /**
+     * @private {!cr.ui.Menu}
+     * @const
+     */
+    this.menu_ = menu;
+
+    /**
+     * @private {!cr.ui.MenuItem}
+     * @const
+     */
+    this.separator_ = /** @type {!cr.ui.MenuItem} */
+        (queryRequiredElement('#actions-separator', this.menu_));
+
+    /**
+     * @private {!Array<!cr.ui.MenuItem>}
+     */
+    this.items_ = [];
+  }
 
   /**
-   * @private {!cr.ui.MenuItem}
-   * @const
+   * @param {!Object} options
+   * @return {cr.ui.MenuItem}
+   * @private
    */
-  this.separator_ = /** @type {!cr.ui.MenuItem} */
-      (queryRequiredElement('#actions-separator', this.menu_));
+  addMenuItem_(options) {
+    const menuItem = this.menu_.addMenuItem(options);
+    menuItem.parentNode.insertBefore(menuItem, this.separator_);
+    this.items_.push(menuItem);
+    return menuItem;
+  }
 
   /**
-   * @private {!Array<!cr.ui.MenuItem>}
+   * @param {ActionsModel} actionsModel
    */
-  this.items_ = [];
+  setActionsModel(actionsModel) {
+    this.items_.forEach(item => {
+      item.parentNode.removeChild(item);
+    });
+    this.items_ = [];
+
+    const remainingActions = {};
+    if (actionsModel) {
+      const actions = actionsModel.getActions();
+      Object.keys(actions).forEach(key => {
+        remainingActions[key] = actions[key];
+      });
+    }
+
+    // First add the sharing item (if available).
+    const shareAction = remainingActions[ActionsModel.CommonActionId.SHARE];
+    if (shareAction) {
+      const menuItem = this.addMenuItem_({});
+      menuItem.command = '#share';
+      menuItem.classList.toggle('hide-on-toolbar', true);
+      delete remainingActions[ActionsModel.CommonActionId.SHARE];
+    }
+    util.queryDecoratedElement('#share', cr.ui.Command).canExecuteChange();
+
+    // Then add the Manage in Drive item (if available).
+    const manageInDriveAction =
+        remainingActions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
+    if (manageInDriveAction) {
+      const menuItem = this.addMenuItem_({});
+      menuItem.command = '#manage-in-drive';
+      menuItem.classList.toggle('hide-on-toolbar', true);
+      delete remainingActions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
+    }
+    util.queryDecoratedElement('#manage-in-drive', cr.ui.Command)
+        .canExecuteChange();
+
+    // Removing shortcuts is not rendered in the submenu to keep the previous
+    // behavior. Shortcuts can be removed in the left nav using the roots menu.
+    // TODO(mtomasz): Consider rendering the menu item here for consistency.
+    util.queryDecoratedElement('#remove-folder-shortcut', cr.ui.Command)
+        .canExecuteChange();
+
+    // Both save-for-offline and offline-not-necessary are handled by the single
+    // #toggle-pinned command.
+    const saveForOfflineAction =
+        remainingActions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE];
+    const offlineNotNecessaryAction =
+        remainingActions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY];
+    if (saveForOfflineAction || offlineNotNecessaryAction) {
+      const menuItem = this.addMenuItem_({});
+      menuItem.command = '#toggle-pinned';
+      if (saveForOfflineAction) {
+        delete remainingActions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE];
+      }
+      if (offlineNotNecessaryAction) {
+        delete remainingActions[ActionsModel.CommonActionId
+                                    .OFFLINE_NOT_NECESSARY];
+      }
+    }
+    util.queryDecoratedElement('#toggle-pinned', cr.ui.Command)
+        .canExecuteChange();
+
+    // Process all the rest as custom actions.
+    Object.keys(remainingActions).forEach(key => {
+      const action = remainingActions[key];
+      const options = {label: action.getTitle()};
+      const menuItem = this.addMenuItem_(options);
+
+      menuItem.addEventListener('activate', () => {
+        action.execute();
+      });
+    });
+
+    this.separator_.hidden = !this.items_.length;
+  }
 }
-
-/**
- * @param {!Object} options
- * @return {cr.ui.MenuItem}
- * @private
- */
-ActionsSubmenu.prototype.addMenuItem_ = function(options) {
-  const menuItem = this.menu_.addMenuItem(options);
-  menuItem.parentNode.insertBefore(menuItem, this.separator_);
-  this.items_.push(menuItem);
-  return menuItem;
-};
-
-/**
- * @param {ActionsModel} actionsModel
- */
-ActionsSubmenu.prototype.setActionsModel = function(actionsModel) {
-  this.items_.forEach(item => {
-    item.parentNode.removeChild(item);
-  });
-  this.items_ = [];
-
-  const remainingActions = {};
-  if (actionsModel) {
-    const actions = actionsModel.getActions();
-    Object.keys(actions).forEach(key => {
-      remainingActions[key] = actions[key];
-    });
-  }
-
-  // First add the sharing item (if available).
-  const shareAction = remainingActions[ActionsModel.CommonActionId.SHARE];
-  if (shareAction) {
-    const menuItem = this.addMenuItem_({});
-    menuItem.command = '#share';
-    menuItem.classList.toggle('hide-on-toolbar', true);
-    delete remainingActions[ActionsModel.CommonActionId.SHARE];
-  }
-  util.queryDecoratedElement('#share', cr.ui.Command).canExecuteChange();
-
-  // Then add the Manage in Drive item (if available).
-  const manageInDriveAction =
-      remainingActions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
-  if (manageInDriveAction) {
-    const menuItem = this.addMenuItem_({});
-    menuItem.command = '#manage-in-drive';
-    menuItem.classList.toggle('hide-on-toolbar', true);
-    delete remainingActions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
-  }
-  util.queryDecoratedElement('#manage-in-drive', cr.ui.Command)
-      .canExecuteChange();
-
-  // Removing shortcuts is not rendered in the submenu to keep the previous
-  // behavior. Shortcuts can be removed in the left nav using the roots menu.
-  // TODO(mtomasz): Consider rendering the menu item here for consistency.
-  util.queryDecoratedElement('#remove-folder-shortcut', cr.ui.Command)
-      .canExecuteChange();
-
-  // Both save-for-offline and offline-not-necessary are handled by the single
-  // #toggle-pinned command.
-  const saveForOfflineAction =
-      remainingActions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE];
-  const offlineNotNecessaryAction =
-      remainingActions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY];
-  if (saveForOfflineAction || offlineNotNecessaryAction) {
-    const menuItem = this.addMenuItem_({});
-    menuItem.command = '#toggle-pinned';
-    if (saveForOfflineAction) {
-      delete remainingActions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE];
-    }
-    if (offlineNotNecessaryAction) {
-      delete remainingActions[ActionsModel.CommonActionId
-                                  .OFFLINE_NOT_NECESSARY];
-    }
-  }
-  util.queryDecoratedElement('#toggle-pinned', cr.ui.Command)
-      .canExecuteChange();
-
-  // Process all the rest as custom actions.
-  Object.keys(remainingActions).forEach(key => {
-    const action = remainingActions[key];
-    const options = {label: action.getTitle()};
-    const menuItem = this.addMenuItem_(options);
-
-    menuItem.addEventListener('activate', () => {
-      action.execute();
-    });
-  });
-
-  this.separator_.hidden = !this.items_.length;
-};
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index a8682b6..1574eda 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -4,659 +4,666 @@
 
 /**
  * The root of the file manager's view managing the DOM of the Files app.
- *
- * @param {!ProvidersModel} providersModel Model for providers.
- * @param {!HTMLElement} element Top level element of the Files app.
- * @param {!LaunchParam} launchParam Launch param.
- * @constructor
- * @struct
  */
-function FileManagerUI(providersModel, element, launchParam) {
-  // Initialize the dialog label. This should be done before constructing dialog
-  // instances.
-  cr.ui.dialogs.BaseDialog.OK_LABEL = str('OK_LABEL');
-  cr.ui.dialogs.BaseDialog.CANCEL_LABEL = str('CANCEL_LABEL');
-
+class FileManagerUI {
   /**
-   * Top level element of the Files app.
-   * @type {!HTMLElement}
+   * @param {!ProvidersModel} providersModel Model for providers.
+   * @param {!HTMLElement} element Top level element of the Files app.
+   * @param {!LaunchParam} launchParam Launch param.
    */
-  this.element = element;
+  constructor(providersModel, element, launchParam) {
+    // Initialize the dialog label. This should be done before constructing
+    // dialog instances.
+    cr.ui.dialogs.BaseDialog.OK_LABEL = str('OK_LABEL');
+    cr.ui.dialogs.BaseDialog.CANCEL_LABEL = str('CANCEL_LABEL');
+
+    /**
+     * Top level element of the Files app.
+     * @type {!HTMLElement}
+     */
+    this.element = element;
+
+    /**
+     * Dialog type.
+     * @type {DialogType}
+     * @private
+     */
+    this.dialogType_ = launchParam.type;
+
+    /**
+     * <hr> elements in cr.ui.Menu.
+     * This is a workaround for crbug.com/689255. This member variable is just
+     * for keeping explicit reference to decorated <hr>s to prevent GC from
+     * collecting <hr> wrappers, and not used anywhere.
+     * TODO(fukino): Remove this member variable once the root cause is fixed.
+     * @private {!Array<!Element>}
+     */
+    this.separators_ = [].slice.call(document.querySelectorAll('cr-menu > hr'));
+
+    /**
+     * Error dialog.
+     * @type {!ErrorDialog}
+     * @const
+     */
+    this.errorDialog = new ErrorDialog(this.element);
+
+    /**
+     * Alert dialog.
+     * @type {!FilesAlertDialog}
+     * @const
+     */
+    this.alertDialog = new FilesAlertDialog(this.element);
+
+    /**
+     * Confirm dialog.
+     * @type {!FilesConfirmDialog}
+     * @const
+     */
+    this.confirmDialog = new FilesConfirmDialog(this.element);
+
+    /**
+     * Confirm dialog for delete.
+     * @type {!FilesConfirmDialog}
+     * @const
+     */
+    this.deleteConfirmDialog = new FilesConfirmDialog(this.element);
+    this.deleteConfirmDialog.setOkLabel(str('DELETE_BUTTON_LABEL'));
+
+    /**
+     * Confirm dialog for file move operation.
+     * @type {!FilesConfirmDialog}
+     * @const
+     */
+    this.moveConfirmDialog = new FilesConfirmDialog(this.element);
+    this.moveConfirmDialog.setOkLabel(str('CONFIRM_MOVE_BUTTON_LABEL'));
+
+    /**
+     * Confirm dialog for file copy operation.
+     * @type {!FilesConfirmDialog}
+     * @const
+     */
+    this.copyConfirmDialog = new FilesConfirmDialog(this.element);
+    this.copyConfirmDialog.setOkLabel(str('CONFIRM_COPY_BUTTON_LABEL'));
+
+    /**
+     * Multi-profile share dialog.
+     * @type {!MultiProfileShareDialog}
+     * @const
+     */
+    this.multiProfileShareDialog = new MultiProfileShareDialog(this.element);
+
+    /**
+     * Default task picker.
+     * @type {!cr.filebrowser.DefaultTaskDialog}
+     * @const
+     */
+    this.defaultTaskPicker = new cr.filebrowser.DefaultTaskDialog(this.element);
+
+    /**
+     * Suggest apps dialog.
+     * @type {!SuggestAppsDialog}
+     * @const
+     */
+    this.suggestAppsDialog = new SuggestAppsDialog(
+        providersModel, this.element, launchParam.suggestAppsDialogState);
+
+    /**
+     * Dialog for installing .deb files
+     * @type {!cr.filebrowser.InstallLinuxPackageDialog}
+     * @const
+     */
+    this.installLinuxPackageDialog =
+        new cr.filebrowser.InstallLinuxPackageDialog(this.element);
+
+    /**
+     * The container element of the dialog.
+     * @type {!HTMLElement}
+     */
+    this.dialogContainer =
+        queryRequiredElement('.dialog-container', this.element);
+
+    /**
+     * Context menu for texts.
+     * @type {!cr.ui.Menu}
+     * @const
+     */
+    this.textContextMenu =
+        util.queryDecoratedElement('#text-context-menu', cr.ui.Menu);
+
+    /**
+     * Location line.
+     * @type {LocationLine}
+     */
+    this.locationLine = null;
+
+    /**
+     * The toolbar which contains controls.
+     * @type {!HTMLElement}
+     * @const
+     */
+    this.toolbar = queryRequiredElement('.dialog-header', this.element);
+
+    /**
+     * The actionbar which contains buttons to perform actions on selected
+     * file(s).
+     * @type {!HTMLElement}
+     * @const
+     */
+    this.actionbar = queryRequiredElement('#action-bar', this.toolbar);
+
+    /**
+     * The navigation list.
+     * @type {!HTMLElement}
+     * @const
+     */
+    this.dialogNavigationList =
+        queryRequiredElement('.dialog-navigation-list', this.element);
+
+    /**
+     * Search box.
+     * @type {!SearchBox}
+     * @const
+     */
+    this.searchBox = new SearchBox(
+        queryRequiredElement('#search-box', this.element),
+        queryRequiredElement('#search-button', this.element));
+
+    /**
+     * Empty folder UI.
+     * @type {!EmptyFolder}
+     * @const
+     */
+    this.emptyFolder =
+        new EmptyFolder(queryRequiredElement('#empty-folder', this.element));
+
+    /**
+     * Toggle-view button.
+     * @type {!Element}
+     * @const
+     */
+    this.toggleViewButton = queryRequiredElement('#view-button', this.element);
+
+    /**
+     * The button to sort the file list.
+     * @type {!cr.ui.MenuButton}
+     * @const
+     */
+    this.sortButton =
+        util.queryDecoratedElement('#sort-button', cr.ui.MenuButton);
+
+    /**
+     * Ripple effect of sort button.
+     * @type {!FilesToggleRipple}
+     * @const
+     */
+    this.sortButtonToggleRipple =
+        /** @type {!FilesToggleRipple} */ (
+            queryRequiredElement('files-toggle-ripple', this.sortButton));
+
+    /**
+     * The button to open gear menu.
+     * @type {!cr.ui.MultiMenuButton}
+     * @const
+     */
+    this.gearButton =
+        util.queryDecoratedElement('#gear-button', cr.ui.MultiMenuButton);
+
+    /**
+     * Ripple effect of gear button.
+     * @type {!FilesToggleRipple}
+     * @const
+     */
+    this.gearButtonToggleRipple =
+        /** @type {!FilesToggleRipple} */ (
+            queryRequiredElement('files-toggle-ripple', this.gearButton));
+
+    /**
+     * @type {!GearMenu}
+     * @const
+     */
+    this.gearMenu = new GearMenu(this.gearButton.menu);
+
+    /**
+     * The button to open context menu in the check-select mode.
+     * @type {!cr.ui.MenuButton}
+     * @const
+     */
+    this.selectionMenuButton =
+        util.queryDecoratedElement('#selection-menu-button', cr.ui.MenuButton);
+
+    /**
+     * Directory tree.
+     * @type {DirectoryTree}
+     */
+    this.directoryTree = null;
+
+    /**
+     * Progress center panel.
+     * @type {!ProgressCenterPanel}
+     * @const
+     */
+    this.progressCenterPanel = new ProgressCenterPanel(
+        queryRequiredElement('#progress-center', this.element));
+
+    /**
+     * List container.
+     * @type {ListContainer}
+     */
+    this.listContainer = null;
+
+    /**
+     * @type {!HTMLElement}
+     */
+    this.formatPanelError =
+        queryRequiredElement('#format-panel > .error', this.element);
+
+    /**
+     * @type {!cr.ui.Menu}
+     * @const
+     */
+    this.fileContextMenu =
+        util.queryDecoratedElement('#file-context-menu', cr.ui.Menu);
+
+    /**
+     * @type {!HTMLMenuItemElement}
+     * @const
+     */
+    this.fileContextMenu.defaultTaskMenuItem =
+        /** @type {!HTMLMenuItemElement} */
+        (queryRequiredElement('#default-task-menu-item', this.fileContextMenu));
+
+    /**
+     * @const {!cr.ui.MenuItem}
+     */
+    this.fileContextMenu.tasksSeparator = /** @type {!cr.ui.MenuItem} */
+        (queryRequiredElement('#tasks-separator', this.fileContextMenu));
+
+    /**
+     * The combo button to specify the task.
+     * @type {!cr.ui.ComboButton}
+     * @const
+     */
+    this.taskMenuButton =
+        util.queryDecoratedElement('#tasks', cr.ui.ComboButton);
+    this.taskMenuButton.showMenu = function(shouldSetFocus) {
+      // Prevent the empty menu from opening.
+      if (!this.menu.length) {
+        return;
+      }
+      cr.ui.ComboButton.prototype.showMenu.call(this, shouldSetFocus);
+    };
+
+    /**
+     * The menu button for share options
+     * @type {!cr.ui.MultiMenuButton}
+     * @const
+     */
+    this.shareMenuButton =
+        util.queryDecoratedElement('#share-menu-button', cr.ui.MultiMenuButton);
+    const shareMenuButtonToggleRipple =
+        /** @type {!FilesToggleRipple} */ (
+            queryRequiredElement('files-toggle-ripple', this.shareMenuButton));
+    this.shareMenuButton.addEventListener('menushow', () => {
+      shareMenuButtonToggleRipple.activated = true;
+    });
+    this.shareMenuButton.addEventListener('menuhide', () => {
+      shareMenuButtonToggleRipple.activated = false;
+    });
+
+    /**
+     * @type {!cr.ui.Menu}
+     * @const
+     */
+    this.shareSubMenu =
+        util.queryDecoratedElement('#share-sub-menu', cr.ui.Menu);
+    this.shareMenuButton.overflow = this.shareSubMenu;
+
+    /**
+     * Banners in the file list.
+     * @type {Banners}
+     */
+    this.banners = null;
+
+    /**
+     * Dialog footer.
+     * @type {!DialogFooter}
+     */
+    this.dialogFooter = DialogFooter.findDialogFooter(
+        this.dialogType_,
+        /** @type {!Document} */ (this.element.ownerDocument));
+
+    /**
+     * @public {!ProvidersMenu}
+     * @const
+     */
+    this.providersMenu = new ProvidersMenu(
+        providersModel,
+        util.queryDecoratedElement('#add-new-services-menu', cr.ui.Menu));
+
+    /**
+     * @public {!ActionsSubmenu}
+     * @const
+     */
+    this.actionsSubmenu = new ActionsSubmenu(this.fileContextMenu);
+
+    /**
+     * @type {!FilesToast}
+     * @const
+     */
+    this.toast =
+        /** @type {!FilesToast} */ (document.querySelector('files-toast'));
+
+    /**
+     * A hidden div that can be used to announce text to screen
+     * reader/ChromeVox.
+     * @private {!HTMLElement}
+     */
+    this.a11yMessage_ = queryRequiredElement('#a11y-msg', this.element);
+
+
+    if (window.IN_TEST) {
+      /**
+       * Stores all a11y announces to be checked in tests.
+       * @public {Array<string>}
+       */
+      this.a11yAnnounces = [];
+    }
+
+    // Initialize attributes.
+    this.element.setAttribute('type', this.dialogType_);
+    if (launchParam.allowedPaths !== AllowedPaths.ANY_PATH_OR_URL) {
+      this.element.setAttribute('block-hosted-docs', '');
+    }
+
+    // Modify UI default behavior.
+    this.element.addEventListener(
+        'click', this.onExternalLinkClick_.bind(this));
+    this.element.addEventListener('drop', e => {
+      e.preventDefault();
+    });
+    if (util.runningInBrowser()) {
+      this.element.addEventListener('contextmenu', e => {
+        e.preventDefault();
+        e.stopPropagation();
+      });
+    }
+  }
 
   /**
-   * Dialog type.
-   * @type {DialogType}
+   * Initializes here elements, which are expensive or hidden in the beginning.
+   *
+   * @param {!FileTable} table
+   * @param {!FileGrid} grid
+   * @param {!LocationLine} locationLine
+   */
+  initAdditionalUI(table, grid, locationLine) {
+    // List container.
+    this.listContainer = new ListContainer(
+        queryRequiredElement('#list-container', this.element), table, grid);
+
+    // Splitter.
+    this.decorateSplitter_(
+        queryRequiredElement('#navigation-list-splitter', this.element));
+
+    // Location line.
+    this.locationLine = locationLine;
+
+    // Init context menus.
+    cr.ui.contextMenuHandler.setContextMenu(grid, this.fileContextMenu);
+    cr.ui.contextMenuHandler.setContextMenu(table.list, this.fileContextMenu);
+    cr.ui.contextMenuHandler.setContextMenu(
+        queryRequiredElement('.drive-welcome.page'), this.fileContextMenu);
+
+    // Add handlers.
+    document.defaultView.addEventListener('resize', this.relayout.bind(this));
+  }
+
+  /**
+   * Initializes the focus.
+   */
+  initUIFocus() {
+    // Set the initial focus. When there is no focus, the active element is the
+    // <body>.
+    let targetElement = null;
+    if (this.dialogType_ == DialogType.SELECT_SAVEAS_FILE) {
+      targetElement = this.dialogFooter.filenameInput;
+    } else if (
+        this.listContainer.currentListType !=
+        ListContainer.ListType.UNINITIALIZED) {
+      targetElement = this.listContainer.currentList;
+    }
+
+    if (targetElement) {
+      targetElement.focus();
+    }
+  }
+
+  /**
+   * TODO(hirono): Merge the method into initAdditionalUI.
+   * @param {!DirectoryTree} directoryTree
+   */
+  initDirectoryTree(directoryTree) {
+    this.directoryTree = directoryTree;
+
+    // Set up the context menu for the volume/shortcut items in directory tree.
+    this.directoryTree.contextMenuForRootItems =
+        util.queryDecoratedElement('#roots-context-menu', cr.ui.Menu);
+    this.directoryTree.contextMenuForSubitems =
+        util.queryDecoratedElement('#directory-tree-context-menu', cr.ui.Menu);
+
+    // Visible height of the directory tree depends on the size of progress
+    // center panel. When the size of progress center panel changes, directory
+    // tree has to be notified to adjust its components (e.g. progress bar).
+    const relayoutLimiter = new AsyncUtil.RateLimiter(
+        directoryTree.relayout.bind(directoryTree), 200);
+    const observer =
+        new MutationObserver(relayoutLimiter.run.bind(relayoutLimiter));
+    observer.observe(
+        this.progressCenterPanel.element,
+        /** @type {MutationObserverInit} */
+        ({subtree: true, attributes: true, childList: true}));
+  }
+
+  /**
+   * TODO(mtomasz): Merge the method into initAdditionalUI if possible.
+   * @param {!Banners} banners
+   */
+  initBanners(banners) {
+    this.banners = banners;
+    this.banners.addEventListener('relayout', this.relayout.bind(this));
+  }
+
+  /**
+   * Attaches files tooltip.
+   */
+  attachFilesTooltip() {
+    assertInstanceof(document.querySelector('files-tooltip'), FilesTooltip)
+        .addTargets(document.querySelectorAll('[has-tooltip]'));
+  }
+
+  /**
+   * Initialize files menu items. This method must be called after all files
+   * menu items are decorated as cr.ui.MenuItem.
+   */
+  decorateFilesMenuItems() {
+    const filesMenuItems =
+        document.querySelectorAll('cr-menu.files-menu > cr-menu-item');
+
+    for (let i = 0; i < filesMenuItems.length; i++) {
+      const filesMenuItem = filesMenuItems[i];
+      assertInstanceof(filesMenuItem, cr.ui.MenuItem);
+      cr.ui.decorate(filesMenuItem, cr.ui.FilesMenuItem);
+    }
+  }
+
+  /**
+   * Relayouts the UI.
+   */
+  relayout() {
+    this.locationLine.truncate();
+    // May not be available during initialization.
+    if (this.listContainer.currentListType !==
+        ListContainer.ListType.UNINITIALIZED) {
+      this.listContainer.currentView.relayout();
+    }
+    if (this.directoryTree) {
+      this.directoryTree.relayout();
+    }
+  }
+
+  /**
+   * Sets the current list type.
+   * @param {ListContainer.ListType} listType New list type.
+   */
+  setCurrentListType(listType) {
+    this.listContainer.setCurrentListType(listType);
+
+    const isListView = (listType === ListContainer.ListType.DETAIL);
+    this.toggleViewButton.classList.toggle('thumbnail', isListView);
+
+    const label = isListView ? str('CHANGE_TO_THUMBNAILVIEW_BUTTON_LABEL') :
+                               str('CHANGE_TO_LISTVIEW_BUTTON_LABEL');
+    this.toggleViewButton.setAttribute('aria-label', label);
+    this.relayout();
+  }
+
+  /**
+   * Overrides default handling for clicks on hyperlinks.
+   * In a packaged apps links with target='_blank' open in a new tab by
+   * default, other links do not open at all.
+   *
+   * @param {!Event} event Click event.
    * @private
    */
-  this.dialogType_ = launchParam.type;
-
-  /**
-   * <hr> elements in cr.ui.Menu.
-   * This is a workaround for crbug.com/689255. This member variable is just for
-   * keeping explicit reference to decorated <hr>s to prevent GC from collecting
-   * <hr> wrappers, and not used anywhere.
-   * TODO(fukino): Remove this member variable once the root cause is fixed.
-   * @private {!Array<!Element>}
-   */
-  this.separators_ = [].slice.call(document.querySelectorAll('cr-menu > hr'));
-
-  /**
-   * Error dialog.
-   * @type {!ErrorDialog}
-   * @const
-   */
-  this.errorDialog = new ErrorDialog(this.element);
-
-  /**
-   * Alert dialog.
-   * @type {!FilesAlertDialog}
-   * @const
-   */
-  this.alertDialog = new FilesAlertDialog(this.element);
-
-  /**
-   * Confirm dialog.
-   * @type {!FilesConfirmDialog}
-   * @const
-   */
-  this.confirmDialog = new FilesConfirmDialog(this.element);
-
-  /**
-   * Confirm dialog for delete.
-   * @type {!FilesConfirmDialog}
-   * @const
-   */
-  this.deleteConfirmDialog = new FilesConfirmDialog(this.element);
-  this.deleteConfirmDialog.setOkLabel(str('DELETE_BUTTON_LABEL'));
-
-  /**
-   * Confirm dialog for file move operation.
-   * @type {!FilesConfirmDialog}
-   * @const
-   */
-  this.moveConfirmDialog = new FilesConfirmDialog(this.element);
-  this.moveConfirmDialog.setOkLabel(str('CONFIRM_MOVE_BUTTON_LABEL'));
-
-  /**
-   * Confirm dialog for file copy operation.
-   * @type {!FilesConfirmDialog}
-   * @const
-   */
-  this.copyConfirmDialog = new FilesConfirmDialog(this.element);
-  this.copyConfirmDialog.setOkLabel(str('CONFIRM_COPY_BUTTON_LABEL'));
-
-  /**
-   * Multi-profile share dialog.
-   * @type {!MultiProfileShareDialog}
-   * @const
-   */
-  this.multiProfileShareDialog = new MultiProfileShareDialog(this.element);
-
-  /**
-   * Default task picker.
-   * @type {!cr.filebrowser.DefaultTaskDialog}
-   * @const
-   */
-  this.defaultTaskPicker = new cr.filebrowser.DefaultTaskDialog(this.element);
-
-  /**
-   * Suggest apps dialog.
-   * @type {!SuggestAppsDialog}
-   * @const
-   */
-  this.suggestAppsDialog = new SuggestAppsDialog(
-      providersModel, this.element, launchParam.suggestAppsDialogState);
-
-  /**
-   * Dialog for installing .deb files
-   * @type {!cr.filebrowser.InstallLinuxPackageDialog}
-   * @const
-   */
-  this.installLinuxPackageDialog =
-      new cr.filebrowser.InstallLinuxPackageDialog(this.element);
-
-  /**
-   * The container element of the dialog.
-   * @type {!HTMLElement}
-   */
-  this.dialogContainer =
-      queryRequiredElement('.dialog-container', this.element);
-
-  /**
-   * Context menu for texts.
-   * @type {!cr.ui.Menu}
-   * @const
-   */
-  this.textContextMenu =
-      util.queryDecoratedElement('#text-context-menu', cr.ui.Menu);
-
-  /**
-   * Location line.
-   * @type {LocationLine}
-   */
-  this.locationLine = null;
-
-  /**
-   * The toolbar which contains controls.
-   * @type {!HTMLElement}
-   * @const
-   */
-  this.toolbar = queryRequiredElement('.dialog-header', this.element);
-
-  /**
-   * The actionbar which contains buttons to perform actions on selected
-   * file(s).
-   * @type {!HTMLElement}
-   * @const
-   */
-  this.actionbar = queryRequiredElement('#action-bar', this.toolbar);
-
-  /**
-   * The navigation list.
-   * @type {!HTMLElement}
-   * @const
-   */
-  this.dialogNavigationList =
-      queryRequiredElement('.dialog-navigation-list', this.element);
-
-  /**
-   * Search box.
-   * @type {!SearchBox}
-   * @const
-   */
-  this.searchBox = new SearchBox(
-      queryRequiredElement('#search-box', this.element),
-      queryRequiredElement('#search-button', this.element));
-
-  /**
-   * Empty folder UI.
-   * @type {!EmptyFolder}
-   * @const
-   */
-  this.emptyFolder =
-      new EmptyFolder(queryRequiredElement('#empty-folder', this.element));
-
-  /**
-   * Toggle-view button.
-   * @type {!Element}
-   * @const
-   */
-  this.toggleViewButton = queryRequiredElement('#view-button', this.element);
-
-  /**
-   * The button to sort the file list.
-   * @type {!cr.ui.MenuButton}
-   * @const
-   */
-  this.sortButton =
-      util.queryDecoratedElement('#sort-button', cr.ui.MenuButton);
-
-  /**
-   * Ripple effect of sort button.
-   * @type {!FilesToggleRipple}
-   * @const
-   */
-  this.sortButtonToggleRipple =
-      /** @type {!FilesToggleRipple} */ (
-          queryRequiredElement('files-toggle-ripple', this.sortButton));
-
-  /**
-   * The button to open gear menu.
-   * @type {!cr.ui.MultiMenuButton}
-   * @const
-   */
-  this.gearButton =
-      util.queryDecoratedElement('#gear-button', cr.ui.MultiMenuButton);
-
-  /**
-   * Ripple effect of gear button.
-   * @type {!FilesToggleRipple}
-   * @const
-   */
-  this.gearButtonToggleRipple =
-      /** @type {!FilesToggleRipple} */ (
-          queryRequiredElement('files-toggle-ripple', this.gearButton));
-
-  /**
-   * @type {!GearMenu}
-   * @const
-   */
-  this.gearMenu = new GearMenu(this.gearButton.menu);
-
-  /**
-   * The button to open context menu in the check-select mode.
-   * @type {!cr.ui.MenuButton}
-   * @const
-   */
-  this.selectionMenuButton =
-      util.queryDecoratedElement('#selection-menu-button', cr.ui.MenuButton);
-
-  /**
-   * Directory tree.
-   * @type {DirectoryTree}
-   */
-  this.directoryTree = null;
-
-  /**
-   * Progress center panel.
-   * @type {!ProgressCenterPanel}
-   * @const
-   */
-  this.progressCenterPanel = new ProgressCenterPanel(
-      queryRequiredElement('#progress-center', this.element));
-
-  /**
-   * List container.
-   * @type {ListContainer}
-   */
-  this.listContainer = null;
-
-  /**
-   * @type {!HTMLElement}
-   */
-  this.formatPanelError =
-      queryRequiredElement('#format-panel > .error', this.element);
-
-  /**
-   * @type {!cr.ui.Menu}
-   * @const
-   */
-  this.fileContextMenu =
-      util.queryDecoratedElement('#file-context-menu', cr.ui.Menu);
-
-  /**
-   * @type {!HTMLMenuItemElement}
-   * @const
-   */
-  this.fileContextMenu.defaultTaskMenuItem =
-      /** @type {!HTMLMenuItemElement} */
-      (queryRequiredElement('#default-task-menu-item', this.fileContextMenu));
-
-  /**
-   * @const {!cr.ui.MenuItem}
-   */
-  this.fileContextMenu.tasksSeparator = /** @type {!cr.ui.MenuItem} */
-      (queryRequiredElement('#tasks-separator', this.fileContextMenu));
-
-  /**
-   * The combo button to specify the task.
-   * @type {!cr.ui.ComboButton}
-   * @const
-   */
-  this.taskMenuButton = util.queryDecoratedElement('#tasks', cr.ui.ComboButton);
-  this.taskMenuButton.showMenu = function(shouldSetFocus) {
-    // Prevent the empty menu from opening.
-    if (!this.menu.length) {
+  onExternalLinkClick_(event) {
+    if (event.target.tagName != 'A' || !event.target.href) {
       return;
     }
-    cr.ui.ComboButton.prototype.showMenu.call(this, shouldSetFocus);
-  };
 
-  /**
-   * The menu button for share options
-   * @type {!cr.ui.MultiMenuButton}
-   * @const
-   */
-  this.shareMenuButton =
-      util.queryDecoratedElement('#share-menu-button', cr.ui.MultiMenuButton);
-  const shareMenuButtonToggleRipple =
-      /** @type {!FilesToggleRipple} */ (
-          queryRequiredElement('files-toggle-ripple', this.shareMenuButton));
-  this.shareMenuButton.addEventListener('menushow', () => {
-    shareMenuButtonToggleRipple.activated = true;
-  });
-  this.shareMenuButton.addEventListener('menuhide', () => {
-    shareMenuButtonToggleRipple.activated = false;
-  });
-
-  /**
-   * @type {!cr.ui.Menu}
-   * @const
-   */
-  this.shareSubMenu = util.queryDecoratedElement('#share-sub-menu', cr.ui.Menu);
-  this.shareMenuButton.overflow = this.shareSubMenu;
-
-  /**
-   * Banners in the file list.
-   * @type {Banners}
-   */
-  this.banners = null;
-
-  /**
-   * Dialog footer.
-   * @type {!DialogFooter}
-   */
-  this.dialogFooter = DialogFooter.findDialogFooter(
-      this.dialogType_, /** @type {!Document} */ (this.element.ownerDocument));
-
-  /**
-   * @public {!ProvidersMenu}
-   * @const
-   */
-  this.providersMenu = new ProvidersMenu(
-      providersModel,
-      util.queryDecoratedElement('#add-new-services-menu', cr.ui.Menu));
-
-  /**
-   * @public {!ActionsSubmenu}
-   * @const
-   */
-  this.actionsSubmenu = new ActionsSubmenu(this.fileContextMenu);
-
-  /**
-   * @type {!FilesToast}
-   * @const
-   */
-  this.toast =
-      /** @type {!FilesToast} */ (document.querySelector('files-toast'));
-
-  /**
-   * A hidden div that can be used to announce text to screen reader/ChromeVox.
-   * @private {!HTMLElement}
-   */
-  this.a11yMessage_ = queryRequiredElement('#a11y-msg', this.element);
-
-
-  if (window.IN_TEST) {
-    /**
-     * Stores all a11y announces to be checked in tests.
-     * @public {Array<string>}
-     */
-    this.a11yAnnounces = [];
+    if (this.dialogType_ != DialogType.FULL_PAGE) {
+      this.dialogFooter.cancelButton.click();
+    }
   }
 
-  // Initialize attributes.
-  this.element.setAttribute('type', this.dialogType_);
-  if (launchParam.allowedPaths !== AllowedPaths.ANY_PATH_OR_URL) {
-    this.element.setAttribute('block-hosted-docs', '');
+  /**
+   * Decorates the given splitter element.
+   * @param {!HTMLElement} splitterElement
+   * @param {boolean=} opt_resizeNextElement
+   * @private
+   */
+  decorateSplitter_(splitterElement, opt_resizeNextElement) {
+    const self = this;
+    const Splitter = cr.ui.Splitter;
+    const customSplitter = cr.ui.define('div');
+
+    customSplitter.prototype = {
+      __proto__: Splitter.prototype,
+
+      handleSplitterDragStart: function(e) {
+        Splitter.prototype.handleSplitterDragStart.apply(this, arguments);
+        this.ownerDocument.documentElement.classList.add('col-resize');
+      },
+
+      handleSplitterDragMove: function(deltaX) {
+        Splitter.prototype.handleSplitterDragMove.apply(this, arguments);
+        self.relayout();
+      },
+
+      handleSplitterDragEnd: function(e) {
+        Splitter.prototype.handleSplitterDragEnd.apply(this, arguments);
+        this.ownerDocument.documentElement.classList.remove('col-resize');
+      }
+    };
+
+    /** @type Object */ (customSplitter).decorate(splitterElement);
+    splitterElement.resizeNextElement = !!opt_resizeNextElement;
   }
 
-  // Modify UI default behavior.
-  this.element.addEventListener('click', this.onExternalLinkClick_.bind(this));
-  this.element.addEventListener('drop', e => {
-    e.preventDefault();
-  });
-  if (util.runningInBrowser()) {
-    this.element.addEventListener('contextmenu', e => {
-      e.preventDefault();
-      e.stopPropagation();
+  /**
+   * Mark |element| with "loaded" attribute to indicate that File Manager has
+   * finished loading.
+   */
+  addLoadedAttribute() {
+    this.element.setAttribute('loaded', '');
+  }
+
+  /**
+   * Sets up and shows the alert to inform a user the task is opened in the
+   * desktop of the running profile.
+   *
+   * @param {Array<Entry>} entries List of opened entries.
+   */
+  showOpenInOtherDesktopAlert(entries) {
+    if (!entries.length) {
+      return;
+    }
+    chrome.fileManagerPrivate.getProfiles(
+        (profiles, currentId, displayedId) => {
+          // Find strings.
+          let displayName;
+          for (let i = 0; i < profiles.length; i++) {
+            if (profiles[i].profileId === currentId) {
+              displayName = profiles[i].displayName;
+              break;
+            }
+          }
+          if (!displayName) {
+            console.warn('Display name is not found.');
+            return;
+          }
+
+          const title = entries.length > 1 ?
+              entries[0].name + '\u2026' /* ellipsis */ :
+              entries[0].name;
+          const message = strf(
+              entries.length > 1 ? 'OPEN_IN_OTHER_DESKTOP_MESSAGE_PLURAL' :
+                                   'OPEN_IN_OTHER_DESKTOP_MESSAGE',
+              displayName, currentId);
+
+          // Show the dialog.
+          this.alertDialog.showWithTitle(title, message, null, null, null);
+        });
+  }
+
+  /**
+   * Shows confirmation dialog and handles user interaction.
+   * @param {boolean} isMove true if the operation is move. false if copy.
+   * @param {!Array<string>} messages The messages to show in the dialog.
+   *     box.
+   * @return {!Promise<boolean>}
+   */
+  showConfirmationDialog(isMove, messages) {
+    let dialog = null;
+    if (isMove) {
+      dialog = this.moveConfirmDialog;
+    } else {
+      dialog = this.copyConfirmDialog;
+    }
+    return new Promise((resolve, reject) => {
+      dialog.show(
+          messages.join(' '),
+          () => {
+            resolve(true);
+          },
+          () => {
+            resolve(false);
+          });
     });
   }
+
+  /**
+   * Send a text to screen reader/Chromevox without displaying the text in the
+   * UI.
+   * @param {string} text Text to be announced by screen reader, which should be
+   * already translated.
+   */
+  speakA11yMessage(text) {
+    // Screen reader only reads if the content changes, so clear the content
+    // first.
+    this.a11yMessage_.textContent = '';
+    this.a11yMessage_.textContent = text;
+    if (window.IN_TEST) {
+      this.a11yAnnounces.push(text);
+    }
+  }
 }
-
-/**
- * Initializes here elements, which are expensive or hidden in the beginning.
- *
- * @param {!FileTable} table
- * @param {!FileGrid} grid
- * @param {!LocationLine} locationLine
- */
-FileManagerUI.prototype.initAdditionalUI = function(table, grid, locationLine) {
-  // List container.
-  this.listContainer = new ListContainer(
-      queryRequiredElement('#list-container', this.element), table, grid);
-
-  // Splitter.
-  this.decorateSplitter_(
-      queryRequiredElement('#navigation-list-splitter', this.element));
-
-  // Location line.
-  this.locationLine = locationLine;
-
-  // Init context menus.
-  cr.ui.contextMenuHandler.setContextMenu(grid, this.fileContextMenu);
-  cr.ui.contextMenuHandler.setContextMenu(table.list, this.fileContextMenu);
-  cr.ui.contextMenuHandler.setContextMenu(
-      queryRequiredElement('.drive-welcome.page'), this.fileContextMenu);
-
-  // Add handlers.
-  document.defaultView.addEventListener('resize', this.relayout.bind(this));
-};
-
-/**
- * Initializes the focus.
- */
-FileManagerUI.prototype.initUIFocus = function() {
-  // Set the initial focus. When there is no focus, the active element is the
-  // <body>.
-  let targetElement = null;
-  if (this.dialogType_ == DialogType.SELECT_SAVEAS_FILE) {
-    targetElement = this.dialogFooter.filenameInput;
-  } else if (
-      this.listContainer.currentListType !=
-      ListContainer.ListType.UNINITIALIZED) {
-    targetElement = this.listContainer.currentList;
-  }
-
-  if (targetElement) {
-    targetElement.focus();
-  }
-};
-
-/**
- * TODO(hirono): Merge the method into initAdditionalUI.
- * @param {!DirectoryTree} directoryTree
- */
-FileManagerUI.prototype.initDirectoryTree = function(directoryTree) {
-  this.directoryTree = directoryTree;
-
-  // Set up the context menu for the volume/shortcut items in directory tree.
-  this.directoryTree.contextMenuForRootItems =
-      util.queryDecoratedElement('#roots-context-menu', cr.ui.Menu);
-  this.directoryTree.contextMenuForSubitems =
-      util.queryDecoratedElement('#directory-tree-context-menu', cr.ui.Menu);
-
-  // Visible height of the directory tree depends on the size of progress
-  // center panel. When the size of progress center panel changes, directory
-  // tree has to be notified to adjust its components (e.g. progress bar).
-  const relayoutLimiter = new AsyncUtil.RateLimiter(
-      directoryTree.relayout.bind(directoryTree), 200);
-  const observer =
-      new MutationObserver(relayoutLimiter.run.bind(relayoutLimiter));
-  observer.observe(
-      this.progressCenterPanel.element,
-      /** @type {MutationObserverInit} */
-      ({subtree: true, attributes: true, childList: true}));
-};
-
-/**
- * TODO(mtomasz): Merge the method into initAdditionalUI if possible.
- * @param {!Banners} banners
- */
-FileManagerUI.prototype.initBanners = function(banners) {
-  this.banners = banners;
-  this.banners.addEventListener('relayout', this.relayout.bind(this));
-};
-
-/**
- * Attaches files tooltip.
- */
-FileManagerUI.prototype.attachFilesTooltip = () => {
-  assertInstanceof(document.querySelector('files-tooltip'), FilesTooltip)
-      .addTargets(document.querySelectorAll('[has-tooltip]'));
-};
-
-/**
- * Initialize files menu items. This method must be called after all files menu
- * items are decorated as cr.ui.MenuItem.
- */
-FileManagerUI.prototype.decorateFilesMenuItems = () => {
-  const filesMenuItems =
-      document.querySelectorAll('cr-menu.files-menu > cr-menu-item');
-
-  for (let i = 0; i < filesMenuItems.length; i++) {
-    const filesMenuItem = filesMenuItems[i];
-    assertInstanceof(filesMenuItem, cr.ui.MenuItem);
-    cr.ui.decorate(filesMenuItem, cr.ui.FilesMenuItem);
-  }
-};
-
-/**
- * Relayouts the UI.
- */
-FileManagerUI.prototype.relayout = function() {
-  this.locationLine.truncate();
-  // May not be available during initialization.
-  if (this.listContainer.currentListType !==
-      ListContainer.ListType.UNINITIALIZED) {
-    this.listContainer.currentView.relayout();
-  }
-  if (this.directoryTree) {
-    this.directoryTree.relayout();
-  }
-};
-
-/**
- * Sets the current list type.
- * @param {ListContainer.ListType} listType New list type.
- */
-FileManagerUI.prototype.setCurrentListType = function(listType) {
-  this.listContainer.setCurrentListType(listType);
-
-  const isListView = (listType === ListContainer.ListType.DETAIL);
-  this.toggleViewButton.classList.toggle('thumbnail', isListView);
-
-  const label = isListView ? str('CHANGE_TO_THUMBNAILVIEW_BUTTON_LABEL') :
-                             str('CHANGE_TO_LISTVIEW_BUTTON_LABEL');
-  this.toggleViewButton.setAttribute('aria-label', label);
-  this.relayout();
-};
-
-/**
- * Overrides default handling for clicks on hyperlinks.
- * In a packaged apps links with targer='_blank' open in a new tab by
- * default, other links do not open at all.
- *
- * @param {!Event} event Click event.
- * @private
- */
-FileManagerUI.prototype.onExternalLinkClick_ = function(event) {
-  if (event.target.tagName != 'A' || !event.target.href) {
-    return;
-  }
-
-  if (this.dialogType_ != DialogType.FULL_PAGE) {
-    this.dialogFooter.cancelButton.click();
-  }
-};
-
-/**
- * Decorates the given splitter element.
- * @param {!HTMLElement} splitterElement
- * @param {boolean=} opt_resizeNextElement
- * @private
- */
-FileManagerUI.prototype.decorateSplitter_ = function(
-    splitterElement, opt_resizeNextElement) {
-  const self = this;
-  const Splitter = cr.ui.Splitter;
-  const customSplitter = cr.ui.define('div');
-
-  customSplitter.prototype = {
-    __proto__: Splitter.prototype,
-
-    handleSplitterDragStart: function(e) {
-      Splitter.prototype.handleSplitterDragStart.apply(this, arguments);
-      this.ownerDocument.documentElement.classList.add('col-resize');
-    },
-
-    handleSplitterDragMove: function(deltaX) {
-      Splitter.prototype.handleSplitterDragMove.apply(this, arguments);
-      self.relayout();
-    },
-
-    handleSplitterDragEnd: function(e) {
-      Splitter.prototype.handleSplitterDragEnd.apply(this, arguments);
-      this.ownerDocument.documentElement.classList.remove('col-resize');
-    }
-  };
-
-  /** @type Object */ (customSplitter).decorate(splitterElement);
-  splitterElement.resizeNextElement = !!opt_resizeNextElement;
-};
-
-/**
- * Mark |element| with "loaded" attribute to indicate that File Manager has
- * finished loading.
- */
-FileManagerUI.prototype.addLoadedAttribute = function() {
-  this.element.setAttribute('loaded', '');
-};
-
-/**
- * Sets up and shows the alert to inform a user the task is opened in the
- * desktop of the running profile.
- *
- * @param {Array<Entry>} entries List of opened entries.
- */
-FileManagerUI.prototype.showOpenInOtherDesktopAlert = function(entries) {
-  if (!entries.length) {
-    return;
-  }
-  chrome.fileManagerPrivate.getProfiles((profiles, currentId, displayedId) => {
-    // Find strings.
-    let displayName;
-    for (let i = 0; i < profiles.length; i++) {
-      if (profiles[i].profileId === currentId) {
-        displayName = profiles[i].displayName;
-        break;
-      }
-    }
-    if (!displayName) {
-      console.warn('Display name is not found.');
-      return;
-    }
-
-    const title = entries.length > 1 ?
-        entries[0].name + '\u2026' /* ellipsis */ :
-        entries[0].name;
-    const message = strf(
-        entries.length > 1 ? 'OPEN_IN_OTHER_DESKTOP_MESSAGE_PLURAL' :
-                             'OPEN_IN_OTHER_DESKTOP_MESSAGE',
-        displayName, currentId);
-
-    // Show the dialog.
-    this.alertDialog.showWithTitle(title, message, null, null, null);
-  });
-};
-
-/**
- * Shows confirmation dialog and handles user interaction.
- * @param {boolean} isMove true if the operation is move. false if copy.
- * @param {!Array<string>} messages The messages to show in the dialog.
- *     box.
- * @return {!Promise<boolean>}
- */
-FileManagerUI.prototype.showConfirmationDialog = function(isMove, messages) {
-  let dialog = null;
-  if (isMove) {
-    dialog = this.moveConfirmDialog;
-  } else {
-    dialog = this.copyConfirmDialog;
-  }
-  return new Promise((resolve, reject) => {
-    dialog.show(
-        messages.join(' '),
-        () => {
-          resolve(true);
-        },
-        () => {
-          resolve(false);
-        });
-  });
-};
-
-/**
- * Send a text to screen reader/Chromevox without displaying the text in the UI.
- * @param {string} text Text to be announced by screen reader, which should be
- * already translated.
- */
-FileManagerUI.prototype.speakA11yMessage = function(text) {
-  // Screen reader only reads if the content changes, so clear the content
-  // first.
-  this.a11yMessage_.textContent = '';
-  this.a11yMessage_.textContent = text;
-  if (window.IN_TEST) {
-    this.a11yAnnounces.push(text);
-  }
-};
diff --git a/ui/gfx/color_analysis.cc b/ui/gfx/color_analysis.cc
index 087069e..97e67683 100644
--- a/ui/gfx/color_analysis.cc
+++ b/ui/gfx/color_analysis.cc
@@ -21,6 +21,7 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/range/range.h"
 
 namespace color_utils {
@@ -139,17 +140,6 @@
 
 // Prominent color utilities ---------------------------------------------------
 
-// A color value with an associated weight.
-struct WeightedColor {
-  WeightedColor(SkColor color, uint64_t weight)
-      : color(color), weight(weight) {}
-
-  SkColor color;
-
-  // The weight correlates to a count, so it should be 1 or greater.
-  uint64_t weight;
-};
-
 // A |ColorBox| represents a 3-dimensional region in a color space (an ordered
 // set of colors). It is a range in the ordered set, with a low index and a high
 // index. The diversity (volume) of the box is computed by looking at the range
@@ -242,18 +232,18 @@
 
   // Returns the average color of this box, weighted by its popularity in
   // |color_counts|.
-  WeightedColor GetWeightedAverageColor(
+  Swatch GetWeightedAverageColor(
       const std::unordered_map<SkColor, int>& color_counts) const {
-    uint64_t sum_r = 0;
-    uint64_t sum_g = 0;
-    uint64_t sum_b = 0;
-    uint64_t total_count_in_box = 0;
+    size_t sum_r = 0;
+    size_t sum_g = 0;
+    size_t sum_b = 0;
+    size_t total_count_in_box = 0;
 
-    for (uint32_t i = color_range_.start(); i < color_range_.end(); ++i) {
+    for (size_t i = color_range_.start(); i < color_range_.end(); ++i) {
       const SkColor color = (*color_space_)[i];
       const auto color_count_iter = color_counts.find(color);
       DCHECK(color_count_iter != color_counts.end());
-      const int color_count = color_count_iter->second;
+      const size_t color_count = color_count_iter->second;
 
       total_count_in_box += color_count;
       sum_r += color_count * SkColorGetR(color);
@@ -261,7 +251,7 @@
       sum_b += color_count * SkColorGetB(color);
     }
 
-    return WeightedColor(
+    return Swatch(
         SkColorSetRGB(
             std::round(static_cast<double>(sum_r) / total_count_in_box),
             std::round(static_cast<double>(sum_g) / total_count_in_box),
@@ -347,86 +337,23 @@
   HSL goal = {-1};
 };
 
-// This algorithm is a port of Android's Palette API. Compare to package
-// android.support.v7.graphics and see that code for additional high-level
-// explanation of this algorithm. There are some minor differences:
-//   * This code doesn't exclude the same color from being used for
-//   different color profiles.
-//   * This code doesn't try to heuristically derive missing colors from
-//   existing colors.
 std::vector<SkColor> CalculateProminentColors(
     const SkBitmap& bitmap,
     const std::vector<ColorBracket>& color_brackets) {
   DCHECK(!bitmap.empty());
   DCHECK(!bitmap.isNull());
 
-  const uint32_t* pixels = static_cast<uint32_t*>(bitmap.getPixels());
-  const int pixel_count = bitmap.width() * bitmap.height();
-
-  // For better performance, only consider at most 10k pixels (evenly
-  // distributed throughout the image). This has a very minor impact on the
-  // outcome but improves runtime substantially for large images. 10,007 is a
-  // prime number to reduce the chance of picking an unrepresentative sample.
-  constexpr int kMaxConsideredPixels = 10007;
-  const int pixel_increment = std::max(1, pixel_count / kMaxConsideredPixels);
-  std::unordered_map<SkColor, int> color_counts(kMaxConsideredPixels);
-
-  // First extract all colors into counts.
-  for (int i = 0; i < pixel_count; i += pixel_increment) {
-    // SkBitmap uses pre-multiplied alpha but the prominent color algorithm
-    // needs non-pre-multiplied alpha.
-    const SkColor pixel = SkUnPreMultiply::PMColorToColor(pixels[i]);
-    if (SkColorGetA(pixel) == SK_AlphaTRANSPARENT)
-      continue;
-
-    color_counts[pixel]++;
-  }
-
-  // Now throw out some uninteresting colors.
-  std::vector<SkColor> interesting_colors;
-  interesting_colors.reserve(color_counts.size());
-  for (auto color_count : color_counts) {
-    SkColor color = color_count.first;
-    if (IsInterestingColor(color))
-      interesting_colors.push_back(color);
-  }
+  std::vector<Swatch> box_colors = CalculateColorSwatches(
+      bitmap, 12, gfx::Rect(bitmap.width(), bitmap.height()),
+      true /* exclude_uninteresting */);
 
   std::vector<SkColor> best_colors(color_brackets.size(), SK_ColorTRANSPARENT);
-  if (interesting_colors.empty())
+  if (box_colors.empty())
     return best_colors;
 
-  // Group the colors into "boxes" and repeatedly split the most voluminous box.
-  // We stop the process when a box can no longer be split (there's only one
-  // color in it) or when the number of color boxes reaches 12. As per the
-  // Android docs,
-  //
-  //   For landscapes, good values are in the range 12-16. For images which
-  //   are largely made up of people's faces then this value should be increased
-  //   to 24-32.
-  const int kMaxColors = 12;
-  // Boxes are sorted by volume with the most voluminous at the front of the PQ.
-  std::priority_queue<ColorBox, std::vector<ColorBox>,
-                      bool (*)(const ColorBox&, const ColorBox&)>
-      boxes(&ColorBox::CompareByVolume);
-  boxes.emplace(&interesting_colors);
-  while (boxes.size() < kMaxColors) {
-    auto box = boxes.top();
-    if (!box.CanSplit())
-      break;
-    boxes.pop();
-    boxes.push(box.Split());
-    boxes.push(box);
-  }
-
-  // Now extract a single color to represent each box. This is the average color
-  // in the box, weighted by the frequency of that color in the source image.
-  std::vector<WeightedColor> box_colors;
-  uint64_t max_weight = 0;
-  while (!boxes.empty()) {
-    box_colors.push_back(boxes.top().GetWeightedAverageColor(color_counts));
-    boxes.pop();
-    max_weight = std::max(max_weight, box_colors.back().weight);
-  }
+  size_t max_weight = 0;
+  for (auto& weighted : box_colors)
+    max_weight = std::max(max_weight, weighted.population);
 
   // Given these box average colors, find the best one for each desired color
   // profile. "Best" in this case means the color which fits in the provided
@@ -445,7 +372,7 @@
       double suitability =
           (1 - std::abs(hsl.s - color_brackets[i].goal.s)) * 3 +
           (1 - std::abs(hsl.l - color_brackets[i].goal.l)) * 6.5 +
-          (box_color.weight / static_cast<float>(max_weight)) * 0.5;
+          (box_color.population / static_cast<float>(max_weight)) * 0.5;
       if (suitability > best_suitability) {
         best_suitability = suitability;
         best_colors[i] = box_color.color;
@@ -733,6 +660,89 @@
       true);
 }
 
+// This algorithm is a port of Android's Palette API. Compare to package
+// android.support.v7.graphics and see that code for additional high-level
+// explanation of this algorithm. There are some minor differences:
+//   * This code doesn't exclude the same color from being used for
+//   different color profiles.
+//   * This code doesn't try to heuristically derive missing colors from
+//   existing colors.
+std::vector<Swatch> CalculateColorSwatches(const SkBitmap& bitmap,
+                                           size_t max_swatches,
+                                           const gfx::Rect& region,
+                                           bool exclude_uninteresting) {
+  DCHECK(!bitmap.empty());
+  DCHECK(!bitmap.isNull());
+  DCHECK(!region.IsEmpty());
+  DCHECK_LE(region.width(), bitmap.width());
+  DCHECK_LE(region.height(), bitmap.height());
+
+  const int pixel_count = region.width() * region.height();
+
+  // For better performance, only consider at most 10k pixels (evenly
+  // distributed throughout the image). This has a very minor impact on the
+  // outcome but improves runtime substantially for large images. 10,007 is a
+  // prime number to reduce the chance of picking an unrepresentative sample.
+  constexpr int kMaxConsideredPixels = 10007;
+  const int pixel_increment = std::max(1, pixel_count / kMaxConsideredPixels);
+  std::unordered_map<SkColor, int> color_counts(kMaxConsideredPixels);
+
+  // First extract all colors into counts.
+  for (int i = 0; i < pixel_count; i += pixel_increment) {
+    const int x = region.x() + (i % region.width());
+    const int y = region.y() + (i / region.width());
+
+    const SkColor pixel = bitmap.getColor(x, y);
+    if (SkColorGetA(pixel) == SK_AlphaTRANSPARENT)
+      continue;
+
+    color_counts[pixel]++;
+  }
+
+  // Now throw out some uninteresting colors if |exclude_uninteresting| is true.
+  std::vector<SkColor> interesting_colors;
+  interesting_colors.reserve(color_counts.size());
+  for (auto color_count : color_counts) {
+    SkColor color = color_count.first;
+    if (!exclude_uninteresting || IsInterestingColor(color))
+      interesting_colors.push_back(color);
+  }
+
+  if (interesting_colors.empty())
+    return {};
+
+  // Group the colors into "boxes" and repeatedly split the most voluminous box.
+  // We stop the process when a box can no longer be split (there's only one
+  // color in it) or when the number of color boxes reaches |max_colors|.
+  //
+  // Boxes are sorted by volume with the most voluminous at the front of the PQ.
+  std::priority_queue<ColorBox, std::vector<ColorBox>,
+                      bool (*)(const ColorBox&, const ColorBox&)>
+      boxes(&ColorBox::CompareByVolume);
+  boxes.emplace(&interesting_colors);
+  while (boxes.size() < max_swatches) {
+    auto box = boxes.top();
+    if (!box.CanSplit())
+      break;
+    boxes.pop();
+    boxes.push(box.Split());
+    boxes.push(box);
+  }
+
+  // Now extract a single color to represent each box. This is the average color
+  // in the box, weighted by the frequency of that color in the source image.
+  size_t max_weight = 0;
+  std::vector<Swatch> box_colors;
+  box_colors.reserve(max_swatches);
+  while (!boxes.empty()) {
+    box_colors.push_back(boxes.top().GetWeightedAverageColor(color_counts));
+    boxes.pop();
+    max_weight = std::max(max_weight, box_colors.back().population);
+  }
+
+  return box_colors;
+}
+
 std::vector<SkColor> CalculateProminentColorsOfBitmap(
     const SkBitmap& bitmap,
     const std::vector<ColorProfile>& color_profiles) {
diff --git a/ui/gfx/color_analysis.h b/ui/gfx/color_analysis.h
index 891d0518..746c88e7 100644
--- a/ui/gfx/color_analysis.h
+++ b/ui/gfx/color_analysis.h
@@ -16,6 +16,10 @@
 
 class SkBitmap;
 
+namespace gfx {
+class Rect;
+}  // namespace gfx
+
 namespace color_utils {
 
 struct HSL;
@@ -136,6 +140,35 @@
   SaturationRange saturation = SaturationRange::MUTED;
 };
 
+// A color value with an associated weight.
+struct Swatch {
+  Swatch(SkColor color, size_t population)
+      : color(color), population(population) {}
+
+  SkColor color;
+
+  // The population correlates to a count, so it should be 1 or greater.
+  size_t population;
+
+  bool operator==(const Swatch& other) const {
+    return color == other.color && population == other.population;
+  }
+};
+
+// Returns a vector of |Swatch| that represent the prominent colors of the
+// bitmap within |region|. The |max_swatches| is the maximum number of swatches.
+// For landscapes, good values are in the range 12-16. For images which are
+// largely made up of people's faces then this value should be increased to
+// 24-32. |exclude_uninteresting| will exclude colors that are not interesting
+// (e.g. too white or black).
+// This is an implementation of the Android Palette API:
+// https://developer.android.com/reference/android/support/v7/graphics/Palette
+GFX_EXPORT std::vector<Swatch> CalculateColorSwatches(
+    const SkBitmap& bitmap,
+    size_t max_swatches,
+    const gfx::Rect& region,
+    bool exclude_uninteresting);
+
 // Returns a vector of RGB colors that represents the bitmap based on the
 // |color_profiles| provided. For each value, if a value is succesfully
 // calculated, the calculated value is fully opaque. For failure, the calculated
diff --git a/ui/gfx/color_analysis_unittest.cc b/ui/gfx/color_analysis_unittest.cc
index 488700e..6f46d30 100644
--- a/ui/gfx/color_analysis_unittest.cc
+++ b/ui/gfx/color_analysis_unittest.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <exception>
 #include <vector>
 
 #include "skia/ext/platform_canvas.h"
@@ -546,4 +547,67 @@
   EXPECT_EQ(expectations, computations);
 }
 
+TEST_F(ColorAnalysisTest, ComputeColorSwatches) {
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(100, 100);
+  bitmap.eraseColor(SK_ColorMAGENTA);
+  bitmap.erase(SK_ColorGREEN, {10, 10, 90, 90});
+  bitmap.erase(SK_ColorYELLOW, {40, 40, 60, 60});
+
+  const Swatch kYellowSwatch = Swatch(SK_ColorYELLOW, (20u * 20u));
+  const Swatch kGreenSwatch =
+      Swatch(SK_ColorGREEN, (80u * 80u) - kYellowSwatch.population);
+  const Swatch kMagentaSwatch =
+      Swatch(SK_ColorMAGENTA, (100u * 100u) - kGreenSwatch.population -
+                                  kYellowSwatch.population);
+
+  {
+    std::vector<Swatch> colors =
+        CalculateColorSwatches(bitmap, 10, gfx::Rect(100, 100), false);
+    EXPECT_EQ(3u, colors.size());
+    EXPECT_EQ(kGreenSwatch, colors[0]);
+    EXPECT_EQ(kMagentaSwatch, colors[1]);
+    EXPECT_EQ(kYellowSwatch, colors[2]);
+  }
+
+  {
+    std::vector<Swatch> colors =
+        CalculateColorSwatches(bitmap, 10, gfx::Rect(10, 10, 80, 80), false);
+    EXPECT_EQ(2u, colors.size());
+    EXPECT_EQ(kGreenSwatch, colors[0]);
+    EXPECT_EQ(kYellowSwatch, colors[1]);
+  }
+}
+
+TEST_F(ColorAnalysisTest, ComputeColorSwatches_Uninteresting) {
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(100, 100);
+  bitmap.eraseColor(SK_ColorMAGENTA);
+  bitmap.erase(SK_ColorBLACK, {10, 10, 90, 90});
+  bitmap.erase(SK_ColorWHITE, {40, 40, 60, 60});
+
+  const Swatch kWhiteSwatch = Swatch(SK_ColorWHITE, (20u * 20u));
+  const Swatch kBlackSwatch =
+      Swatch(SK_ColorBLACK, (80u * 80u) - kWhiteSwatch.population);
+  const Swatch kMagentaSwatch =
+      Swatch(SK_ColorMAGENTA,
+             (100u * 100u) - kBlackSwatch.population - kWhiteSwatch.population);
+
+  {
+    std::vector<Swatch> colors =
+        CalculateColorSwatches(bitmap, 10, gfx::Rect(100, 100), true);
+    EXPECT_EQ(1u, colors.size());
+    EXPECT_EQ(kMagentaSwatch, colors[0]);
+  }
+
+  {
+    std::vector<Swatch> colors =
+        CalculateColorSwatches(bitmap, 10, gfx::Rect(100, 100), false);
+    EXPECT_EQ(3u, colors.size());
+    EXPECT_EQ(kBlackSwatch, colors[0]);
+    EXPECT_EQ(kMagentaSwatch, colors[1]);
+    EXPECT_EQ(kWhiteSwatch, colors[2]);
+  }
+}
+
 }  // namespace color_utils
diff --git a/ui/gfx/font_render_params_linux.cc b/ui/gfx/font_render_params_linux.cc
index b3620f4..18d44fab 100644
--- a/ui/gfx/font_render_params_linux.cc
+++ b/ui/gfx/font_render_params_linux.cc
@@ -12,7 +12,7 @@
 
 #include "base/command_line.h"
 #include "base/containers/mru_cache.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/macros.h"
diff --git a/ui/gfx/generic_shared_memory_id.h b/ui/gfx/generic_shared_memory_id.h
index 1db8acd..39c53e0 100644
--- a/ui/gfx/generic_shared_memory_id.h
+++ b/ui/gfx/generic_shared_memory_id.h
@@ -8,7 +8,9 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/hash.h"
+#include <functional>
+
+#include "base/hash/hash.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "ui/gfx/gfx_export.h"
 
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
index c8c2499..237ee97 100644
--- a/ui/gfx/render_text_harfbuzz.cc
+++ b/ui/gfx/render_text_harfbuzz.cc
@@ -10,7 +10,7 @@
 #include "base/command_line.h"
 #include "base/containers/mru_cache.h"
 #include "base/feature_list.h"
-#include "base/hash.h"
+#include "base/hash/hash.h"
 #include "base/i18n/base_i18n_switches.h"
 #include "base/i18n/break_iterator.h"
 #include "base/i18n/char_iterator.h"
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index d87ecb6..0b132a5 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -739,14 +739,22 @@
 }
 
 void KeyboardController::LoadKeyboardWindowInBackground() {
-  // ShowKeyboardInternal may trigger RootControllerWindow::ActiveKeyboard which
-  // will cause LoadKeyboardWindowInBackground to potentially run even though
-  // the keyboard has been initialized.
-  if (state_ != KeyboardControllerState::INITIAL)
-    return;
+  DCHECK_EQ(state_, KeyboardControllerState::INITIAL);
 
-  PopulateKeyboardContent(layout_delegate_->GetContainerForDefaultDisplay(),
-                          false);
+  TRACE_EVENT0("vk", "LoadKeyboardWindowInBackground");
+
+  // For now, using Unretained is safe here because the |ui_| is owned by
+  // |this| and the callback does not outlive |ui_|.
+  // TODO(https://crbug.com/845780): Use a weak ptr here in case this
+  // assumption changes.
+  DVLOG(1) << "LoadKeyboardWindow";
+  aura::Window* keyboard_window = ui_->LoadKeyboardWindow(base::BindOnce(
+      &KeyboardController::NotifyKeyboardWindowLoaded, base::Unretained(this)));
+  keyboard_window->AddPreTargetHandler(&event_filter_);
+  keyboard_window->AddObserver(this);
+  parent_container_->AddChild(keyboard_window);
+
+  ChangeState(KeyboardControllerState::LOADING_EXTENSION);
 }
 
 ui::InputMethod* KeyboardController::GetInputMethodForTest() {
@@ -872,32 +880,17 @@
 
 void KeyboardController::ShowKeyboardInternal(aura::Window* target_container) {
   MarkKeyboardLoadStarted();
-  PopulateKeyboardContent(target_container, true);
+  PopulateKeyboardContent(target_container);
   UpdateInputMethodObserver();
 }
 
-void KeyboardController::PopulateKeyboardContent(aura::Window* target_container,
-                                                 bool show_keyboard) {
-  DCHECK(show_keyboard || state_ == KeyboardControllerState::INITIAL);
+void KeyboardController::PopulateKeyboardContent(
+    aura::Window* target_container) {
+  DCHECK_NE(state_, KeyboardControllerState::INITIAL);
 
   DVLOG(1) << "PopulateKeyboardContent: " << StateToStr(state_);
   TRACE_EVENT0("vk", "PopulateKeyboardContent");
 
-  if (parent_container_->children().empty()) {
-    DCHECK_EQ(state_, KeyboardControllerState::INITIAL);
-    // For now, using Unretained is safe here because the |ui_| is owned by
-    // |this| and the callback does not outlive |ui_|.
-    // TODO(https://crbug.com/845780): Use a weak ptr here in case this
-    // assumption changes.
-    DVLOG(1) << "LoadKeyboardWindow";
-    aura::Window* keyboard_window = ui_->LoadKeyboardWindow(
-        base::BindOnce(&KeyboardController::NotifyKeyboardWindowLoaded,
-                       base::Unretained(this)));
-    keyboard_window->AddPreTargetHandler(&event_filter_);
-    keyboard_window->AddObserver(this);
-    parent_container_->AddChild(keyboard_window);
-  }
-
   MoveToParentContainer(target_container);
 
   aura::Window* keyboard_window = GetKeyboardWindow();
@@ -908,7 +901,7 @@
     case KeyboardControllerState::SHOWN:
       return;
     case KeyboardControllerState::LOADING_EXTENSION:
-      show_on_keyboard_window_load_ |= show_keyboard;
+      show_on_keyboard_window_load_ = true;
       return;
     default:
       break;
@@ -916,14 +909,9 @@
 
   ui_->ReloadKeyboardIfNeeded();
 
-  SetTouchEventLogging(!show_keyboard /* enable */);
+  SetTouchEventLogging(false /* enable */);
 
   switch (state_) {
-    case KeyboardControllerState::INITIAL:
-      DCHECK(!IsKeyboardVisible());
-      show_on_keyboard_window_load_ = show_keyboard;
-      ChangeState(KeyboardControllerState::LOADING_EXTENSION);
-      return;
     case KeyboardControllerState::WILL_HIDE:
       ChangeState(KeyboardControllerState::SHOWN);
       return;
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h
index 541ec39c..38cf908 100644
--- a/ui/keyboard/keyboard_controller.h
+++ b/ui/keyboard/keyboard_controller.h
@@ -337,8 +337,7 @@
 
   // Show virtual keyboard immediately with animation.
   void ShowKeyboardInternal(aura::Window* target_container);
-  void PopulateKeyboardContent(aura::Window* target_container,
-                               bool show_keyboard);
+  void PopulateKeyboardContent(aura::Window* target_container);
 
   // Returns true if keyboard is scheduled to hide.
   bool WillHideKeyboard() const;
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 76208d9..7981c68 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -16,78 +16,78 @@
   sources = [
     "client_native_pixmap_factory_wayland.cc",
     "client_native_pixmap_factory_wayland.h",
-    "gl_surface_wayland.cc",
-    "gl_surface_wayland.h",
+    "common/wayland_object.cc",
+    "common/wayland_object.h",
+    "common/wayland_util.cc",
+    "common/wayland_util.h",
     "gpu/drm_render_node_path_finder.cc",
     "gpu/drm_render_node_path_finder.h",
+    "gpu/gl_surface_wayland.cc",
+    "gpu/gl_surface_wayland.h",
     "gpu/wayland_canvas_surface.cc",
     "gpu/wayland_canvas_surface.h",
     "gpu/wayland_connection_proxy.cc",
     "gpu/wayland_connection_proxy.h",
+    "gpu/wayland_surface_factory.cc",
+    "gpu/wayland_surface_factory.h",
+    "host/wayland_buffer_manager.cc",
+    "host/wayland_buffer_manager.h",
+    "host/wayland_connection.cc",
+    "host/wayland_connection.h",
+    "host/wayland_connection_connector.cc",
+    "host/wayland_connection_connector.h",
+    "host/wayland_cursor.cc",
+    "host/wayland_cursor.h",
+    "host/wayland_cursor_position.cc",
+    "host/wayland_cursor_position.h",
+    "host/wayland_data_device.cc",
+    "host/wayland_data_device.h",
+    "host/wayland_data_device_manager.cc",
+    "host/wayland_data_device_manager.h",
+    "host/wayland_data_offer.cc",
+    "host/wayland_data_offer.h",
+    "host/wayland_data_source.cc",
+    "host/wayland_data_source.h",
+    "host/wayland_input_method_context.cc",
+    "host/wayland_input_method_context.h",
+    "host/wayland_input_method_context_factory.cc",
+    "host/wayland_input_method_context_factory.h",
+    "host/wayland_keyboard.cc",
+    "host/wayland_keyboard.h",
+    "host/wayland_output.cc",
+    "host/wayland_output.h",
+    "host/wayland_output_manager.cc",
+    "host/wayland_output_manager.h",
+    "host/wayland_pointer.cc",
+    "host/wayland_pointer.h",
+    "host/wayland_screen.cc",
+    "host/wayland_screen.h",
+    "host/wayland_shared_memory_buffer_manager.cc",
+    "host/wayland_shared_memory_buffer_manager.h",
+    "host/wayland_shm_buffer.cc",
+    "host/wayland_shm_buffer.h",
+    "host/wayland_touch.cc",
+    "host/wayland_touch.h",
+    "host/wayland_window.cc",
+    "host/wayland_window.h",
+    "host/wayland_zwp_linux_dmabuf.cc",
+    "host/wayland_zwp_linux_dmabuf.h",
+    "host/xdg_popup_wrapper.h",
+    "host/xdg_popup_wrapper_v5.cc",
+    "host/xdg_popup_wrapper_v5.h",
+    "host/xdg_popup_wrapper_v6.cc",
+    "host/xdg_popup_wrapper_v6.h",
+    "host/xdg_surface_wrapper.cc",
+    "host/xdg_surface_wrapper.h",
+    "host/xdg_surface_wrapper_v5.cc",
+    "host/xdg_surface_wrapper_v5.h",
+    "host/xdg_surface_wrapper_v6.cc",
+    "host/xdg_surface_wrapper_v6.h",
+    "host/zwp_text_input_wrapper.h",
+    "host/zwp_text_input_wrapper_v1.cc",
+    "host/zwp_text_input_wrapper_v1.h",
     "ozone_platform_wayland.cc",
     "ozone_platform_wayland.h",
-    "wayland_buffer_manager.cc",
-    "wayland_buffer_manager.h",
-    "wayland_connection.cc",
-    "wayland_connection.h",
-    "wayland_connection_connector.cc",
-    "wayland_connection_connector.h",
-    "wayland_cursor.cc",
-    "wayland_cursor.h",
-    "wayland_cursor_position.cc",
-    "wayland_cursor_position.h",
-    "wayland_data_device.cc",
-    "wayland_data_device.h",
-    "wayland_data_device_manager.cc",
-    "wayland_data_device_manager.h",
-    "wayland_data_offer.cc",
-    "wayland_data_offer.h",
-    "wayland_data_source.cc",
-    "wayland_data_source.h",
-    "wayland_input_method_context.cc",
-    "wayland_input_method_context.h",
-    "wayland_input_method_context_factory.cc",
-    "wayland_input_method_context_factory.h",
-    "wayland_keyboard.cc",
-    "wayland_keyboard.h",
-    "wayland_object.cc",
-    "wayland_object.h",
-    "wayland_output.cc",
-    "wayland_output.h",
-    "wayland_output_manager.cc",
-    "wayland_output_manager.h",
-    "wayland_pointer.cc",
-    "wayland_pointer.h",
-    "wayland_screen.cc",
-    "wayland_screen.h",
-    "wayland_shared_memory_buffer_manager.cc",
-    "wayland_shared_memory_buffer_manager.h",
-    "wayland_shm_buffer.cc",
-    "wayland_shm_buffer.h",
-    "wayland_surface_factory.cc",
-    "wayland_surface_factory.h",
-    "wayland_touch.cc",
-    "wayland_touch.h",
-    "wayland_util.cc",
-    "wayland_util.h",
-    "wayland_window.cc",
-    "wayland_window.h",
-    "wayland_zwp_linux_dmabuf.cc",
-    "wayland_zwp_linux_dmabuf.h",
-    "xdg_popup_wrapper.h",
-    "xdg_popup_wrapper_v5.cc",
-    "xdg_popup_wrapper_v5.h",
-    "xdg_popup_wrapper_v6.cc",
-    "xdg_popup_wrapper_v6.h",
-    "xdg_surface_wrapper.cc",
-    "xdg_surface_wrapper.h",
-    "xdg_surface_wrapper_v5.cc",
-    "xdg_surface_wrapper_v5.h",
-    "xdg_surface_wrapper_v6.cc",
-    "xdg_surface_wrapper_v6.h",
-    "zwp_text_input_wrapper.h",
-    "zwp_text_input_wrapper_v1.cc",
-    "zwp_text_input_wrapper_v1.h",
   ]
 
   import("//ui/base/ui_features.gni")
@@ -230,18 +230,18 @@
   assert(use_wayland_gbm)
 
   sources = [
-    "wayland_buffer_manager_unittest.cc",
-    "wayland_connection_unittest.cc",
-    "wayland_data_device_unittest.cc",
-    "wayland_input_method_context_unittest.cc",
-    "wayland_keyboard_unittest.cc",
-    "wayland_pointer_unittest.cc",
-    "wayland_screen_unittest.cc",
-    "wayland_surface_factory_unittest.cc",
-    "wayland_test.cc",
-    "wayland_test.h",
-    "wayland_touch_unittest.cc",
-    "wayland_window_unittest.cc",
+    "gpu/wayland_surface_factory_unittest.cc",
+    "host/wayland_buffer_manager_unittest.cc",
+    "host/wayland_connection_unittest.cc",
+    "host/wayland_data_device_unittest.cc",
+    "host/wayland_input_method_context_unittest.cc",
+    "host/wayland_keyboard_unittest.cc",
+    "host/wayland_pointer_unittest.cc",
+    "host/wayland_screen_unittest.cc",
+    "host/wayland_touch_unittest.cc",
+    "host/wayland_window_unittest.cc",
+    "test/wayland_test.cc",
+    "test/wayland_test.h",
   ]
 
   deps = [
diff --git a/ui/ozone/platform/wayland/wayland_object.cc b/ui/ozone/platform/wayland/common/wayland_object.cc
similarity index 98%
rename from ui/ozone/platform/wayland/wayland_object.cc
rename to ui/ozone/platform/wayland/common/wayland_object.cc
index 31fae0c..afb78c83 100644
--- a/ui/ozone/platform/wayland/wayland_object.cc
+++ b/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include <presentation-time-client-protocol.h>
diff --git a/ui/ozone/platform/wayland/wayland_object.h b/ui/ozone/platform/wayland/common/wayland_object.h
similarity index 96%
rename from ui/ozone/platform/wayland/wayland_object.h
rename to ui/ozone/platform/wayland/common/wayland_object.h
index cdae701b..367e1c58 100644
--- a/ui/ozone/platform/wayland/wayland_object.h
+++ b/ui/ozone/platform/wayland/common/wayland_object.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_OBJECT_H_
+#define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_OBJECT_H_
 
 #include <wayland-client-core.h>
 #include <memory>
@@ -271,4 +271,4 @@
 
 }  // namespace wl
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_OBJECT_H_
diff --git a/ui/ozone/platform/wayland/wayland_util.cc b/ui/ozone/platform/wayland/common/wayland_util.cc
similarity index 95%
rename from ui/ozone/platform/wayland/wayland_util.cc
rename to ui/ozone/platform/wayland/common/wayland_util.cc
index bd6b328..309ab08 100644
--- a/ui/ozone/platform/wayland/wayland_util.cc
+++ b/ui/ozone/platform/wayland/common/wayland_util.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 
 #include <xdg-shell-unstable-v5-client-protocol.h>
 #include <xdg-shell-unstable-v6-client-protocol.h>
 
 #include "ui/base/hit_test.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_shm_buffer.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
 
 namespace wl {
 
diff --git a/ui/ozone/platform/wayland/wayland_util.h b/ui/ozone/platform/wayland/common/wayland_util.h
similarity index 82%
rename from ui/ozone/platform/wayland/wayland_util.h
rename to ui/ozone/platform/wayland/common/wayland_util.h
index 0ed2877..a6cbdd96 100644
--- a/ui/ozone/platform/wayland/wayland_util.h
+++ b/ui/ozone/platform/wayland/common/wayland_util.h
@@ -2,27 +2,27 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_UTIL_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_UTIL_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
 
 #include <wayland-client.h>
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 class SkBitmap;
 
 namespace ui {
 class WaylandConnection;
 class WaylandShmBuffer;
-}
+}  // namespace ui
 
 namespace gfx {
 class Size;
 enum class SwapResult;
 struct PresentationFeedback;
-}
+}  // namespace gfx
 
 namespace wl {
 
@@ -47,4 +47,4 @@
 
 }  // namespace wl
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_UTIL_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
index 88f4b0ab..08086eb6 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -21,7 +21,7 @@
 #include "ui/ozone/common/linux/gbm_device.h"
 #include "ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h"
-#include "ui/ozone/platform/wayland/wayland_surface_factory.h"
+#include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h"
 #include "ui/ozone/public/overlay_plane.h"
 #include "ui/ozone/public/ozone_platform.h"
 
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 49d2938..bbc49264 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -11,7 +11,7 @@
 #include "base/trace_event/trace_event.h"
 #include "ui/gfx/gpu_fence.h"
 #include "ui/ozone/common/egl_util.h"
-#include "ui/ozone/platform/wayland/wayland_surface_factory.h"
+#include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/gl_surface_wayland.cc b/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
similarity index 94%
rename from ui/ozone/platform/wayland/gl_surface_wayland.cc
rename to ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
index 1c65f6d..22d06a8 100644
--- a/ui/ozone/platform/wayland/gl_surface_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/gl_surface_wayland.h"
+#include "ui/ozone/platform/wayland/gpu/gl_surface_wayland.h"
 
 #include <wayland-egl.h>
 #include <memory>
@@ -10,7 +10,7 @@
 
 #include "third_party/khronos/EGL/egl.h"
 #include "ui/ozone/common/egl_util.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/gl_surface_wayland.h b/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h
similarity index 85%
rename from ui/ozone/platform/wayland/gl_surface_wayland.h
rename to ui/ozone/platform/wayland/gpu/gl_surface_wayland.h
index 27b81f0e..4b9b15e 100644
--- a/ui/ozone/platform/wayland/gl_surface_wayland.h
+++ b/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_GL_SURFACE_WAYLAND_H_
-#define UI_OZONE_PLATFORM_WAYLAND_GL_SURFACE_WAYLAND_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_GPU_GL_SURFACE_WAYLAND_H_
+#define UI_OZONE_PLATFORM_WAYLAND_GPU_GL_SURFACE_WAYLAND_H_
 
 #include <memory>
 
@@ -47,4 +47,4 @@
 };
 
 }  // namespace ui
-#endif  // UI_OZONE_PLATFORM_WAYLAND_GL_SURFACE_WAYLAND_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_GPU_GL_SURFACE_WAYLAND_H_
diff --git a/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.cc b/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.cc
index 50f95f8..d9ed612 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.cc
@@ -10,7 +10,7 @@
 #include "base/process/process.h"
 #include "third_party/khronos/EGL/egl.h"
 #include "ui/ozone/common/linux/drm_util_linux.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h b/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
index 13a8d04..9ac1542 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
@@ -12,8 +12,8 @@
 #include "base/threading/thread_checker.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/public/interfaces/wayland/wayland_connection.mojom.h"
 
 #if defined(WAYLAND_GBM)
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
similarity index 95%
rename from ui/ozone/platform/wayland/wayland_surface_factory.cc
rename to ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
index f05366d..e0c80a9a 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_surface_factory.h"
+#include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h"
 
 #include <memory>
 
@@ -10,11 +10,11 @@
 #include "ui/gfx/linux/client_native_pixmap_dmabuf.h"
 #include "ui/ozone/common/egl_util.h"
 #include "ui/ozone/common/gl_ozone_egl.h"
-#include "ui/ozone/platform/wayland/gl_surface_wayland.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/gpu/gl_surface_wayland.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 #if defined(WAYLAND_GBM)
 #include "ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h"
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.h b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
similarity index 89%
rename from ui/ozone/platform/wayland/wayland_surface_factory.h
rename to ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
index e9e1afa..39116b7 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SURFACE_FACTORY_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SURFACE_FACTORY_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_SURFACE_FACTORY_H_
 
 #include <memory>
 
@@ -12,7 +12,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "ui/gl/gl_surface.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 
 namespace gfx {
@@ -67,4 +67,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SURFACE_FACTORY_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc
rename to ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index 95b3608f..2eee676 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -11,17 +11,17 @@
 #include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/common/linux/gbm_device.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h"
+#include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_surface_factory.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 #include "ui/ozone/test/mock_platform_window_delegate.h"
 
+using ::testing::_;
 using ::testing::Expectation;
 using ::testing::SaveArg;
-using ::testing::_;
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_buffer_manager.cc
rename to ui/ozone/platform/wayland/host/wayland_buffer_manager.cc
index 6867d448..80e06d8 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_buffer_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_buffer_manager.h"
 
 #include <presentation-time-client-protocol.h>
 #include <memory>
 
 #include "base/trace_event/trace_event.h"
 #include "ui/ozone/common/linux/drm_util_linux.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
-#include "ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager.h b/ui/ozone/platform/wayland/host/wayland_buffer_manager.h
similarity index 95%
rename from ui/ozone/platform/wayland/wayland_buffer_manager.h
rename to ui/ozone/platform/wayland/host/wayland_buffer_manager.h
index 95136a3..435484a0 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_BUFFER_MANAGER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_BUFFER_MANAGER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_H_
 
 #include <map>
 #include <memory>
@@ -18,8 +18,8 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/presentation_feedback.h"
 #include "ui/gfx/swap_result.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 
 struct wp_presentation_feedback;
 
@@ -179,4 +179,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_BUFFER_MANAGER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_H_
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_unittest.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_buffer_manager_unittest.cc
index 98af9ff..31e3e399 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_buffer_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_buffer_manager.h"
 
 #include <memory>
 
@@ -12,7 +12,7 @@
 #include "base/files/file_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 
 using testing::_;
 
diff --git a/ui/ozone/platform/wayland/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_connection.cc
rename to ui/ozone/platform/wayland/host/wayland_connection.cc
index 43cbbd51..0d10fa3c 100644
--- a/ui/ozone/platform/wayland/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 
 #include <xdg-shell-unstable-v5-client-protocol.h>
 #include <xdg-shell-unstable-v6-client-protocol.h>
@@ -20,13 +20,13 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 #include "ui/gfx/swap_result.h"
-#include "ui/ozone/platform/wayland/wayland_buffer_manager.h"
-#include "ui/ozone/platform/wayland/wayland_input_method_context.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/platform/wayland/wayland_output_manager.h"
-#include "ui/ozone/platform/wayland/wayland_shared_memory_buffer_manager.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
-#include "ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_buffer_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_input_method_context.h"
+#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_shared_memory_buffer_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
 
 static_assert(XDG_SHELL_VERSION_CURRENT == 5, "Unsupported xdg-shell version");
 
diff --git a/ui/ozone/platform/wayland/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
similarity index 92%
rename from ui/ozone/platform/wayland/wayland_connection.h
rename to ui/ozone/platform/wayland/host/wayland_connection.h
index 9a4a4a3..c1ec041 100644
--- a/ui/ozone/platform/wayland/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CONNECTION_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CONNECTION_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CONNECTION_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CONNECTION_H_
 
 #include <map>
 #include <memory>
@@ -16,15 +16,15 @@
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/platform/wayland/wayland_cursor_position.h"
-#include "ui/ozone/platform/wayland/wayland_data_device.h"
-#include "ui/ozone/platform/wayland/wayland_data_device_manager.h"
-#include "ui/ozone/platform/wayland/wayland_data_source.h"
-#include "ui/ozone/platform/wayland/wayland_keyboard.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/platform/wayland/wayland_output.h"
-#include "ui/ozone/platform/wayland/wayland_pointer.h"
-#include "ui/ozone/platform/wayland/wayland_touch.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_keyboard.h"
+#include "ui/ozone/platform/wayland/host/wayland_output.h"
+#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/wayland_touch.h"
 #include "ui/ozone/public/interfaces/wayland/wayland_connection.mojom.h"
 #include "ui/ozone/public/platform_clipboard.h"
 
@@ -74,7 +74,7 @@
                           ScheduleBufferSwapCallback callback) override;
   // These overridden methods below are invoked by the GPU when hardware
   // accelerated rendering is not used. Check comments in the
-  // ui/ozone/public/interfaces/wayland/wayland_connection.mojom.
+  // ui/ozone/public/interfaces/wayland/host/wayland_connection.mojom.
   void CreateShmBufferForWidget(gfx::AcceleratedWidget widget,
                                 base::File file,
                                 uint64_t length,
@@ -289,4 +289,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CONNECTION_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CONNECTION_H_
diff --git a/ui/ozone/platform/wayland/wayland_connection_connector.cc b/ui/ozone/platform/wayland/host/wayland_connection_connector.cc
similarity index 94%
rename from ui/ozone/platform/wayland/wayland_connection_connector.cc
rename to ui/ozone/platform/wayland/host/wayland_connection_connector.cc
index 4fbb271..6ad4be6 100644
--- a/ui/ozone/platform/wayland/wayland_connection_connector.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection_connector.cc
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_connection_connector.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection_connector.h"
 
 #include "base/bind.h"
 #include "base/task_runner_util.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/public/interfaces/wayland/wayland_connection.mojom.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_connection_connector.h b/ui/ozone/platform/wayland/host/wayland_connection_connector.h
similarity index 89%
rename from ui/ozone/platform/wayland/wayland_connection_connector.h
rename to ui/ozone/platform/wayland/host/wayland_connection_connector.h
index c8941ed..72c97fe8 100644
--- a/ui/ozone/platform/wayland/wayland_connection_connector.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection_connector.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CONNECTION_CONNECTOR_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CONNECTION_CONNECTOR_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CONNECTION_CONNECTOR_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CONNECTION_CONNECTOR_H_
 
 #include "ui/ozone/public/gpu_platform_support_host.h"
 
@@ -56,4 +56,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CONNECTION_CONNECTOR_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CONNECTION_CONNECTOR_H_
diff --git a/ui/ozone/platform/wayland/wayland_connection_unittest.cc b/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
similarity index 95%
rename from ui/ozone/platform/wayland/wayland_connection_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
index 9438a32e..88cf0f6 100644
--- a/ui/ozone/platform/wayland/wayland_connection_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
@@ -8,8 +8,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_cursor.cc b/ui/ozone/platform/wayland/host/wayland_cursor.cc
similarity index 92%
rename from ui/ozone/platform/wayland/wayland_cursor.cc
rename to ui/ozone/platform/wayland/host/wayland_cursor.cc
index e9dfed6..79d5834 100644
--- a/ui/ozone/platform/wayland/wayland_cursor.cc
+++ b/ui/ozone/platform/wayland/host/wayland_cursor.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_cursor.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor.h"
 
 #include <memory>
 #include <vector>
@@ -10,8 +10,8 @@
 #include "base/memory/shared_memory.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/skia_util.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_cursor.h b/ui/ozone/platform/wayland/host/wayland_cursor.h
similarity index 85%
rename from ui/ozone/platform/wayland/wayland_cursor.h
rename to ui/ozone/platform/wayland/host/wayland_cursor.h
index 7f09394..bad636c 100644
--- a/ui/ozone/platform/wayland/wayland_cursor.h
+++ b/ui/ozone/platform/wayland/host/wayland_cursor.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_H_
 
 #include <wayland-client.h>
 
@@ -14,8 +14,8 @@
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "third_party/skia/include/core/SkSurface.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/platform/wayland/wayland_shm_buffer.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
 
 class SkBitmap;
 
@@ -66,4 +66,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_H_
diff --git a/ui/ozone/platform/wayland/wayland_cursor_position.cc b/ui/ozone/platform/wayland/host/wayland_cursor_position.cc
similarity index 81%
rename from ui/ozone/platform/wayland/wayland_cursor_position.cc
rename to ui/ozone/platform/wayland/host/wayland_cursor_position.cc
index 97cb640..018c1a33 100644
--- a/ui/ozone/platform/wayland/wayland_cursor_position.cc
+++ b/ui/ozone/platform/wayland/host/wayland_cursor_position.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_cursor_position.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
 
-#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_cursor_position.h b/ui/ozone/platform/wayland/host/wayland_cursor_position.h
similarity index 80%
rename from ui/ozone/platform/wayland/wayland_cursor_position.h
rename to ui/ozone/platform/wayland/host/wayland_cursor_position.h
index 123ed9c..57a7ea40 100644
--- a/ui/ozone/platform/wayland/wayland_cursor_position.h
+++ b/ui/ozone/platform/wayland/host/wayland_cursor_position.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_POSITION_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_POSITION_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_POSITION_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_POSITION_H_
 
 #include "base/macros.h"
 #include "ui/gfx/geometry/point.h"
@@ -31,4 +31,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_POSITION_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_POSITION_H_
diff --git a/ui/ozone/platform/wayland/wayland_data_device.cc b/ui/ozone/platform/wayland/host/wayland_data_device.cc
similarity index 98%
rename from ui/ozone/platform/wayland/wayland_data_device.cc
rename to ui/ozone/platform/wayland/host/wayland_data_device.cc
index 8892c3b..a8e16cd 100644
--- a/ui/ozone/platform/wayland/wayland_data_device.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_data_device.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
 
 #include <memory>
 #include <utility>
@@ -15,9 +15,9 @@
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/dragdrop/os_exchange_data_provider_aura.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_data_device.h b/ui/ozone/platform/wayland/host/wayland_data_device.h
similarity index 94%
rename from ui/ozone/platform/wayland/wayland_data_device.h
rename to ui/ozone/platform/wayland/host/wayland_data_device.h
index 088eedc..c69be56 100644
--- a/ui/ozone/platform/wayland/wayland_data_device.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_DEVICE_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_DEVICE_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_H_
 
 #include <wayland-client.h>
 
@@ -16,9 +16,9 @@
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/ozone/platform/wayland/wayland_data_offer.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/platform/wayland/wayland_shm_buffer.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
+#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
 
 class SkBitmap;
 
@@ -187,4 +187,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_DEVICE_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_H_
diff --git a/ui/ozone/platform/wayland/wayland_data_device_manager.cc b/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
similarity index 83%
rename from ui/ozone/platform/wayland/wayland_data_device_manager.cc
rename to ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
index 25737b78..5b4a79d 100644
--- a/ui/ozone/platform/wayland/wayland_data_device_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
 
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_data_device_manager.h b/ui/ozone/platform/wayland/host/wayland_data_device_manager.h
similarity index 73%
rename from ui/ozone/platform/wayland/wayland_data_device_manager.h
rename to ui/ozone/platform/wayland/host/wayland_data_device_manager.h
index 18f5b07..ea37eee 100644
--- a/ui/ozone/platform/wayland/wayland_data_device_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_device_manager.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_DEVICE_MANAGER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_DEVICE_MANAGER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_
 
 #include <wayland-client.h>
 
 #include <memory>
 
 #include "base/macros.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 namespace ui {
 
@@ -36,4 +36,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_DEVICE_MANAGER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_DEVICE_MANAGER_H_
diff --git a/ui/ozone/platform/wayland/wayland_data_device_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
similarity index 99%
rename from ui/ozone/platform/wayland/wayland_data_device_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
index 50c4d7e..406ca31 100644
--- a/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
@@ -18,7 +18,7 @@
 #include "ui/ozone/platform/wayland/test/test_data_offer.h"
 #include "ui/ozone/platform/wayland/test/test_data_source.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 #include "ui/ozone/public/platform_clipboard.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/wayland/wayland_data_offer.cc b/ui/ozone/platform/wayland/host/wayland_data_offer.cc
similarity index 98%
rename from ui/ozone/platform/wayland/wayland_data_offer.cc
rename to ui/ozone/platform/wayland/host/wayland_data_offer.cc
index 1a7d06b..7fc0156 100644
--- a/ui/ozone/platform/wayland/wayland_data_offer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_offer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_data_offer.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
 
 #include <fcntl.h>
 #include <algorithm>
diff --git a/ui/ozone/platform/wayland/wayland_data_offer.h b/ui/ozone/platform/wayland/host/wayland_data_offer.h
similarity index 91%
rename from ui/ozone/platform/wayland/wayland_data_offer.h
rename to ui/ozone/platform/wayland/host/wayland_data_offer.h
index a2e8170..ec7abc9 100644
--- a/ui/ozone/platform/wayland/wayland_data_offer.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_offer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_OFFER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_OFFER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_OFFER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_OFFER_H_
 
 #include <wayland-client.h>
 
@@ -12,7 +12,7 @@
 
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 namespace ui {
 
@@ -78,4 +78,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_OFFER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_OFFER_H_
diff --git a/ui/ozone/platform/wayland/wayland_data_source.cc b/ui/ozone/platform/wayland/host/wayland_data_source.cc
similarity index 96%
rename from ui/ozone/platform/wayland/wayland_data_source.cc
rename to ui/ozone/platform/wayland/host/wayland_data_source.cc
index 1acf9b9..592b51f 100644
--- a/ui/ozone/platform/wayland/wayland_data_source.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_source.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
 
 #include "base/files/file_util.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_data_source.h b/ui/ozone/platform/wayland/host/wayland_data_source.h
similarity index 90%
rename from ui/ozone/platform/wayland/wayland_data_source.h
rename to ui/ozone/platform/wayland/host/wayland_data_source.h
index 34fb885b..5cddfb7 100644
--- a/ui/ozone/platform/wayland/wayland_data_source.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_source.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_SOURCE_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_SOURCE_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
 
 #include <wayland-client.h>
 
@@ -14,7 +14,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/optional.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 #include "ui/ozone/public/platform_clipboard.h"
 
 namespace ui {
@@ -81,4 +81,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DATA_SOURCE_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_DATA_SOURCE_H_
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context.cc b/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
similarity index 96%
rename from ui/ozone/platform/wayland/wayland_input_method_context.cc
rename to ui/ozone/platform/wayland/host/wayland_input_method_context.cc
index fadb28c..700232b 100644
--- a/ui/ozone/platform/wayland/wayland_input_method_context.cc
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_input_method_context.h"
+#include "ui/ozone/platform/wayland/host/wayland_input_method_context.h"
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -20,8 +20,8 @@
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 #include "ui/gfx/range/range.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h"
 #include "ui/ozone/public/ozone_switches.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context.h b/ui/ozone/platform/wayland/host/wayland_input_method_context.h
similarity index 88%
rename from ui/ozone/platform/wayland/wayland_input_method_context.h
rename to ui/ozone/platform/wayland/host/wayland_input_method_context.h
index bee874c..30268e2 100644
--- a/ui/ozone/platform/wayland/wayland_input_method_context.h
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_H_
 
 #include <memory>
 #include <string>
@@ -12,7 +12,7 @@
 #include "ui/base/ime/character_composer.h"
 #include "ui/base/ime/linux/linux_input_method_context.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
-#include "ui/ozone/platform/wayland/zwp_text_input_wrapper.h"
+#include "ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h"
 
 namespace ui {
 
@@ -66,4 +66,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_H_
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc b/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.cc
similarity index 84%
rename from ui/ozone/platform/wayland/wayland_input_method_context_factory.cc
rename to ui/ozone/platform/wayland/host/wayland_input_method_context_factory.cc
index 7537f27e..e931236 100644
--- a/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h"
+#include "ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h"
 
 #include <memory>
 
 #include "base/bind.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_input_method_context.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_input_method_context.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_factory.h b/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h
similarity index 81%
rename from ui/ozone/platform/wayland/wayland_input_method_context_factory.h
rename to ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h
index 23bd695..303dc8e 100644
--- a/ui/ozone/platform/wayland/wayland_input_method_context_factory.h
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
 
 #include <memory>
 
@@ -37,4 +37,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc b/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
similarity index 93%
rename from ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
index 83ca9f2b..dcfed4e 100644
--- a/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
@@ -11,13 +11,13 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/linux/linux_input_method_context.h"
 #include "ui/events/event.h"
+#include "ui/ozone/platform/wayland/host/wayland_input_method_context.h"
+#include "ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/mock_zwp_text_input.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_input_method_context.h"
-#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 
 using ::testing::_;
 using ::testing::SaveArg;
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.cc b/ui/ozone/platform/wayland/host/wayland_keyboard.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_keyboard.cc
rename to ui/ozone/platform/wayland/host/wayland_keyboard.cc
index 910a5ec..181e6e56 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard.cc
+++ b/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_keyboard.h"
+#include "ui/ozone/platform/wayland/host/wayland_keyboard.h"
 
 #include <sys/mman.h>
 #include <utility>
@@ -17,8 +17,8 @@
 #include "ui/events/ozone/evdev/keyboard_util_evdev.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 #if BUILDFLAG(USE_XKBCOMMON)
 #include "ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h"
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.h b/ui/ozone/platform/wayland/host/wayland_keyboard.h
similarity index 92%
rename from ui/ozone/platform/wayland/wayland_keyboard.h
rename to ui/ozone/platform/wayland/host/wayland_keyboard.h
index 9c4155c..1e5fd7a 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard.h
+++ b/ui/ozone/platform/wayland/host/wayland_keyboard.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_KEYBOARD_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_KEYBOARD_H_
 
 #include <wayland-client.h>
 
 #include "ui/base/buildflags.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
 #include "ui/events/ozone/keyboard/event_auto_repeat_handler.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 namespace ui {
 
@@ -99,4 +99,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_KEYBOARD_H_
diff --git a/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc b/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc
similarity index 99%
rename from ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc
index 3e7abb0..60eec44 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc
@@ -14,7 +14,7 @@
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/test_keyboard.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 
 #if BUILDFLAG(USE_XKBCOMMON)
 #include "base/memory/free_deleter.h"
@@ -22,8 +22,8 @@
 #include "ui/events/keycodes/scoped_xkb.h"  // nogncheck
 #endif
 
-using ::testing::SaveArg;
 using ::testing::_;
+using ::testing::SaveArg;
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_output.cc b/ui/ozone/platform/wayland/host/wayland_output.cc
similarity index 90%
rename from ui/ozone/platform/wayland/wayland_output.cc
rename to ui/ozone/platform/wayland/host/wayland_output.cc
index 91cdf2c4..0b36d95 100644
--- a/ui/ozone/platform/wayland/wayland_output.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_output.h"
+#include "ui/ozone/platform/wayland/host/wayland_output.h"
 
 #include <wayland-client.h>
 
 #include "ui/gfx/color_space.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 
 namespace ui {
 
@@ -27,8 +27,10 @@
   DCHECK(!delegate_);
   delegate_ = delegate;
   static const wl_output_listener output_listener = {
-      &WaylandOutput::OutputHandleGeometry, &WaylandOutput::OutputHandleMode,
-      &WaylandOutput::OutputHandleDone, &WaylandOutput::OutputHandleScale,
+      &WaylandOutput::OutputHandleGeometry,
+      &WaylandOutput::OutputHandleMode,
+      &WaylandOutput::OutputHandleDone,
+      &WaylandOutput::OutputHandleScale,
   };
   wl_output_add_listener(output_.get(), &output_listener, this);
 }
diff --git a/ui/ozone/platform/wayland/wayland_output.h b/ui/ozone/platform/wayland/host/wayland_output.h
similarity index 91%
rename from ui/ozone/platform/wayland/wayland_output.h
rename to ui/ozone/platform/wayland/host/wayland_output.h
index 41a4d395..464689e 100644
--- a/ui/ozone/platform/wayland/wayland_output.h
+++ b/ui/ozone/platform/wayland/host/wayland_output.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OUTPUT_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OUTPUT_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_OUTPUT_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_OUTPUT_H_
 
 #include <stdint.h>
 
 #include "ui/display/types/display_snapshot.h"
 #include "ui/display/types/native_display_delegate.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 namespace ui {
 
@@ -78,4 +78,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SCREEN_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SCREEN_H_
diff --git a/ui/ozone/platform/wayland/wayland_output_manager.cc b/ui/ozone/platform/wayland/host/wayland_output_manager.cc
similarity index 95%
rename from ui/ozone/platform/wayland/wayland_output_manager.cc
rename to ui/ozone/platform/wayland/host/wayland_output_manager.cc
index a7f6e44..38dad07 100644
--- a/ui/ozone/platform/wayland/wayland_output_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output_manager.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
 
 #include <memory>
 
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_output.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_output.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_output_manager.h b/ui/ozone/platform/wayland/host/wayland_output_manager.h
similarity index 79%
rename from ui/ozone/platform/wayland/wayland_output_manager.h
rename to ui/ozone/platform/wayland/host/wayland_output_manager.h
index cae7097..8123232 100644
--- a/ui/ozone/platform/wayland/wayland_output_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_output_manager.h
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OUTPUT_MANAGER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OUTPUT_MANAGER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_OUTPUT_MANAGER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_OUTPUT_MANAGER_H_
 
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 #include <memory>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "ui/ozone/platform/wayland/wayland_output.h"
-#include "ui/ozone/platform/wayland/wayland_screen.h"
+#include "ui/ozone/platform/wayland/host/wayland_output.h"
+#include "ui/ozone/platform/wayland/host/wayland_screen.h"
 
 struct wl_output;
 
@@ -59,4 +59,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OUTPUT_MANAGER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_OUTPUT_MANAGER_H_
diff --git a/ui/ozone/platform/wayland/wayland_pointer.cc b/ui/ozone/platform/wayland/host/wayland_pointer.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_pointer.cc
rename to ui/ozone/platform/wayland/host/wayland_pointer.cc
index 4c05825..5ee7d19 100644
--- a/ui/ozone/platform/wayland/wayland_pointer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
 
 #include <linux/input.h>
 #include <wayland-client.h>
@@ -10,8 +10,8 @@
 
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 // TODO(forney): Handle version 5 of wl_pointer.
 
diff --git a/ui/ozone/platform/wayland/wayland_pointer.h b/ui/ozone/platform/wayland/host/wayland_pointer.h
similarity index 90%
rename from ui/ozone/platform/wayland/wayland_pointer.h
rename to ui/ozone/platform/wayland/host/wayland_pointer.h
index 070e0b62..bf51fed 100644
--- a/ui/ozone/platform/wayland/wayland_pointer.h
+++ b/ui/ozone/platform/wayland/host/wayland_pointer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POINTER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POINTER_H_
 
 #include <memory>
 
@@ -11,8 +11,8 @@
 #include "base/memory/weak_ptr.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
 #include "ui/gfx/geometry/point_f.h"
-#include "ui/ozone/platform/wayland/wayland_cursor.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor.h"
 
 namespace ui {
 
@@ -97,4 +97,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POINTER_H_
diff --git a/ui/ozone/platform/wayland/wayland_pointer_unittest.cc b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
similarity index 98%
rename from ui/ozone/platform/wayland/wayland_pointer_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
index 3b3aa896..f967107c9 100644
--- a/ui/ozone/platform/wayland/wayland_pointer_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -9,12 +9,12 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/test/mock_pointer.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_cursor.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 #include "ui/ozone/test/mock_platform_window_delegate.h"
 #include "ui/platform_window/platform_window_init_properties.h"
 
diff --git a/ui/ozone/platform/wayland/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
similarity index 96%
rename from ui/ozone/platform/wayland/wayland_screen.cc
rename to ui/ozone/platform/wayland/host/wayland_screen.cc
index 19fb4050..e53a959 100644
--- a/ui/ozone/platform/wayland/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_screen.h"
+#include "ui/ozone/platform/wayland/host/wayland_screen.h"
 
 #include "ui/display/display.h"
 #include "ui/display/display_finder.h"
 #include "ui/display/display_observer.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_cursor_position.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_screen.h b/ui/ozone/platform/wayland/host/wayland_screen.h
similarity index 89%
rename from ui/ozone/platform/wayland/wayland_screen.h
rename to ui/ozone/platform/wayland/host/wayland_screen.h
index 480957bf..f395b9b 100644
--- a/ui/ozone/platform/wayland/wayland_screen.h
+++ b/ui/ozone/platform/wayland/host/wayland_screen.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SCREEN_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SCREEN_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SCREEN_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SCREEN_H_
 
 #include <vector>
 
@@ -11,7 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "ui/display/display_list.h"
-#include "ui/ozone/platform/wayland/wayland_output.h"
+#include "ui/ozone/platform/wayland/host/wayland_output.h"
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/platform_screen.h"
 
@@ -62,4 +62,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SCREEN_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SCREEN_H_
diff --git a/ui/ozone/platform/wayland/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
similarity index 98%
rename from ui/ozone/platform/wayland/wayland_screen_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index e081590a..54e72fb5 100644
--- a/ui/ozone/platform/wayland/wayland_screen_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <memory>
 #include <wayland-server.h>
+#include <memory>
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display_observer.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_screen.h"
 #include "ui/ozone/platform/wayland/test/mock_pointer.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_output_manager.h"
-#include "ui/ozone/platform/wayland/wayland_screen.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 #include "ui/platform_window/platform_window_init_properties.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/wayland/wayland_shared_memory_buffer_manager.cc b/ui/ozone/platform/wayland/host/wayland_shared_memory_buffer_manager.cc
similarity index 93%
rename from ui/ozone/platform/wayland/wayland_shared_memory_buffer_manager.cc
rename to ui/ozone/platform/wayland/host/wayland_shared_memory_buffer_manager.cc
index 0cfe3cd..af129fe 100644
--- a/ui/ozone/platform/wayland/wayland_shared_memory_buffer_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_shared_memory_buffer_manager.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_shared_memory_buffer_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_shared_memory_buffer_manager.h"
 
 #include <utility>
 
 #include "base/trace_event/trace_event.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_shared_memory_buffer_manager.h b/ui/ozone/platform/wayland/host/wayland_shared_memory_buffer_manager.h
similarity index 85%
rename from ui/ozone/platform/wayland/wayland_shared_memory_buffer_manager.h
rename to ui/ozone/platform/wayland/host/wayland_shared_memory_buffer_manager.h
index 8626ff00..e10ffe6 100644
--- a/ui/ozone/platform/wayland/wayland_shared_memory_buffer_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_shared_memory_buffer_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SHARED_MEMORY_BUFFER_MANAGER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SHARED_MEMORY_BUFFER_MANAGER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SHARED_MEMORY_BUFFER_MANAGER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SHARED_MEMORY_BUFFER_MANAGER_H_
 
 #include <map>
 #include <memory>
@@ -14,8 +14,8 @@
 #include "base/macros.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 
 namespace ui {
 
@@ -73,4 +73,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SHARED_MEMORY_BUFFER_MANAGER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SHARED_MEMORY_BUFFER_MANAGER_H_
diff --git a/ui/ozone/platform/wayland/wayland_shm_buffer.cc b/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
similarity index 92%
rename from ui/ozone/platform/wayland/wayland_shm_buffer.cc
rename to ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
index 98f48dd..d5d2c25 100644
--- a/ui/ozone/platform/wayland/wayland_shm_buffer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_shm_buffer.h"
+#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
 
 #include "ui/gfx/skia_util.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 
 namespace {
 
diff --git a/ui/ozone/platform/wayland/wayland_shm_buffer.h b/ui/ozone/platform/wayland/host/wayland_shm_buffer.h
similarity index 88%
rename from ui/ozone/platform/wayland/wayland_shm_buffer.h
rename to ui/ozone/platform/wayland/host/wayland_shm_buffer.h
index d6644d4..8ed08df 100644
--- a/ui/ozone/platform/wayland/wayland_shm_buffer.h
+++ b/ui/ozone/platform/wayland/host/wayland_shm_buffer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SHM_BUFFER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SHM_BUFFER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SHM_BUFFER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SHM_BUFFER_H_
 
 #include <wayland-client.h>
 
@@ -14,7 +14,7 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 namespace ui {
 
@@ -61,4 +61,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SHM_BUFFER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_SHM_BUFFER_H_
diff --git a/ui/ozone/platform/wayland/wayland_touch.cc b/ui/ozone/platform/wayland/host/wayland_touch.cc
similarity index 96%
rename from ui/ozone/platform/wayland/wayland_touch.cc
rename to ui/ozone/platform/wayland/host/wayland_touch.cc
index d30bc73..ce18b08 100644
--- a/ui/ozone/platform/wayland/wayland_touch.cc
+++ b/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_touch.h"
+#include "ui/ozone/platform/wayland/host/wayland_touch.h"
 
 #include <sys/mman.h>
 #include <wayland-client.h>
@@ -10,8 +10,8 @@
 #include "base/files/scoped_file.h"
 #include "ui/base/buildflags.h"
 #include "ui/events/event.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_touch.h b/ui/ozone/platform/wayland/host/wayland_touch.h
similarity index 89%
rename from ui/ozone/platform/wayland/wayland_touch.h
rename to ui/ozone/platform/wayland/host/wayland_touch.h
index ae097fd0..52baf9f9 100644
--- a/ui/ozone/platform/wayland/wayland_touch.h
+++ b/ui/ozone/platform/wayland/host/wayland_touch.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TOUCH_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TOUCH_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOUCH_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOUCH_H_
 
 #include <memory>
 
 #include "base/containers/flat_map.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 namespace ui {
 
@@ -77,4 +77,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TOUCH_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOUCH_H_
diff --git a/ui/ozone/platform/wayland/wayland_touch_unittest.cc b/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc
similarity index 95%
rename from ui/ozone/platform/wayland/wayland_touch_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_touch_unittest.cc
index 9a64f9c..dc2bb0ff 100644
--- a/ui/ozone/platform/wayland/wayland_touch_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc
@@ -9,15 +9,15 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/test_touch.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 #include "ui/ozone/test/mock_platform_window_delegate.h"
 
-using ::testing::SaveArg;
 using ::testing::_;
+using ::testing::SaveArg;
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_window.cc
rename to ui/ozone/platform/wayland/host/wayland_window.cc
index 98fe563..4b0a990 100644
--- a/ui/ozone/platform/wayland/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 #include <wayland-client.h>
 #include <memory>
@@ -16,14 +16,14 @@
 #include "ui/events/event_utils.h"
 #include "ui/events/ozone/events_ozone.h"
 #include "ui/gfx/geometry/point_f.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_cursor_position.h"
-#include "ui/ozone/platform/wayland/wayland_output_manager.h"
-#include "ui/ozone/platform/wayland/wayland_pointer.h"
-#include "ui/ozone/platform/wayland/xdg_popup_wrapper_v5.h"
-#include "ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h"
-#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v5.h"
-#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_v5.h"
+#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_v5.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.h"
 #include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_window.h
rename to ui/ozone/platform/wayland/host/wayland_window.h
index 94c3a60..3d46ba1f 100644
--- a/ui/ozone/platform/wayland/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_H_
 
 #include <memory>
 #include <set>
@@ -14,7 +14,7 @@
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 #include "ui/platform_window/platform_window.h"
 #include "ui/platform_window/platform_window_delegate.h"
 #include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
@@ -245,4 +245,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_H_
diff --git a/ui/ozone/platform/wayland/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
similarity index 99%
rename from ui/ozone/platform/wayland/wayland_window_unittest.cc
rename to ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index fcad755..8083f7a 100644
--- a/ui/ozone/platform/wayland/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 #include <memory>
 #include <utility>
@@ -19,12 +19,12 @@
 #include "ui/base/hit_test.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 #include "ui/ozone/platform/wayland/test/mock_pointer.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/test_region.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_test.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 #include "ui/ozone/test/mock_platform_window_delegate.h"
 #include "ui/platform_window/platform_window_init_properties.h"
 
diff --git a/ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.cc b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.cc
rename to ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
index fccb607..08d5dbf8b 100644
--- a/ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.h"
+#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
 
 #include <drm_fourcc.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 
 #include "ui/ozone/common/linux/drm_util_linux.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.h b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h
similarity index 91%
rename from ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.h
rename to ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h
index 5c393d5..00cc223d 100644
--- a/ui/ozone/platform/wayland/wayland_zwp_linux_dmabuf.h
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_ZWP_LINUX_DMABUF_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_ZWP_LINUX_DMABUF_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_LINUX_DMABUF_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_LINUX_DMABUF_H_
 
 #include <vector>
 
 #include "base/containers/flat_map.h"
 #include "base/files/file.h"
 #include "base/macros.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 
 struct zwp_linux_dmabuf_v1;
 struct zwp_linux_buffer_params_v1;
@@ -99,4 +99,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_ZWP_LINUX_DMABUF_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_LINUX_DMABUF_H_
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper.h b/ui/ozone/platform/wayland/host/xdg_popup_wrapper.h
similarity index 73%
rename from ui/ozone/platform/wayland/xdg_popup_wrapper.h
rename to ui/ozone/platform/wayland/host/xdg_popup_wrapper.h
index 2bd215c..75cbb04 100644
--- a/ui/ozone/platform/wayland/xdg_popup_wrapper.h
+++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_H_
 
 #include "ui/gfx/geometry/rect.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 namespace ui {
 
@@ -27,4 +27,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_H_
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v5.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v5.cc
similarity index 89%
rename from ui/ozone/platform/wayland/xdg_popup_wrapper_v5.cc
rename to ui/ozone/platform/wayland/host/xdg_popup_wrapper_v5.cc
index 80cd1ac..6f011c4f 100644
--- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v5.cc
+++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v5.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/xdg_popup_wrapper_v5.h"
+#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_v5.h"
 #include <xdg-shell-unstable-v5-client-protocol.h>
 #include <vector>
 
 #include "ui/gfx/geometry/rect.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v5.h b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v5.h
similarity index 76%
rename from ui/ozone/platform/wayland/xdg_popup_wrapper_v5.h
rename to ui/ozone/platform/wayland/host/xdg_popup_wrapper_v5.h
index 2304e84e5..b6578d1 100644
--- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v5.h
+++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v5.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_V5_H_
-#define UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_V5_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_V5_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_V5_H_
 
-#include "ui/ozone/platform/wayland/xdg_popup_wrapper.h"
+#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper.h"
 
 namespace ui {
 
@@ -35,4 +35,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_V5_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_V5_H_
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.cc
similarity index 96%
rename from ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
rename to ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.cc
index 866133e..a17719ea 100644
--- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
+++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.cc
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h"
+#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.h"
 
 #include <xdg-shell-unstable-v6-client-protocol.h>
 #include <memory>
 
 #include "ui/events/event_constants.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_pointer.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
-#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.h"
 
 namespace ui {
 
@@ -185,7 +185,8 @@
                                    const gfx::Rect& bounds) {
   DCHECK(connection && surface && parent_window);
   static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
-      &XDGPopupWrapperV6::Configure, &XDGPopupWrapperV6::PopupDone,
+      &XDGPopupWrapperV6::Configure,
+      &XDGPopupWrapperV6::PopupDone,
   };
 
   XDGSurfaceWrapperV6* xdg_surface =
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.h
similarity index 85%
rename from ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h
rename to ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.h
index cd56eeff..7b7f2921 100644
--- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h
+++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_V6_H_
-#define UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_V6_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_V6_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_V6_H_
 
 #include <memory>
 
-#include "ui/ozone/platform/wayland/xdg_popup_wrapper.h"
+#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper.h"
 
 namespace ui {
 
@@ -52,4 +52,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_V6_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_POPUP_WRAPPER_V6_H_
diff --git a/ui/ozone/platform/wayland/xdg_surface_wrapper.cc b/ui/ozone/platform/wayland/host/xdg_surface_wrapper.cc
similarity index 92%
rename from ui/ozone/platform/wayland/xdg_surface_wrapper.cc
rename to ui/ozone/platform/wayland/host/xdg_surface_wrapper.cc
index 6d272e5..089e353 100644
--- a/ui/ozone/platform/wayland/xdg_surface_wrapper.cc
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/xdg_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/xdg_surface_wrapper.h b/ui/ozone/platform/wayland/host/xdg_surface_wrapper.h
similarity index 88%
rename from ui/ozone/platform/wayland/xdg_surface_wrapper.h
rename to ui/ozone/platform/wayland/host/xdg_surface_wrapper.h
index 58bf129..c9736ab 100644
--- a/ui/ozone/platform/wayland/xdg_surface_wrapper.h
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_H_
 
 #include "base/strings/string16.h"
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 namespace gfx {
 class Rect;
@@ -65,4 +65,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_H_
diff --git a/ui/ozone/platform/wayland/xdg_surface_wrapper_v5.cc b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_v5.cc
similarity index 91%
rename from ui/ozone/platform/wayland/xdg_surface_wrapper_v5.cc
rename to ui/ozone/platform/wayland/host/xdg_surface_wrapper_v5.cc
index 7f9cdf8..7d4172d2 100644
--- a/ui/ozone/platform/wayland/xdg_surface_wrapper_v5.cc
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_v5.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v5.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_v5.h"
 
 #include <xdg-shell-unstable-v5-client-protocol.h>
 
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/hit_test.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
@@ -23,7 +23,8 @@
                                      wl_surface* surface,
                                      bool with_toplevel) {
   static const xdg_surface_listener xdg_surface_listener = {
-      &XDGSurfaceWrapperV5::Configure, &XDGSurfaceWrapperV5::Close,
+      &XDGSurfaceWrapperV5::Configure,
+      &XDGSurfaceWrapperV5::Close,
   };
   xdg_surface_.reset(xdg_shell_get_xdg_surface(connection->shell(), surface));
   if (!xdg_surface_) {
diff --git a/ui/ozone/platform/wayland/xdg_surface_wrapper_v5.h b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_v5.h
similarity index 86%
rename from ui/ozone/platform/wayland/xdg_surface_wrapper_v5.h
rename to ui/ozone/platform/wayland/host/xdg_surface_wrapper_v5.h
index 5ef0e607..a8e82fc 100644
--- a/ui/ozone/platform/wayland/xdg_surface_wrapper_v5.h
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_v5.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_V5_H_
-#define UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_V5_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_V5_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_V5_H_
 
-#include "ui/ozone/platform/wayland/xdg_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper.h"
 
 #include "base/macros.h"
 
@@ -55,4 +55,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_V5_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_V5_H_
diff --git a/ui/ozone/platform/wayland/xdg_surface_wrapper_v6.cc b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.cc
similarity index 95%
rename from ui/ozone/platform/wayland/xdg_surface_wrapper_v6.cc
rename to ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.cc
index f913d20..9cac792 100644
--- a/ui/ozone/platform/wayland/xdg_surface_wrapper_v6.cc
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.h"
 
 #include <xdg-shell-unstable-v6-client-protocol.h>
 
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/hit_test.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_util.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.h
similarity index 87%
rename from ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h
rename to ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.h
index 92443cc..2b49fcf 100644
--- a/ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_v6.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_V6_H_
-#define UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_V6_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_V6_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_V6_H_
 
-#include "ui/ozone/platform/wayland/xdg_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper.h"
 
 #include "base/macros.h"
 
@@ -66,4 +66,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_XDG_SURFACE_WRAPPER_V6_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_V6_H_
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper.h b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h
similarity index 89%
rename from ui/ozone/platform/wayland/zwp_text_input_wrapper.h
rename to ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h
index 8b11a95b7..83e84c5 100644
--- a/ui/ozone/platform/wayland/zwp_text_input_wrapper.h
+++ b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_
-#define UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_TEXT_INPUT_WRAPPER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_TEXT_INPUT_WRAPPER_H_
 
-#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
 
 #include "base/strings/string16.h"
 
@@ -71,4 +71,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_TEXT_INPUT_WRAPPER_H_
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
similarity index 96%
rename from ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc
rename to ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
index 4a12ace..7b72165b4 100644
--- a/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc
+++ b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h"
+#include "ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/gfx/range/range.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h
similarity index 93%
rename from ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h
rename to ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h
index 62cfaa6..59f329f 100644
--- a/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h
+++ b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_
-#define UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_TEXT_INPUT_WRAPPER_V1_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_TEXT_INPUT_WRAPPER_V1_H_
 
 #include <text-input-unstable-v1-client-protocol.h>
 #include <string>
 
-#include "ui/ozone/platform/wayland/zwp_text_input_wrapper.h"
+#include "ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h"
 
 namespace gfx {
 class Rect;
@@ -103,4 +103,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_TEXT_INPUT_WRAPPER_V1_H_
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 6bdd791..c368863 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -20,12 +20,12 @@
 #include "ui/ozone/common/stub_overlay_manager.h"
 #include "ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_connection_connector.h"
-#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h"
-#include "ui/ozone/platform/wayland/wayland_output_manager.h"
-#include "ui/ozone/platform/wayland/wayland_surface_factory.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection_connector.h"
+#include "ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h"
+#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/public/gpu_platform_support_host.h"
 #include "ui/ozone/public/input_controller.h"
 #include "ui/ozone/public/ozone_platform.h"
diff --git a/ui/ozone/platform/wayland/wayland_test.cc b/ui/ozone/platform/wayland/test/wayland_test.cc
similarity index 97%
rename from ui/ozone/platform/wayland/wayland_test.cc
rename to ui/ozone/platform/wayland/test/wayland_test.cc
index 495d6a37..11f3b7a0 100644
--- a/ui/ozone/platform/wayland/wayland_test.cc
+++ b/ui/ozone/platform/wayland/test/wayland_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/wayland/wayland_test.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
 
 #include "base/run_loop.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
diff --git a/ui/ozone/platform/wayland/wayland_test.h b/ui/ozone/platform/wayland/test/wayland_test.h
similarity index 85%
rename from ui/ozone/platform/wayland/wayland_test.h
rename to ui/ozone/platform/wayland/test/wayland_test.h
index 2c83f37..461d279 100644
--- a/ui/ozone/platform/wayland/wayland_test.h
+++ b/ui/ozone/platform/wayland/test/wayland_test.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TEST_H_
-#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TEST_H_
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_TEST_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_TEST_H_
 
 #include <memory>
 
@@ -12,9 +12,9 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/buildflags.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
 #include "ui/ozone/test/mock_platform_window_delegate.h"
 
 #if BUILDFLAG(USE_XKBCOMMON)
@@ -66,4 +66,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TEST_H_
+#endif  // UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_TEST_H_
diff --git a/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc b/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc
index 117208c..c4ad4ed3 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc
+++ b/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc
@@ -17,9 +17,9 @@
 #include "base/test/fuzzed_data_provider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/wayland_connection.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
 #include "ui/platform_window/platform_window_delegate.h"
 #include "ui/platform_window/platform_window_init_properties.h"
 
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index f037f38..9e1b2cea 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -160,7 +160,6 @@
     "controls/resize_area.h",
     "controls/resize_area_delegate.h",
     "controls/scroll_view.h",
-    "controls/scrollbar/base_scroll_bar.h",
     "controls/scrollbar/base_scroll_bar_button.h",
     "controls/scrollbar/base_scroll_bar_thumb.h",
     "controls/scrollbar/cocoa_scroll_bar.h",
@@ -365,7 +364,6 @@
     "controls/progress_bar.cc",
     "controls/resize_area.cc",
     "controls/scroll_view.cc",
-    "controls/scrollbar/base_scroll_bar.cc",
     "controls/scrollbar/base_scroll_bar_button.cc",
     "controls/scrollbar/base_scroll_bar_thumb.cc",
     "controls/scrollbar/cocoa_scroll_bar.mm",
@@ -890,7 +888,6 @@
     "test/widget_test_mac.mm",
     "test/x11_property_change_waiter.cc",
     "test/x11_property_change_waiter.h",
-    "view_test_api.h",
     "views_test_suite.cc",
     "views_test_suite.h",
   ]
diff --git a/ui/views/accessibility/ax_aura_obj_cache.cc b/ui/views/accessibility/ax_aura_obj_cache.cc
index cc8ad5f..426d19fa 100644
--- a/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -69,8 +69,8 @@
 
 void AXAuraObjCache::RemoveViewSubtree(View* view) {
   Remove(view);
-  for (int i = 0; i < view->child_count(); ++i)
-    RemoveViewSubtree(view->child_at(i));
+  for (View* child : view->children())
+    RemoveViewSubtree(child);
 }
 
 void AXAuraObjCache::Remove(Widget* widget) {
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.cc b/ui/views/accessibility/ax_view_obj_wrapper.cc
index f5fbf1c..70c92d4 100644
--- a/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -56,12 +56,9 @@
     return;
 
   // TODO(dtseng): Need to handle |Widget| child of |View|.
-  for (int i = 0; i < view_->child_count(); ++i) {
-    if (!view_->child_at(i)->visible())
-      continue;
-
-    AXAuraObjWrapper* child = aura_obj_cache_->GetOrCreate(view_->child_at(i));
-    out_children->push_back(child);
+  for (View* child : view_->children()) {
+    if (child->visible())
+      out_children->push_back(aura_obj_cache_->GetOrCreate(child));
   }
 
   for (int i = 0; i < view_accessibility.virtual_child_count(); ++i) {
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc
index 6556a431..b51c419 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -454,8 +454,10 @@
 }
 
 void BubbleDialogDelegateView::UpdateAnchorWidgetRenderState(bool visible) {
-  if (!anchor_widget() || !anchor_widget()->GetTopLevelWidget())
+  if (!anchor_widget() || !anchor_widget()->GetTopLevelWidget() ||
+      !CanActivate()) {
     return;
+  }
 
   anchor_widget()->GetTopLevelWidget()->SetAlwaysRenderAsActive(visible);
 }
diff --git a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
index 147b261..492625f 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/i18n/rtl.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "ui/base/hit_test.h"
 #include "ui/events/event_utils.h"
 #include "ui/views/animation/test/ink_drop_host_view_test_api.h"
@@ -23,6 +24,10 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
 
+#if defined(OS_WIN)
+#include "ui/base/win/shell.h"
+#endif
+
 namespace views {
 
 using test::TestInkDrop;
@@ -272,13 +277,21 @@
   BubbleDialogDelegateView::CreateBubble(bubble_delegate);
   BubbleFrameView* frame = bubble_delegate->GetBubbleFrameView();
 
+#if defined(OS_WIN)
+  bool is_aero_glass_enabled = ui::win::IsAeroGlassEnabled();
+#endif
+
   struct {
     const int point;
     const int hit;
-  } constexpr kTestCases[] = {
-      {0, HTTRANSPARENT},
-      {60, HTCLIENT},
-      {1000, HTNOWHERE},
+  } kTestCases[] = {
+#if defined(OS_WIN)
+    {0, is_aero_glass_enabled ? HTTRANSPARENT : HTNOWHERE},
+#else
+    {0, HTTRANSPARENT},
+#endif
+    {60, HTCLIENT},
+    {1000, HTNOWHERE},
   };
 
   for (const auto& test_case : kTestCases) {
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index 3828c024..57f4b69 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -262,7 +262,7 @@
                                !delegate->GetWindowTitle().empty());
     default_title_->SetText(delegate->GetWindowTitle());
   }  // custom_title_'s updates are handled by its creator.
-  InvalidateLayout();
+  Layout();
 }
 
 void BubbleFrameView::SizeConstraintsChanged() {}
@@ -533,7 +533,8 @@
         GetOffScreenLength(available_bounds, window_bounds, vertical)) {
       bubble_border_->set_arrow(arrow);
     } else {
-      InvalidateLayout();
+      if (parent())
+        parent()->Layout();
       SchedulePaint();
     }
   }
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.h b/ui/views/cocoa/bridged_native_widget_host_impl.h
index 69f1c98..9403ce40 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.h
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -362,7 +362,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDeviceScaleFactorChanged(float old_device_scale_factor,
                                   float new_device_scale_factor) override;
-  void UpdateVisualState() override;
 
   // ui::AcceleratedWidgetMacNSView:
   void AcceleratedWidgetCALayerParamsUpdated() override;
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.mm b/ui/views/cocoa/bridged_native_widget_host_impl.mm
index 5048760..4d7d94a 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -694,8 +694,8 @@
   auto it = associated_views_.find(view);
   if (it != associated_views_.end())
     rank->emplace(it->second, rank->size());
-  for (int i = 0; i < view->child_count(); ++i)
-    RankNSViewsRecursive(view->child_at(i), rank);
+  for (View* child : view->children())
+    RankNSViewsRecursive(child, rank);
 }
 
 void BridgedNativeWidgetHostImpl::UpdateLocalWindowFrame(
@@ -1407,10 +1407,6 @@
       old_device_scale_factor, new_device_scale_factor);
 }
 
-void BridgedNativeWidgetHostImpl::UpdateVisualState() {
-  native_widget_mac_->GetWidget()->LayoutRootViewIfNecessary();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // BridgedNativeWidgetHostImpl, AcceleratedWidgetMac:
 
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc
index 963e009..2be096e 100644
--- a/ui/views/controls/button/label_button.cc
+++ b/ui/views/controls/button/label_button.cc
@@ -385,7 +385,7 @@
   ResetLabelEnabledColor();
   label_->SetEnabled(state() != STATE_DISABLED);
   if (image_->GetPreferredSize() != previous_image_size)
-    InvalidateLayout();
+    Layout();
 }
 
 void LabelButton::GetExtraParams(ui::NativeTheme::ExtraParams* params) const {
@@ -479,6 +479,7 @@
 void LabelButton::ChildPreferredSizeChanged(View* child) {
   ResetCachedPreferredSize();
   PreferredSizeChanged();
+  Layout();
 }
 
 ui::NativeTheme::Part LabelButton::GetThemePart() const {
diff --git a/ui/views/controls/button/label_button_unittest.cc b/ui/views/controls/button/label_button_unittest.cc
index be3f7fe9..375c6a5 100644
--- a/ui/views/controls/button/label_button_unittest.cc
+++ b/ui/views/controls/button/label_button_unittest.cc
@@ -29,7 +29,6 @@
 #include "ui/views/style/platform_style.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/test/widget_test.h"
-#include "ui/views/view_test_api.h"
 #include "ui/views/widget/widget_utils.h"
 
 using base::ASCIIToUTF16;
@@ -460,16 +459,12 @@
   // The button preferred size and the label size increase when the text size
   // is increased.
   button_->SetText(longer_text);
-  EXPECT_TRUE(ViewTestApi(button_).needs_layout());
-  button_->Layout();
   EXPECT_GT(button_->label()->bounds().width(), original_label_width * 2);
   EXPECT_GT(button_->GetPreferredSize().width(), original_width * 2);
 
   // The button and the label view return to its original size when the original
   // text is restored.
   button_->SetText(text);
-  EXPECT_TRUE(ViewTestApi(button_).needs_layout());
-  button_->Layout();
   EXPECT_EQ(original_label_width, button_->label()->bounds().width());
   EXPECT_EQ(original_width, button_->GetPreferredSize().width());
 }
diff --git a/ui/views/controls/focus_ring.cc b/ui/views/controls/focus_ring.cc
index 2346789..b1bd6f1c 100644
--- a/ui/views/controls/focus_ring.cc
+++ b/ui/views/controls/focus_ring.cc
@@ -32,7 +32,7 @@
   auto ring = base::WrapUnique<FocusRing>(new FocusRing());
   ring->set_owned_by_client();
   parent->AddChildView(ring.get());
-  ring->InvalidateLayout();
+  ring->Layout();
   ring->SchedulePaint();
   return ring;
 }
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index bba4490..09c24be 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -831,6 +831,7 @@
 }
 
 void Label::ResetLayout() {
+  InvalidateLayout();
   PreferredSizeChanged();
   SchedulePaint();
   ClearDisplayText();
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 606214a..ce3827e 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -120,8 +120,8 @@
   if (button && button->IsHotTracked())
     return button;
 
-  for (int i = 0; i < view->child_count(); ++i) {
-    Button* hot_view = GetFirstHotTrackedView(view->child_at(i));
+  for (View* child : view->children()) {
+    Button* hot_view = GetFirstHotTrackedView(child);
     if (hot_view)
       return hot_view;
   }
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index eb56fba..95049b9 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -10,6 +10,7 @@
 #include <algorithm>
 #include <numeric>
 
+#include "base/containers/adapters.h"
 #include "base/i18n/case_conversion.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
@@ -485,7 +486,7 @@
     AddChildView(icon_view);
     icon_view_ = icon_view;
   }
-  InvalidateLayout();
+  Layout();
   SchedulePaint();
 }
 
@@ -606,10 +607,9 @@
     controller->MenuChildrenChanged(this);
 
     if (submenu_) {
-      // Force a paint and a synchronous layout. This needs a synchronous layout
-      // as UpdateSubmenuSelection() looks at bounds. This handles the case of
-      // the top level window's size remaining the same, resulting in no change
-      // to the submenu's size and no layout.
+      // Force a paint and layout. This handles the case of the top
+      // level window's size remaining the same, resulting in no
+      // change to the submenu's size and no layout.
       submenu_->Layout();
       submenu_->SchedulePaint();
       // Update the menu selection after layout.
@@ -638,8 +638,7 @@
     // Child views are laid out right aligned and given the full height. To
     // right align start with the last view and progress to the first.
     int x = width() - (use_right_margin_ ? item_right_margin_ : 0);
-    for (int i = child_count() - 1; i >= 0; --i) {
-      View* child = child_at(i);
+    for (View* child : base::Reversed(children())) {
       if (icon_view_ == child)
         continue;
       if (radio_check_image_view_ == child)
@@ -923,10 +922,9 @@
 
 void MenuItemView::RemoveEmptyMenus() {
   DCHECK(HasSubmenu());
-  // Iterate backwards as we may end up removing views, which alters the child
-  // view count.
-  for (int i = submenu_->child_count() - 1; i >= 0; --i) {
-    View* child = submenu_->child_at(i);
+  // Copy the children, since we may mutate them as we go.
+  const Views children = submenu_->children();
+  for (View* child : children) {
     if (child->id() == MenuItemView::kMenuItemViewID) {
       MenuItemView* menu_item = static_cast<MenuItemView*>(child);
       if (menu_item->HasSubmenu())
@@ -1213,7 +1211,7 @@
     dimensions.standard_width = menu_config.touchable_menu_width;
 
     if (icon_view_) {
-      dimensions.height = icon_view_->GetPreferredSize().height() +
+      dimensions.height = icon_view_->height() +
                           2 * menu_config.vertical_touchable_menu_item_padding;
     }
     return dimensions;
diff --git a/ui/views/controls/menu/menu_item_view.h b/ui/views/controls/menu/menu_item_view.h
index d182c277..db677e0ce 100644
--- a/ui/views/controls/menu/menu_item_view.h
+++ b/ui/views/controls/menu/menu_item_view.h
@@ -381,8 +381,8 @@
   // MenuRunner owns MenuItemView and should be the only one deleting it.
   ~MenuItemView() override;
 
-  // View:
   void ChildPreferredSizeChanged(View* child) override;
+
   const char* GetClassName() const override;
 
   // Returns the preferred size (and padding) of any children.
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc
index f3ff29e3..85ae4ec9 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -282,7 +282,7 @@
   gfx::Size content_pref = scroll_view_->GetContents()->GetPreferredSize();
   scroll_up_button_->SetVisible(content_pref.height() > height());
   scroll_down_button_->SetVisible(content_pref.height() > height());
-  InvalidateLayout();
+  Layout();
 }
 
 void MenuScrollViewContainer::CreateBorder() {
diff --git a/ui/views/controls/menu/submenu_view.cc b/ui/views/controls/menu/submenu_view.cc
index 8ffe4c11..d600a142 100644
--- a/ui/views/controls/menu/submenu_view.cc
+++ b/ui/views/controls/menu/submenu_view.cc
@@ -127,8 +127,7 @@
   int x = insets.left();
   int y = insets.top();
   int menu_item_width = width() - insets.width();
-  for (int i = 0; i < child_count(); ++i) {
-    View* child = child_at(i);
+  for (View* child : children()) {
     if (child->visible()) {
       int child_height = child->GetHeightForWidth(menu_item_width);
       child->SetBounds(x, y, menu_item_width, child_height);
@@ -153,8 +152,7 @@
   // calculate the width of the menu. In the second, we calculate the height
   // using that width. This allows views that have flexible widths to adjust
   // accordingly.
-  for (int i = 0; i < child_count(); ++i) {
-    const View* child = child_at(i);
+  for (const View* child : children()) {
     if (!child->visible())
       continue;
     if (child->id() == MenuItemView::kMenuItemViewID) {
diff --git a/ui/views/controls/native/native_view_host.cc b/ui/views/controls/native/native_view_host.cc
index 3ec401e..e64c679 100644
--- a/ui/views/controls/native/native_view_host.cc
+++ b/ui/views/controls/native/native_view_host.cc
@@ -33,12 +33,6 @@
   DCHECK(!native_view_);
   native_view_ = native_view;
   native_wrapper_->AttachNativeView();
-  // This does not use InvalidateLayout() to ensure the visibility state of
-  // the NativeView is correctly set (if this View isn't visible, Layout()
-  // won't, be called, resulting in the NativeView potentially having the wrong
-  // visibility state).
-  // TODO(https://crbug.com/947051): inestigate removing updating visibility
-  // immediately and calling InvalidateLayout() to update bounds.
   Layout();
 
   Widget* widget = Widget::GetWidgetForNativeView(native_view);
@@ -156,8 +150,6 @@
 }
 
 void NativeViewHost::VisibilityChanged(View* starting_from, bool is_visible) {
-  // This does not use InvalidateLayout() to ensure the visibility state is
-  // correctly set (if this View isn't visible, Layout() won't be called).
   Layout();
 }
 
@@ -169,7 +161,7 @@
 }
 
 void NativeViewHost::OnVisibleBoundsChanged() {
-  InvalidateLayout();
+  Layout();
 }
 
 void NativeViewHost::ViewHierarchyChanged(
diff --git a/ui/views/controls/native/native_view_host_aura.cc b/ui/views/controls/native/native_view_host_aura.cc
index c15db47..f11658d 100644
--- a/ui/views/controls/native/native_view_host_aura.cc
+++ b/ui/views/controls/native/native_view_host_aura.cc
@@ -144,7 +144,7 @@
     host_->native_view()->Show();
   else
     host_->native_view()->Hide();
-  host_->InvalidateLayout();
+  host_->Layout();
 }
 
 void NativeViewHostAura::RemovedFromWidget() {
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc
index 0cf1032..5518ed93 100644
--- a/ui/views/controls/scroll_view.cc
+++ b/ui/views/controls/scroll_view.cc
@@ -135,8 +135,6 @@
     scroll_view_->ScrollContentsRegionToBeVisible(scroll_rect);
   }
 
-  // TODO(https://crbug.com/947053): this override should not be necessary, but
-  // there are some assumptions that this calls Layout().
   void ChildPreferredSizeChanged(View* child) override {
     if (parent())
       parent()->Layout();
@@ -703,9 +701,6 @@
     *member = parent->AddChildView(std::move(new_view));
   else
     *member = nullptr;
-  // TODO(https://crbug.com/947053): this should call InvalidateLayout(), but
-  // there are some assumptions that it call Layout(). These assumptions should
-  // be updated.
   Layout();
 }
 
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc
index c2f68dc..6ca5557 100644
--- a/ui/views/controls/scroll_view_unittest.cc
+++ b/ui/views/controls/scroll_view_unittest.cc
@@ -27,7 +27,6 @@
 #include "ui/views/test/test_views.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/test/widget_test.h"
-#include "ui/views/view_test_api.h"
 
 #if defined(OS_MACOSX)
 #include "ui/base/test/scoped_preferred_scroller_style_mac.h"
@@ -43,19 +42,19 @@
   explicit ScrollViewTestApi(ScrollView* scroll_view)
       : scroll_view_(scroll_view) {}
 
-  BaseScrollBar* GetBaseScrollBar(ScrollBarOrientation orientation) {
+  ScrollBar* GetScrollBar(ScrollBarOrientation orientation) {
     ScrollBar* scroll_bar = orientation == VERTICAL ? scroll_view_->vert_sb_
                                                     : scroll_view_->horiz_sb_;
-    return static_cast<BaseScrollBar*>(scroll_bar);
+    return static_cast<ScrollBar*>(scroll_bar);
   }
 
   const base::OneShotTimer& GetScrollBarTimer(
       ScrollBarOrientation orientation) {
-    return GetBaseScrollBar(orientation)->repeater_.timer_for_testing();
+    return GetScrollBar(orientation)->repeater_.timer_for_testing();
   }
 
   BaseScrollBarThumb* GetScrollBarThumb(ScrollBarOrientation orientation) {
-    return GetBaseScrollBar(orientation)->thumb_;
+    return GetScrollBar(orientation)->thumb_;
   }
 
   gfx::Point IntegralViewOffset() {
@@ -66,7 +65,7 @@
 
   base::RetainingOneShotTimer* GetScrollBarHideTimer(
       ScrollBarOrientation orientation) {
-    return BaseScrollBar::GetHideTimerForTest(GetBaseScrollBar(orientation));
+    return ScrollBar::GetHideTimerForTesting(GetScrollBar(orientation));
   }
 
   View* corner_view() { return scroll_view_->corner_view_; }
@@ -568,8 +567,6 @@
 
   // Get the header a height of 20.
   header->SetPreferredSize(gfx::Size(10, 20));
-  EXPECT_TRUE(ViewTestApi(scroll_view_.get()).needs_layout());
-  scroll_view_->Layout();
   EXPECT_EQ("0,0 100x20", header->parent()->bounds().ToString());
   EXPECT_EQ("0,20 100x80", contents->parent()->bounds().ToString());
   if (contents->layer()) {
@@ -672,13 +669,13 @@
 
   // Scroll the horizontal scrollbar.
   ASSERT_TRUE(scroll_view_->horizontal_scroll_bar());
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 1);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(HORIZONTAL), 1);
   EXPECT_EQ("-1,0", test_api.IntegralViewOffset().ToString());
   EXPECT_EQ("-1,0", header->origin().ToString());
 
   // Scrolling the vertical scrollbar shouldn't effect the header.
   ASSERT_TRUE(scroll_view_->vertical_scroll_bar());
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 1);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), 1);
   EXPECT_EQ("-1,-1", test_api.IntegralViewOffset().ToString());
   EXPECT_EQ("-1,0", header->origin().ToString());
 }
@@ -693,7 +690,7 @@
   // should be updated (i.e. it should be non-zero).
   contents->SetBounds(0, 0, 400, 50);
   scroll_view_->Layout();
-  auto* scroll_bar = test_api.GetBaseScrollBar(HORIZONTAL);
+  auto* scroll_bar = test_api.GetScrollBar(HORIZONTAL);
   ASSERT_TRUE(scroll_bar);
   EXPECT_TRUE(scroll_bar->visible());
   EXPECT_EQ(0, scroll_bar->GetPosition());
@@ -703,7 +700,7 @@
   // Scroll the vertical scrollbar.
   contents->SetBounds(0, 0, 50, 400);
   scroll_view_->Layout();
-  scroll_bar = test_api.GetBaseScrollBar(VERTICAL);
+  scroll_bar = test_api.GetScrollBar(VERTICAL);
   ASSERT_TRUE(scroll_bar);
   EXPECT_TRUE(scroll_bar->visible());
   EXPECT_EQ(0, scroll_bar->GetPosition());
@@ -992,8 +989,6 @@
   // Switch to the non-overlay style and check that the ViewPort is now sized
   // to be smaller, and ScrollbarWidth and ScrollbarHeight are non-zero.
   SetOverlayScrollersEnabled(false);
-  EXPECT_TRUE(ViewTestApi(scroll_view_.get()).needs_layout());
-  scroll_view_->Layout();
   EXPECT_EQ(100 - VerticalScrollBarWidth(), contents->parent()->width());
   EXPECT_EQ(100 - HorizontalScrollBarHeight(), contents->parent()->height());
   EXPECT_NE(0, VerticalScrollBarWidth());
@@ -1014,8 +1009,8 @@
   ScrollView* scroll_view = AddScrollViewWithContentSize(
       gfx::Size(kDefaultWidth * 5, kDefaultHeight * 5));
   ScrollViewTestApi test_api(scroll_view);
-  BaseScrollBar* bar[]{test_api.GetBaseScrollBar(HORIZONTAL),
-                       test_api.GetBaseScrollBar(VERTICAL)};
+  ScrollBar* bar[]{test_api.GetScrollBar(HORIZONTAL),
+                   test_api.GetScrollBar(VERTICAL)};
   base::RetainingOneShotTimer* hide_timer[] = {
       test_api.GetScrollBarHideTimer(HORIZONTAL),
       test_api.GetScrollBarHideTimer(VERTICAL)};
@@ -1132,7 +1127,7 @@
   EXPECT_EQ(gfx::Size(300, 150), scroll_view_->size());
 
   // Scroll down.
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 25);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), 25);
   EXPECT_EQ(25, test_api.CurrentOffset().y());
   // Call Layout; no change to scroll position.
   scroll_view_->Layout();
@@ -1164,9 +1159,8 @@
   scroll_view_->ClipHeightTo(0, kMaxHeight);
 
   // Make sure the size is set such that no horizontal scrollbar gets shown.
-  scroll_view_->SetSize(
-      gfx::Size(kWidth + test_api.GetBaseScrollBar(VERTICAL)->GetThickness(),
-                kMaxHeight));
+  scroll_view_->SetSize(gfx::Size(
+      kWidth + test_api.GetScrollBar(VERTICAL)->GetThickness(), kMaxHeight));
 
   // Make sure the initial origin is 0,0
   EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset());
@@ -1188,7 +1182,7 @@
 
   // Now scroll the view to someplace in the middle of the scrollable region.
   int offset = kMaxHeight * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
 
   // At this point, both overflow indicators on the top and bottom should be
@@ -1202,7 +1196,7 @@
 
   // Finally scroll the view to end of the scrollable region.
   offset = kMaxHeight * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
 
   // The overflow indicator on the bottom should not be visible.
@@ -1228,7 +1222,7 @@
 
   // Make sure the size is set such that no vertical scrollbar gets shown.
   scroll_view_->SetSize(gfx::Size(
-      kWidth, kHeight + test_api.GetBaseScrollBar(HORIZONTAL)->GetThickness()));
+      kWidth, kHeight + test_api.GetScrollBar(HORIZONTAL)->GetThickness()));
 
   contents->SetBounds(0, 0, kWidth * 5, kHeight);
 
@@ -1252,7 +1246,7 @@
 
   // Now scroll the view to someplace in the middle of the scrollable region.
   int offset = kWidth * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(HORIZONTAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(offset, 0), test_api.CurrentOffset());
 
   // At this point, both overflow indicators on the left and right should be
@@ -1266,7 +1260,7 @@
 
   // Finally scroll the view to end of the scrollable region.
   offset = kWidth * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(HORIZONTAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(offset, 0), test_api.CurrentOffset());
 
   // The overflow indicator on the right should not be visible.
@@ -1313,8 +1307,7 @@
   // Now scroll the view to someplace in the middle of the horizontal scrollable
   // region.
   int offset_x = kWidth * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
-                                 offset_x);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(HORIZONTAL), offset_x);
   EXPECT_EQ(gfx::ScrollOffset(offset_x, 0), test_api.CurrentOffset());
 
   // Since there is a vertical scrollbar only the overflow indicator on the left
@@ -1328,8 +1321,7 @@
 
   // Next, scroll the view to end of the scrollable region.
   offset_x = kWidth * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
-                                 offset_x);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(HORIZONTAL), offset_x);
   EXPECT_EQ(gfx::ScrollOffset(offset_x, 0), test_api.CurrentOffset());
 
   // The overflow indicator on the right should still not be visible.
@@ -1345,7 +1337,7 @@
   EXPECT_FALSE(test_api.more_content_bottom()->visible());
 
   // Return the view back to the horizontal origin.
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 0);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(HORIZONTAL), 0);
   EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset());
 
   // The overflow indicators on the right and bottom should not be visible since
@@ -1361,7 +1353,7 @@
   // Now scroll the view to somplace in the middle of the vertical scrollable
   // region.
   int offset_y = kHeight * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), offset_y);
   EXPECT_EQ(gfx::ScrollOffset(0, offset_y), test_api.CurrentOffset());
 
   // Similar to the above, since there is a horizontal scrollbar only the
@@ -1376,7 +1368,7 @@
 
   // Finally, for the vertical test scroll the region all the way to the end.
   offset_y = kHeight * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), offset_y);
   EXPECT_EQ(gfx::ScrollOffset(0, offset_y), test_api.CurrentOffset());
 
   // The overflow indicator on the bottom should still not be visible.
@@ -1394,8 +1386,7 @@
   // Back to the horizontal. Scroll all the way to the end in the horizontal
   // direction.
   offset_x = kWidth * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
-                                 offset_x);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(HORIZONTAL), offset_x);
   EXPECT_EQ(gfx::ScrollOffset(offset_x, offset_y), test_api.CurrentOffset());
 
   // The overflow indicator on the bottom and right should still not be visible.
@@ -1423,7 +1414,7 @@
 
   // Make sure the size is set such that no horizontal scrollbar gets shown.
   scroll_view_->SetSize(
-      gfx::Size(kWidth + test_api.GetBaseScrollBar(VERTICAL)->GetThickness(),
+      gfx::Size(kWidth + test_api.GetScrollBar(VERTICAL)->GetThickness(),
                 kMaxHeight + header_ptr->height()));
 
   // Make sure the initial origin is 0,0
@@ -1446,7 +1437,7 @@
 
   // Now scroll the view to someplace in the middle of the scrollable region.
   int offset = kMaxHeight * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
 
   // At this point, only the overflow indicator on the bottom should be visible
@@ -1460,8 +1451,8 @@
   EXPECT_FALSE(test_api.more_content_right()->visible());
 
   // Finally scroll the view to end of the scrollable region.
-  offset = test_api.GetBaseScrollBar(VERTICAL)->GetMaxPosition();
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+  offset = test_api.GetScrollBar(VERTICAL)->GetMaxPosition();
+  scroll_view_->ScrollToPosition(test_api.GetScrollBar(VERTICAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
 
   // The overflow indicator on the bottom should not be visible now.
@@ -1481,7 +1472,7 @@
   ScrollView* scroll_view =
       AddScrollViewWithContentSize(gfx::Size(10, kDefaultHeight * 5));
   ScrollViewTestApi test_api(scroll_view);
-  BaseScrollBar* scroll_bar = test_api.GetBaseScrollBar(VERTICAL);
+  ScrollBar* scroll_bar = test_api.GetScrollBar(VERTICAL);
   View* thumb = test_api.GetScrollBarThumb(VERTICAL);
 
   // Click in the middle of the track, ensuring it's below the thumb.
diff --git a/ui/views/controls/scrollbar/base_scroll_bar.cc b/ui/views/controls/scrollbar/base_scroll_bar.cc
deleted file mode 100644
index bb31c72d..0000000
--- a/ui/views/controls/scrollbar/base_scroll_bar.cc
+++ /dev/null
@@ -1,478 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/scrollbar/base_scroll_bar.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/events/event.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/geometry/safe_integer_conversions.h"
-#include "ui/strings/grit/ui_strings.h"
-#include "ui/views/controls/menu/menu_item_view.h"
-#include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/controls/scroll_view.h"
-#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-///////////////////////////////////////////////////////////////////////////////
-// BaseScrollBar, public:
-
-BaseScrollBar::BaseScrollBar(bool horizontal)
-    : ScrollBar(horizontal),
-      thumb_(nullptr),
-      contents_size_(0),
-      contents_scroll_offset_(0),
-      viewport_size_(0),
-      last_scroll_amount_(SCROLL_NONE),
-      repeater_(base::BindRepeating(&BaseScrollBar::TrackClicked,
-                                    base::Unretained(this))),
-      context_menu_mouse_position_(0) {
-  set_context_menu_controller(this);
-}
-
-BaseScrollBar::~BaseScrollBar() = default;
-
-void BaseScrollBar::SetThumb(BaseScrollBarThumb* thumb) {
-  DCHECK(!thumb_);
-  thumb_ = thumb;
-  AddChildView(thumb);
-  thumb->set_context_menu_controller(this);
-}
-
-void BaseScrollBar::ScrollByAmount(ScrollAmount amount) {
-  int offset = contents_scroll_offset_;
-  switch (amount) {
-    case SCROLL_START:
-      offset = GetMinPosition();
-      break;
-    case SCROLL_END:
-      offset = GetMaxPosition();
-      break;
-    case SCROLL_PREV_LINE:
-      offset -= GetScrollIncrement(false, false);
-      offset = std::max(GetMinPosition(), offset);
-      break;
-    case SCROLL_NEXT_LINE:
-      offset += GetScrollIncrement(false, true);
-      offset = std::min(GetMaxPosition(), offset);
-      break;
-    case SCROLL_PREV_PAGE:
-      offset -= GetScrollIncrement(true, false);
-      offset = std::max(GetMinPosition(), offset);
-      break;
-    case SCROLL_NEXT_PAGE:
-      offset += GetScrollIncrement(true, true);
-      offset = std::min(GetMaxPosition(), offset);
-      break;
-    default:
-      break;
-  }
-  contents_scroll_offset_ = offset;
-  ScrollContentsToOffset();
-}
-
-void BaseScrollBar::ScrollToThumbPosition(int thumb_position,
-                                          bool scroll_to_middle) {
-  contents_scroll_offset_ = CalculateContentsOffset(
-      static_cast<float>(thumb_position), scroll_to_middle);
-  if (contents_scroll_offset_ < GetMinPosition()) {
-    contents_scroll_offset_ = GetMinPosition();
-  } else if (contents_scroll_offset_ > GetMaxPosition()) {
-    contents_scroll_offset_ = GetMaxPosition();
-  }
-  ScrollContentsToOffset();
-  SchedulePaint();
-}
-
-bool BaseScrollBar::ScrollByContentsOffset(int contents_offset) {
-  int old_offset = contents_scroll_offset_;
-  contents_scroll_offset_ -= contents_offset;
-  if (contents_scroll_offset_ < GetMinPosition()) {
-    contents_scroll_offset_ = GetMinPosition();
-  } else if (contents_scroll_offset_ > GetMaxPosition()) {
-    contents_scroll_offset_ = GetMaxPosition();
-  }
-  if (old_offset == contents_scroll_offset_)
-    return false;
-
-  ScrollContentsToOffset();
-  return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BaseScrollBar, View implementation:
-
-bool BaseScrollBar::OnMousePressed(const ui::MouseEvent& event) {
-  if (event.IsOnlyLeftMouseButton())
-    ProcessPressEvent(event);
-  return true;
-}
-
-void BaseScrollBar::OnMouseReleased(const ui::MouseEvent& event) {
-  repeater_.Stop();
-}
-
-void BaseScrollBar::OnMouseCaptureLost() {
-  repeater_.Stop();
-}
-
-bool BaseScrollBar::OnKeyPressed(const ui::KeyEvent& event) {
-  ScrollAmount amount = SCROLL_NONE;
-  switch (event.key_code()) {
-    case ui::VKEY_UP:
-      if (!IsHorizontal())
-        amount = SCROLL_PREV_LINE;
-      break;
-    case ui::VKEY_DOWN:
-      if (!IsHorizontal())
-        amount = SCROLL_NEXT_LINE;
-      break;
-    case ui::VKEY_LEFT:
-      if (IsHorizontal())
-        amount = SCROLL_PREV_LINE;
-      break;
-    case ui::VKEY_RIGHT:
-      if (IsHorizontal())
-        amount = SCROLL_NEXT_LINE;
-      break;
-    case ui::VKEY_PRIOR:
-      amount = SCROLL_PREV_PAGE;
-      break;
-    case ui::VKEY_NEXT:
-      amount = SCROLL_NEXT_PAGE;
-      break;
-    case ui::VKEY_HOME:
-      amount = SCROLL_START;
-      break;
-    case ui::VKEY_END:
-      amount = SCROLL_END;
-      break;
-    default:
-      break;
-  }
-  if (amount != SCROLL_NONE) {
-    ScrollByAmount(amount);
-    return true;
-  }
-  return false;
-}
-
-bool BaseScrollBar::OnMouseWheel(const ui::MouseWheelEvent& event) {
-  OnScroll(event.x_offset(), event.y_offset());
-  return true;
-}
-
-void BaseScrollBar::OnGestureEvent(ui::GestureEvent* event) {
-  // If a fling is in progress, then stop the fling for any incoming gesture
-  // event (except for the GESTURE_END event that is generated at the end of the
-  // fling).
-  if (scroll_animator_.get() && scroll_animator_->is_scrolling() &&
-      (event->type() != ui::ET_GESTURE_END ||
-       event->details().touch_points() > 1)) {
-    scroll_animator_->Stop();
-  }
-
-  if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
-    ProcessPressEvent(*event);
-    event->SetHandled();
-    return;
-  }
-
-  if (event->type() == ui::ET_GESTURE_LONG_PRESS) {
-    // For a long-press, the repeater started in tap-down should continue. So
-    // return early.
-    return;
-  }
-
-  repeater_.Stop();
-
-  if (event->type() == ui::ET_GESTURE_TAP) {
-    // TAP_DOWN would have already scrolled some amount. So scrolling again on
-    // TAP is not necessary.
-    event->SetHandled();
-    return;
-  }
-
-  if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN ||
-      event->type() == ui::ET_GESTURE_SCROLL_END) {
-    event->SetHandled();
-    return;
-  }
-
-  if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
-    float scroll_amount_f;
-    int scroll_amount;
-    if (IsHorizontal()) {
-      scroll_amount_f = event->details().scroll_x() - roundoff_error_.x();
-      scroll_amount = gfx::ToRoundedInt(scroll_amount_f);
-      roundoff_error_.set_x(scroll_amount - scroll_amount_f);
-    } else {
-      scroll_amount_f = event->details().scroll_y() - roundoff_error_.y();
-      scroll_amount = gfx::ToRoundedInt(scroll_amount_f);
-      roundoff_error_.set_y(scroll_amount - scroll_amount_f);
-    }
-    if (ScrollByContentsOffset(scroll_amount))
-      event->SetHandled();
-    return;
-  }
-
-  if (event->type() == ui::ET_SCROLL_FLING_START) {
-    if (!scroll_animator_.get())
-      scroll_animator_ = std::make_unique<ScrollAnimator>(this);
-    scroll_animator_->Start(
-        IsHorizontal() ?  event->details().velocity_x() : 0.f,
-        IsHorizontal() ? 0.f : event->details().velocity_y());
-    event->SetHandled();
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BaseScrollBar, ScrollDelegate implementation:
-
-bool BaseScrollBar::OnScroll(float dx, float dy) {
-  return IsHorizontal() ? ScrollByContentsOffset(dx) :
-                          ScrollByContentsOffset(dy);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BaseScrollBar, ContextMenuController implementation:
-
-enum ScrollBarContextMenuCommands {
-  ScrollBarContextMenuCommand_ScrollHere = 1,
-  ScrollBarContextMenuCommand_ScrollStart,
-  ScrollBarContextMenuCommand_ScrollEnd,
-  ScrollBarContextMenuCommand_ScrollPageUp,
-  ScrollBarContextMenuCommand_ScrollPageDown,
-  ScrollBarContextMenuCommand_ScrollPrev,
-  ScrollBarContextMenuCommand_ScrollNext
-};
-
-void BaseScrollBar::ShowContextMenuForViewImpl(View* source,
-                                               const gfx::Point& p,
-                                               ui::MenuSourceType source_type) {
-  Widget* widget = GetWidget();
-  gfx::Rect widget_bounds = widget->GetWindowBoundsInScreen();
-  gfx::Point temp_pt(p.x() - widget_bounds.x(), p.y() - widget_bounds.y());
-  View::ConvertPointFromWidget(this, &temp_pt);
-  context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y();
-
-  if (!menu_model_) {
-    menu_model_ = std::make_unique<ui::SimpleMenuModel>(this);
-    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollHere,
-                                     IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE);
-    menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
-    menu_model_->AddItemWithStringId(
-        ScrollBarContextMenuCommand_ScrollStart,
-        IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE
-                       : IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME);
-    menu_model_->AddItemWithStringId(
-        ScrollBarContextMenuCommand_ScrollEnd,
-        IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE
-                       : IDS_APP_SCROLLBAR_CXMENU_SCROLLEND);
-    menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
-    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPageUp,
-                                     IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP);
-    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPageDown,
-                                     IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN);
-    menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
-    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPrev,
-                                     IsHorizontal()
-                                         ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT
-                                         : IDS_APP_SCROLLBAR_CXMENU_SCROLLUP);
-    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollNext,
-                                     IsHorizontal()
-                                         ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT
-                                         : IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN);
-  }
-  menu_runner_ = std::make_unique<MenuRunner>(
-      menu_model_.get(),
-      MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU);
-  menu_runner_->RunMenuAt(GetWidget(), nullptr, gfx::Rect(p, gfx::Size()),
-                          MenuAnchorPosition::kTopLeft, source_type);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BaseScrollBar, Menu::Delegate implementation:
-
-bool BaseScrollBar::IsCommandIdEnabled(int id) const {
-  switch (id) {
-    case ScrollBarContextMenuCommand_ScrollPageUp:
-    case ScrollBarContextMenuCommand_ScrollPageDown:
-      return !IsHorizontal();
-  }
-  return true;
-}
-
-bool BaseScrollBar::IsCommandIdChecked(int id) const {
-  return false;
-}
-
-void BaseScrollBar::ExecuteCommand(int id, int event_flags) {
-  switch (id) {
-    case ScrollBarContextMenuCommand_ScrollHere:
-      ScrollToThumbPosition(context_menu_mouse_position_, true);
-      break;
-    case ScrollBarContextMenuCommand_ScrollStart:
-      ScrollByAmount(SCROLL_START);
-      break;
-    case ScrollBarContextMenuCommand_ScrollEnd:
-      ScrollByAmount(SCROLL_END);
-      break;
-    case ScrollBarContextMenuCommand_ScrollPageUp:
-      ScrollByAmount(SCROLL_PREV_PAGE);
-      break;
-    case ScrollBarContextMenuCommand_ScrollPageDown:
-      ScrollByAmount(SCROLL_NEXT_PAGE);
-      break;
-    case ScrollBarContextMenuCommand_ScrollPrev:
-      ScrollByAmount(SCROLL_PREV_LINE);
-      break;
-    case ScrollBarContextMenuCommand_ScrollNext:
-      ScrollByAmount(SCROLL_NEXT_LINE);
-      break;
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BaseScrollBar, ScrollBar implementation:
-
-void BaseScrollBar::Update(int viewport_size,
-                           int content_size,
-                           int contents_scroll_offset) {
-  ScrollBar::Update(viewport_size, content_size, contents_scroll_offset);
-
-  // Make sure contents_size is always > 0 to avoid divide by zero errors in
-  // calculations throughout this code.
-  contents_size_ = std::max(1, content_size);
-
-  viewport_size_ = std::max(1, viewport_size);
-
-  if (content_size < 0)
-    content_size = 0;
-  if (contents_scroll_offset < 0)
-    contents_scroll_offset = 0;
-  if (contents_scroll_offset > content_size)
-    contents_scroll_offset = content_size;
-  contents_scroll_offset_ = contents_scroll_offset;
-
-  // Thumb Height and Thumb Pos.
-  // The height of the thumb is the ratio of the Viewport height to the
-  // content size multiplied by the height of the thumb track.
-  double ratio =
-      std::min(1.0, static_cast<double>(viewport_size) / contents_size_);
-  thumb_->SetLength(static_cast<int>(ratio * GetTrackSize()));
-
-  int thumb_position = CalculateThumbPosition(contents_scroll_offset);
-  thumb_->SetPosition(thumb_position);
-}
-
-int BaseScrollBar::GetPosition() const {
-  return thumb_->GetPosition();
-}
-
-bool BaseScrollBar::OverlapsContent() const {
-  return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BaseScrollBar, protected:
-
-BaseScrollBarThumb* BaseScrollBar::GetThumb() const {
-  return thumb_;
-}
-
-void BaseScrollBar::ScrollToPosition(int position) {
-  controller()->ScrollToPosition(this, position);
-}
-
-int BaseScrollBar::GetScrollIncrement(bool is_page, bool is_positive) {
-  return controller()->GetScrollIncrement(this, is_page, is_positive);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BaseScrollBar, private:
-
-#if !defined(OS_MACOSX)
-// static
-base::RetainingOneShotTimer* BaseScrollBar::GetHideTimerForTest(
-    BaseScrollBar* scroll_bar) {
-  return nullptr;
-}
-#endif
-
-int BaseScrollBar::GetThumbSizeForTest() {
-  return thumb_->GetSize();
-}
-
-void BaseScrollBar::ProcessPressEvent(const ui::LocatedEvent& event) {
-  gfx::Rect thumb_bounds = thumb_->bounds();
-  if (IsHorizontal()) {
-    if (GetMirroredXInView(event.x()) < thumb_bounds.x()) {
-      last_scroll_amount_ = SCROLL_PREV_PAGE;
-    } else if (GetMirroredXInView(event.x()) > thumb_bounds.right()) {
-      last_scroll_amount_ = SCROLL_NEXT_PAGE;
-    }
-  } else {
-    if (event.y() < thumb_bounds.y()) {
-      last_scroll_amount_ = SCROLL_PREV_PAGE;
-    } else if (event.y() > thumb_bounds.bottom()) {
-      last_scroll_amount_ = SCROLL_NEXT_PAGE;
-    }
-  }
-  TrackClicked();
-  repeater_.Start();
-}
-
-void BaseScrollBar::TrackClicked() {
-  if (last_scroll_amount_ != SCROLL_NONE)
-    ScrollByAmount(last_scroll_amount_);
-}
-
-void BaseScrollBar::ScrollContentsToOffset() {
-  ScrollToPosition(contents_scroll_offset_);
-  thumb_->SetPosition(CalculateThumbPosition(contents_scroll_offset_));
-}
-
-int BaseScrollBar::GetTrackSize() const {
-  gfx::Rect track_bounds = GetTrackBounds();
-  return IsHorizontal() ? track_bounds.width() : track_bounds.height();
-}
-
-int BaseScrollBar::CalculateThumbPosition(int contents_scroll_offset) const {
-  // In some combination of viewport_size and contents_size_, the result of
-  // simple division can be rounded and there could be 1 pixel gap even when the
-  // contents scroll down to the bottom. See crbug.com/244671
-  int thumb_max = GetTrackSize() - thumb_->GetSize();
-  if (contents_scroll_offset + viewport_size_ == contents_size_)
-    return thumb_max;
-  return (contents_scroll_offset * thumb_max) /
-         (contents_size_ - viewport_size_);
-}
-
-int BaseScrollBar::CalculateContentsOffset(float thumb_position,
-                                           bool scroll_to_middle) const {
-  float thumb_size = static_cast<float>(thumb_->GetSize());
-  int track_size = GetTrackSize();
-  if (track_size == thumb_size)
-    return 0;
-  if (scroll_to_middle)
-    thumb_position = thumb_position - (thumb_size / 2);
-  float result = (thumb_position * (contents_size_ - viewport_size_)) /
-                 (track_size - thumb_size);
-  return static_cast<int>(result);
-}
-
-}  // namespace views
diff --git a/ui/views/controls/scrollbar/base_scroll_bar.h b/ui/views/controls/scrollbar/base_scroll_bar.h
deleted file mode 100644
index bdf2f1e1..0000000
--- a/ui/views/controls/scrollbar/base_scroll_bar.h
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_H_
-#define UI_VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_H_
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "ui/base/models/simple_menu_model.h"
-#include "ui/views/animation/scroll_animator.h"
-#include "ui/views/context_menu_controller.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/scrollbar/scroll_bar.h"
-#include "ui/views/repeat_controller.h"
-
-namespace views {
-namespace test {
-class ScrollViewTestApi;
-}
-
-class BaseScrollBarThumb;
-class MenuRunner;
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// BaseScrollBar
-//
-///////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
-                                   public ScrollDelegate,
-                                   public ContextMenuController,
-                                   public ui::SimpleMenuModel::Delegate {
- public:
-  explicit BaseScrollBar(bool horizontal);
-  ~BaseScrollBar() override;
-
-  void SetThumb(BaseScrollBarThumb* thumb);
-
-  // Get the bounds of the "track" area that the thumb is free to slide within.
-  virtual gfx::Rect GetTrackBounds() const = 0;
-
-  // An enumeration of different amounts of incremental scroll, representing
-  // events sent from different parts of the UI/keyboard.
-  enum ScrollAmount {
-    SCROLL_NONE = 0,
-    SCROLL_START,
-    SCROLL_END,
-    SCROLL_PREV_LINE,
-    SCROLL_NEXT_LINE,
-    SCROLL_PREV_PAGE,
-    SCROLL_NEXT_PAGE,
-  };
-
-  // Scroll the contents by the specified type (see ScrollAmount above).
-  void ScrollByAmount(ScrollAmount amount);
-
-  // Scroll the contents to the appropriate position given the supplied
-  // position of the thumb (thumb track coordinates). If |scroll_to_middle| is
-  // true, then the conversion assumes |thumb_position| is in the middle of the
-  // thumb rather than the top.
-  void ScrollToThumbPosition(int thumb_position, bool scroll_to_middle);
-
-  // Scroll the contents by the specified offset (contents coordinates).
-  bool ScrollByContentsOffset(int contents_offset);
-
-  // View overrides:
-  bool OnMousePressed(const ui::MouseEvent& event) override;
-  void OnMouseReleased(const ui::MouseEvent& event) override;
-  void OnMouseCaptureLost() override;
-  bool OnKeyPressed(const ui::KeyEvent& event) override;
-  bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
-
-  // ui::EventHandler overrides:
-  void OnGestureEvent(ui::GestureEvent* event) override;
-
-  // ScrollBar overrides:
-  void Update(int viewport_size,
-              int content_size,
-              int contents_scroll_offset) override;
-  int GetPosition() const override;
-  int GetThickness() const override = 0;
-  bool OverlapsContent() const override;
-
-  // ScrollDelegate overrides:
-  bool OnScroll(float dx, float dy) override;
-
-  // ContextMenuController overrides:
-  void ShowContextMenuForViewImpl(View* source,
-                                  const gfx::Point& point,
-                                  ui::MenuSourceType source_type) override;
-
-  // ui::SimpleMenuModel::Delegate overrides:
-  bool IsCommandIdChecked(int id) const override;
-  bool IsCommandIdEnabled(int id) const override;
-  void ExecuteCommand(int id, int event_flags) override;
-
- protected:
-  BaseScrollBarThumb* GetThumb() const;
-
-  // Wrapper functions that calls the controller. We need this since native
-  // scrollbars wrap around a different scrollbar. When calling the controller
-  // we need to pass in the appropriate scrollbar. For normal scrollbars it's
-  // the |this| scrollbar, for native scrollbars it's the native scrollbar used
-  // to create this.
-  virtual void ScrollToPosition(int position);
-  virtual int GetScrollIncrement(bool is_page, bool is_positive);
-
- private:
-  friend class test::ScrollViewTestApi;
-
-  FRIEND_TEST_ALL_PREFIXES(ScrollBarViewsTest, ScrollBarFitsToBottom);
-  FRIEND_TEST_ALL_PREFIXES(ScrollBarViewsTest, ThumbFullLengthOfTrack);
-  static base::RetainingOneShotTimer* GetHideTimerForTest(
-      BaseScrollBar* scroll_bar);
-  int GetThumbSizeForTest();
-
-  // Changes to 'pushed' state and starts a timer to scroll repeatedly.
-  void ProcessPressEvent(const ui::LocatedEvent& event);
-
-  // Called when the mouse is pressed down in the track area.
-  void TrackClicked();
-
-  // Responsible for scrolling the contents and also updating the UI to the
-  // current value of the Scroll Offset.
-  void ScrollContentsToOffset();
-
-  // Returns the size (width or height) of the track area of the ScrollBar.
-  int GetTrackSize() const;
-
-  // Calculate the position of the thumb within the track based on the
-  // specified scroll offset of the contents.
-  int CalculateThumbPosition(int contents_scroll_offset) const;
-
-  // Calculates the current value of the contents offset (contents coordinates)
-  // based on the current thumb position (thumb track coordinates). See
-  // |ScrollToThumbPosition| for an explanation of |scroll_to_middle|.
-  int CalculateContentsOffset(float thumb_position,
-                              bool scroll_to_middle) const;
-
-  // Called when the state of the thumb track changes (e.g. by the user
-  // pressing the mouse button down in it).
-  void SetThumbTrackState(Button::ButtonState state);
-
-  BaseScrollBarThumb* thumb_;
-
-  // The size of the scrolled contents, in pixels.
-  int contents_size_;
-
-  // The current amount the contents is offset by in the viewport.
-  int contents_scroll_offset_;
-
-  // The current size of the view port, in pixels.
-  int viewport_size_;
-
-  // The last amount of incremental scroll that this scrollbar performed. This
-  // is accessed by the callbacks for the auto-repeat up/down buttons to know
-  // what direction to repeatedly scroll in.
-  ScrollAmount last_scroll_amount_;
-
-  // An instance of a RepeatController which scrolls the scrollbar continuously
-  // as the user presses the mouse button down on the up/down buttons or the
-  // track.
-  RepeatController repeater_;
-
-  // The position of the mouse within the scroll bar when the context menu
-  // was invoked.
-  int context_menu_mouse_position_;
-
-  std::unique_ptr<ui::SimpleMenuModel> menu_model_;
-  std::unique_ptr<MenuRunner> menu_runner_;
-  std::unique_ptr<ScrollAnimator> scroll_animator_;
-
-  // Difference between current position and cumulative deltas obtained from
-  // scroll update events.
-  // TODO(tdresser): This should be removed when raw pixel scrolling for views
-  // is enabled. See crbug.com/329354.
-  gfx::Vector2dF roundoff_error_;
-
-  DISALLOW_COPY_AND_ASSIGN(BaseScrollBar);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_H_
diff --git a/ui/views/controls/scrollbar/base_scroll_bar_thumb.cc b/ui/views/controls/scrollbar/base_scroll_bar_thumb.cc
index aec1188..f6f78dbd 100644
--- a/ui/views/controls/scrollbar/base_scroll_bar_thumb.cc
+++ b/ui/views/controls/scrollbar/base_scroll_bar_thumb.cc
@@ -6,7 +6,7 @@
 
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/views/controls/scrollbar/base_scroll_bar.h"
+#include "ui/views/controls/scrollbar/scroll_bar.h"
 
 namespace {
 // The distance the mouse can be dragged outside the bounds of the thumb during
@@ -16,7 +16,7 @@
 
 namespace views {
 
-BaseScrollBarThumb::BaseScrollBarThumb(BaseScrollBar* scroll_bar)
+BaseScrollBarThumb::BaseScrollBarThumb(ScrollBar* scroll_bar)
     : scroll_bar_(scroll_bar),
       drag_start_position_(-1),
       mouse_offset_(-1),
diff --git a/ui/views/controls/scrollbar/base_scroll_bar_thumb.h b/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
index bf4fccc..a8f29da 100644
--- a/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
+++ b/ui/views/controls/scrollbar/base_scroll_bar_thumb.h
@@ -17,7 +17,7 @@
 
 namespace views {
 
-class BaseScrollBar;
+class ScrollBar;
 
 ///////////////////////////////////////////////////////////////////////////////
 //
@@ -29,7 +29,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 class VIEWS_EXPORT BaseScrollBarThumb : public View {
  public:
-  explicit BaseScrollBarThumb(BaseScrollBar* scroll_bar);
+  explicit BaseScrollBarThumb(ScrollBar* scroll_bar);
   ~BaseScrollBarThumb() override;
 
   // Sets the length (width or height) of the thumb to the specified value.
@@ -64,11 +64,11 @@
 
   bool IsHorizontal() const;
 
-  BaseScrollBar* scroll_bar() { return scroll_bar_; }
+  ScrollBar* scroll_bar() { return scroll_bar_; }
 
  private:
-  // The BaseScrollBar that owns us.
-  BaseScrollBar* scroll_bar_;
+  // The ScrollBar that owns us.
+  ScrollBar* scroll_bar_;
 
   int drag_start_position_;
 
diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.h b/ui/views/controls/scrollbar/cocoa_scroll_bar.h
index cf3fb10..b4ae90e 100644
--- a/ui/views/controls/scrollbar/cocoa_scroll_bar.h
+++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.h
@@ -10,7 +10,7 @@
 #include "base/timer/timer.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/gfx/animation/slide_animation.h"
-#include "ui/views/controls/scrollbar/base_scroll_bar.h"
+#include "ui/views/controls/scrollbar/scroll_bar.h"
 #include "ui/views/views_export.h"
 #import "ui/views_bridge_mac/views_scrollbar_bridge.h"
 
@@ -19,7 +19,7 @@
 class CocoaScrollBarThumb;
 
 // The transparent scrollbar for Mac which overlays its contents.
-class VIEWS_EXPORT CocoaScrollBar : public BaseScrollBar,
+class VIEWS_EXPORT CocoaScrollBar : public ScrollBar,
                                     public ViewsScrollbarBridgeDelegate,
                                     public ui::ImplicitAnimationObserver,
                                     public gfx::AnimationDelegate {
@@ -59,7 +59,7 @@
   bool IsScrollbarFullyHidden() const;
 
  protected:
-  // BaseScrollBar:
+  // ScrollBar:
   gfx::Rect GetTrackBounds() const override;
 
   // ScrollBar:
@@ -72,7 +72,7 @@
   void OnPaint(gfx::Canvas* canvas) override;
 
  private:
-  friend class BaseScrollBar;  // For BaseScrollBar::GetHideTimerForTest().
+  friend class ScrollBar;  // For ScrollBar::GetHideTimerForTesting().
 
   // Methods to change the visibility of the scrollbar.
   void ShowScrollbar();
diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.mm b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
index 568b120..99a0392 100644
--- a/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
+++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
@@ -178,7 +178,7 @@
 // CocoaScrollBar class
 
 CocoaScrollBar::CocoaScrollBar(bool horizontal)
-    : BaseScrollBar(horizontal),
+    : ScrollBar(horizontal),
       hide_scrollbar_timer_(
           FROM_HERE,
           base::TimeDelta::FromMilliseconds(kScrollbarHideTimeoutMs),
@@ -204,7 +204,7 @@
 }
 
 //////////////////////////////////////////////////////////////////
-// CocoaScrollBar, BaseScrollBar:
+// CocoaScrollBar, ScrollBar:
 
 gfx::Rect CocoaScrollBar::GetTrackBounds() const {
   return GetLocalBounds();
@@ -226,7 +226,7 @@
 
 void CocoaScrollBar::Layout() {
   // Set the thickness of the thumb according to the track bounds.
-  // The length of the thumb is set by BaseScrollBar::Update().
+  // The length of the thumb is set by ScrollBar::Update().
   gfx::Rect thumb_bounds(GetThumb()->bounds());
   gfx::Rect track_bounds(GetTrackBounds());
   if (IsHorizontal()) {
@@ -292,12 +292,12 @@
   if (IsScrollbarFullyHidden())
     return false;
 
-  return BaseScrollBar::OnMousePressed(event);
+  return ScrollBar::OnMousePressed(event);
 }
 
 void CocoaScrollBar::OnMouseReleased(const ui::MouseEvent& event) {
   ResetOverlayScrollbar();
-  BaseScrollBar::OnMouseReleased(event);
+  ScrollBar::OnMouseReleased(event);
 }
 
 void CocoaScrollBar::OnMouseEntered(const ui::MouseEvent& event) {
@@ -339,7 +339,7 @@
                             int contents_scroll_offset) {
   // TODO(tapted): Pass in overscroll amounts from the Layer and "Squish" the
   // scroller thumb accordingly.
-  BaseScrollBar::Update(viewport_size, content_size, contents_scroll_offset);
+  ScrollBar::Update(viewport_size, content_size, contents_scroll_offset);
 
   // Only reveal the scroller when |contents_scroll_offset| changes. Note this
   // is different to GetPosition() which can change due to layout. A layout
@@ -413,7 +413,7 @@
 
   // Ensure that the ScrollView updates the scrollbar's layout.
   if (parent())
-    parent()->InvalidateLayout();
+    parent()->Layout();
 
   if (scroller_style_ == NSScrollerStyleOverlay) {
     // Hide the scrollbar, but don't fade out.
@@ -546,8 +546,8 @@
 }
 
 // static
-base::RetainingOneShotTimer* BaseScrollBar::GetHideTimerForTest(
-    BaseScrollBar* scroll_bar) {
+base::RetainingOneShotTimer* ScrollBar::GetHideTimerForTesting(
+    ScrollBar* scroll_bar) {
   return &static_cast<CocoaScrollBar*>(scroll_bar)->hide_scrollbar_timer_;
 }
 
diff --git a/ui/views/controls/scrollbar/overlay_scroll_bar.cc b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
index a81be1ac..1e2940af 100644
--- a/ui/views/controls/scrollbar/overlay_scroll_bar.cc
+++ b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
@@ -124,8 +124,7 @@
   }
 }
 
-OverlayScrollBar::OverlayScrollBar(bool horizontal)
-    : BaseScrollBar(horizontal) {
+OverlayScrollBar::OverlayScrollBar(bool horizontal) : ScrollBar(horizontal) {
   auto* thumb = new Thumb(this);
   SetThumb(thumb);
   thumb->Init();
diff --git a/ui/views/controls/scrollbar/overlay_scroll_bar.h b/ui/views/controls/scrollbar/overlay_scroll_bar.h
index 7e66e01..3ae0c0b 100644
--- a/ui/views/controls/scrollbar/overlay_scroll_bar.h
+++ b/ui/views/controls/scrollbar/overlay_scroll_bar.h
@@ -7,19 +7,19 @@
 
 #include "base/macros.h"
 #include "base/timer/timer.h"
-#include "ui/views/controls/scrollbar/base_scroll_bar.h"
 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
+#include "ui/views/controls/scrollbar/scroll_bar.h"
 
 namespace views {
 
 // The transparent scrollbar which overlays its contents.
-class VIEWS_EXPORT OverlayScrollBar : public BaseScrollBar {
+class VIEWS_EXPORT OverlayScrollBar : public ScrollBar {
  public:
   explicit OverlayScrollBar(bool horizontal);
   ~OverlayScrollBar() override;
 
  protected:
-  // BaseScrollBar overrides:
+  // ScrollBar overrides:
   gfx::Rect GetTrackBounds() const override;
 
   // ScrollBar overrides:
diff --git a/ui/views/controls/scrollbar/scroll_bar.cc b/ui/views/controls/scrollbar/scroll_bar.cc
index 6036fc09d..0b66dc8e 100644
--- a/ui/views/controls/scrollbar/scroll_bar.cc
+++ b/ui/views/controls/scrollbar/scroll_bar.cc
@@ -4,22 +4,70 @@
 
 #include "ui/views/controls/scrollbar/scroll_bar.h"
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/containers/flat_map.h"
+#include "base/no_destructor.h"
+#include "base/numerics/ranges.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/controls/scroll_view.h"
+#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
+#include "ui/views/widget/widget.h"
 
 namespace views {
 
 ScrollBar::~ScrollBar() = default;
 
-void ScrollBar::GetAccessibleNodeData(ui::AXNodeData* node_data) {
-  node_data->role = ax::mojom::Role::kScrollBar;
-}
-
 bool ScrollBar::IsHorizontal() const {
   return is_horiz_;
 }
 
-void ScrollBar::Update(int viewport_size, int content_size, int current_pos) {
-  max_pos_ = std::max(0, content_size - viewport_size);
+void ScrollBar::SetThumb(BaseScrollBarThumb* thumb) {
+  DCHECK(!thumb_);
+  thumb_ = thumb;
+  AddChildView(thumb);
+  thumb->set_context_menu_controller(this);
+}
+
+bool ScrollBar::ScrollByAmount(ScrollAmount amount) {
+  auto desired_offset = GetDesiredScrollOffset(amount);
+  if (!desired_offset)
+    return false;
+
+  SetContentsScrollOffset(desired_offset.value());
+  ScrollContentsToOffset();
+  return true;
+}
+
+void ScrollBar::ScrollToThumbPosition(int thumb_position,
+                                      bool scroll_to_middle) {
+  SetContentsScrollOffset(CalculateContentsOffset(
+      static_cast<float>(thumb_position), scroll_to_middle));
+  ScrollContentsToOffset();
+  SchedulePaint();
+}
+
+bool ScrollBar::ScrollByContentsOffset(int contents_offset) {
+  int old_offset = contents_scroll_offset_;
+  SetContentsScrollOffset(contents_scroll_offset_ - contents_offset);
+  if (old_offset == contents_scroll_offset_)
+    return false;
+
+  ScrollContentsToOffset();
+  return true;
 }
 
 int ScrollBar::GetMaxPosition() const {
@@ -30,9 +78,381 @@
   return 0;
 }
 
+int ScrollBar::GetPosition() const {
+  return thumb_->GetPosition();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ScrollBar, View implementation:
+
+void ScrollBar::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  node_data->role = ax::mojom::Role::kScrollBar;
+}
+
+bool ScrollBar::OnMousePressed(const ui::MouseEvent& event) {
+  if (event.IsOnlyLeftMouseButton())
+    ProcessPressEvent(event);
+  return true;
+}
+
+void ScrollBar::OnMouseReleased(const ui::MouseEvent& event) {
+  repeater_.Stop();
+}
+
+void ScrollBar::OnMouseCaptureLost() {
+  repeater_.Stop();
+}
+
+bool ScrollBar::OnKeyPressed(const ui::KeyEvent& event) {
+  return ScrollByAmount(DetermineScrollAmountByKeyCode(event.key_code()));
+}
+
+bool ScrollBar::OnMouseWheel(const ui::MouseWheelEvent& event) {
+  OnScroll(event.x_offset(), event.y_offset());
+  return true;
+}
+
+void ScrollBar::OnGestureEvent(ui::GestureEvent* event) {
+  // If a fling is in progress, then stop the fling for any incoming gesture
+  // event (except for the GESTURE_END event that is generated at the end of the
+  // fling).
+  if (scroll_animator_ && scroll_animator_->is_scrolling() &&
+      (event->type() != ui::ET_GESTURE_END ||
+       event->details().touch_points() > 1)) {
+    scroll_animator_->Stop();
+  }
+
+  if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
+    ProcessPressEvent(*event);
+    event->SetHandled();
+    return;
+  }
+
+  if (event->type() == ui::ET_GESTURE_LONG_PRESS) {
+    // For a long-press, the repeater started in tap-down should continue. So
+    // return early.
+    return;
+  }
+
+  repeater_.Stop();
+
+  if (event->type() == ui::ET_GESTURE_TAP) {
+    // TAP_DOWN would have already scrolled some amount. So scrolling again on
+    // TAP is not necessary.
+    event->SetHandled();
+    return;
+  }
+
+  if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN ||
+      event->type() == ui::ET_GESTURE_SCROLL_END) {
+    event->SetHandled();
+    return;
+  }
+
+  if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
+    float scroll_amount_f;
+    int scroll_amount;
+    if (IsHorizontal()) {
+      scroll_amount_f = event->details().scroll_x() - roundoff_error_.x();
+      scroll_amount = gfx::ToRoundedInt(scroll_amount_f);
+      roundoff_error_.set_x(scroll_amount - scroll_amount_f);
+    } else {
+      scroll_amount_f = event->details().scroll_y() - roundoff_error_.y();
+      scroll_amount = gfx::ToRoundedInt(scroll_amount_f);
+      roundoff_error_.set_y(scroll_amount - scroll_amount_f);
+    }
+    if (ScrollByContentsOffset(scroll_amount))
+      event->SetHandled();
+    return;
+  }
+
+  if (event->type() == ui::ET_SCROLL_FLING_START) {
+    if (!scroll_animator_)
+      scroll_animator_ = std::make_unique<ScrollAnimator>(this);
+    scroll_animator_->Start(
+        IsHorizontal() ? event->details().velocity_x() : 0.f,
+        IsHorizontal() ? 0.f : event->details().velocity_y());
+    event->SetHandled();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ScrollBar, ScrollDelegate implementation:
+
+bool ScrollBar::OnScroll(float dx, float dy) {
+  return IsHorizontal() ? ScrollByContentsOffset(dx)
+                        : ScrollByContentsOffset(dy);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ScrollBar, ContextMenuController implementation:
+
+enum ScrollBarContextMenuCommands {
+  ScrollBarContextMenuCommand_ScrollHere = 1,
+  ScrollBarContextMenuCommand_ScrollStart,
+  ScrollBarContextMenuCommand_ScrollEnd,
+  ScrollBarContextMenuCommand_ScrollPageUp,
+  ScrollBarContextMenuCommand_ScrollPageDown,
+  ScrollBarContextMenuCommand_ScrollPrev,
+  ScrollBarContextMenuCommand_ScrollNext
+};
+
+void ScrollBar::ShowContextMenuForViewImpl(View* source,
+                                           const gfx::Point& p,
+                                           ui::MenuSourceType source_type) {
+  Widget* widget = GetWidget();
+  gfx::Rect widget_bounds = widget->GetWindowBoundsInScreen();
+  gfx::Point temp_pt(p.x() - widget_bounds.x(), p.y() - widget_bounds.y());
+  View::ConvertPointFromWidget(this, &temp_pt);
+  context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y();
+
+  if (!menu_model_) {
+    menu_model_ = std::make_unique<ui::SimpleMenuModel>(this);
+    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollHere,
+                                     IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE);
+    menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
+    menu_model_->AddItemWithStringId(
+        ScrollBarContextMenuCommand_ScrollStart,
+        IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE
+                       : IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME);
+    menu_model_->AddItemWithStringId(
+        ScrollBarContextMenuCommand_ScrollEnd,
+        IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE
+                       : IDS_APP_SCROLLBAR_CXMENU_SCROLLEND);
+    menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
+    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPageUp,
+                                     IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP);
+    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPageDown,
+                                     IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN);
+    menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
+    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPrev,
+                                     IsHorizontal()
+                                         ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT
+                                         : IDS_APP_SCROLLBAR_CXMENU_SCROLLUP);
+    menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollNext,
+                                     IsHorizontal()
+                                         ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT
+                                         : IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN);
+  }
+  menu_runner_ = std::make_unique<MenuRunner>(
+      menu_model_.get(),
+      MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU);
+  menu_runner_->RunMenuAt(GetWidget(), nullptr, gfx::Rect(p, gfx::Size()),
+                          MenuAnchorPosition::kTopLeft, source_type);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ScrollBar, Menu::Delegate implementation:
+
+bool ScrollBar::IsCommandIdEnabled(int id) const {
+  switch (id) {
+    case ScrollBarContextMenuCommand_ScrollPageUp:
+    case ScrollBarContextMenuCommand_ScrollPageDown:
+      return !IsHorizontal();
+  }
+  return true;
+}
+
+bool ScrollBar::IsCommandIdChecked(int id) const {
+  return false;
+}
+
+void ScrollBar::ExecuteCommand(int id, int event_flags) {
+  switch (id) {
+    case ScrollBarContextMenuCommand_ScrollHere:
+      ScrollToThumbPosition(context_menu_mouse_position_, true);
+      break;
+    case ScrollBarContextMenuCommand_ScrollStart:
+      ScrollByAmount(ScrollAmount::kStart);
+      break;
+    case ScrollBarContextMenuCommand_ScrollEnd:
+      ScrollByAmount(ScrollAmount::kEnd);
+      break;
+    case ScrollBarContextMenuCommand_ScrollPageUp:
+      ScrollByAmount(ScrollAmount::kPrevPage);
+      break;
+    case ScrollBarContextMenuCommand_ScrollPageDown:
+      ScrollByAmount(ScrollAmount::kNextPage);
+      break;
+    case ScrollBarContextMenuCommand_ScrollPrev:
+      ScrollByAmount(ScrollAmount::kPrevLine);
+      break;
+    case ScrollBarContextMenuCommand_ScrollNext:
+      ScrollByAmount(ScrollAmount::kNextLine);
+      break;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ScrollBar implementation:
+
+bool ScrollBar::OverlapsContent() const {
+  return false;
+}
+
+void ScrollBar::Update(int viewport_size,
+                       int content_size,
+                       int contents_scroll_offset) {
+  max_pos_ = std::max(0, content_size - viewport_size);
+  // Make sure contents_size is always > 0 to avoid divide by zero errors in
+  // calculations throughout this code.
+  contents_size_ = std::max(1, content_size);
+  viewport_size_ = std::max(1, viewport_size);
+
+  SetContentsScrollOffset(contents_scroll_offset);
+
+  // Thumb Height and Thumb Pos.
+  // The height of the thumb is the ratio of the Viewport height to the
+  // content size multiplied by the height of the thumb track.
+  float ratio =
+      std::min<float>(1.0, static_cast<float>(viewport_size) / contents_size_);
+  thumb_->SetLength(gfx::ToRoundedInt(ratio * GetTrackSize()));
+
+  int thumb_position = CalculateThumbPosition(contents_scroll_offset);
+  thumb_->SetPosition(thumb_position);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ScrollBar, protected:
+
+BaseScrollBarThumb* ScrollBar::GetThumb() const {
+  return thumb_;
+}
+
+void ScrollBar::ScrollToPosition(int position) {
+  controller()->ScrollToPosition(this, position);
+}
+
+int ScrollBar::GetScrollIncrement(bool is_page, bool is_positive) {
+  return controller()->GetScrollIncrement(this, is_page, is_positive);
+}
+
 void ScrollBar::ObserveScrollEvent(const ui::ScrollEvent& event) {}
 
 ScrollBar::ScrollBar(bool is_horiz)
-    : is_horiz_(is_horiz), controller_(nullptr), max_pos_(0) {}
+    : is_horiz_(is_horiz),
+      repeater_(base::BindRepeating(&ScrollBar::TrackClicked,
+                                    base::Unretained(this))) {
+  set_context_menu_controller(this);
+}
 
+///////////////////////////////////////////////////////////////////////////////
+// ScrollBar, private:
+
+#if !defined(OS_MACOSX)
+// static
+base::RetainingOneShotTimer* ScrollBar::GetHideTimerForTesting(
+    ScrollBar* scroll_bar) {
+  return nullptr;
+}
+#endif
+
+int ScrollBar::GetThumbSizeForTesting() {
+  return thumb_->GetSize();
+}
+
+void ScrollBar::ProcessPressEvent(const ui::LocatedEvent& event) {
+  gfx::Rect thumb_bounds = thumb_->bounds();
+  if (IsHorizontal()) {
+    if (GetMirroredXInView(event.x()) < thumb_bounds.x()) {
+      last_scroll_amount_ = ScrollAmount::kPrevPage;
+    } else if (GetMirroredXInView(event.x()) > thumb_bounds.right()) {
+      last_scroll_amount_ = ScrollAmount::kNextPage;
+    }
+  } else {
+    if (event.y() < thumb_bounds.y()) {
+      last_scroll_amount_ = ScrollAmount::kPrevPage;
+    } else if (event.y() > thumb_bounds.bottom()) {
+      last_scroll_amount_ = ScrollAmount::kNextPage;
+    }
+  }
+  TrackClicked();
+  repeater_.Start();
+}
+
+void ScrollBar::TrackClicked() {
+  ScrollByAmount(last_scroll_amount_);
+}
+
+void ScrollBar::ScrollContentsToOffset() {
+  ScrollToPosition(contents_scroll_offset_);
+  thumb_->SetPosition(CalculateThumbPosition(contents_scroll_offset_));
+}
+
+int ScrollBar::GetTrackSize() const {
+  gfx::Rect track_bounds = GetTrackBounds();
+  return IsHorizontal() ? track_bounds.width() : track_bounds.height();
+}
+
+int ScrollBar::CalculateThumbPosition(int contents_scroll_offset) const {
+  // In some combination of viewport_size and contents_size_, the result of
+  // simple division can be rounded and there could be 1 pixel gap even when the
+  // contents scroll down to the bottom. See crbug.com/244671.
+  int thumb_max = GetTrackSize() - thumb_->GetSize();
+  if (contents_scroll_offset + viewport_size_ == contents_size_)
+    return thumb_max;
+  return (contents_scroll_offset * thumb_max) /
+         (contents_size_ - viewport_size_);
+}
+
+int ScrollBar::CalculateContentsOffset(float thumb_position,
+                                       bool scroll_to_middle) const {
+  float thumb_size = static_cast<float>(thumb_->GetSize());
+  int track_size = GetTrackSize();
+  if (track_size == thumb_size)
+    return 0;
+  if (scroll_to_middle)
+    thumb_position = thumb_position - (thumb_size / 2);
+  float result = (thumb_position * (contents_size_ - viewport_size_)) /
+                 (track_size - thumb_size);
+  return gfx::ToFlooredInt(result);
+}
+
+void ScrollBar::SetContentsScrollOffset(int contents_scroll_offset) {
+  contents_scroll_offset_ = base::ClampToRange(
+      contents_scroll_offset, GetMinPosition(), GetMaxPosition());
+}
+
+ScrollBar::ScrollAmount ScrollBar::DetermineScrollAmountByKeyCode(
+    const ui::KeyboardCode& keycode) const {
+  // Reject arrows that don't match the scrollbar orientation.
+  if (IsHorizontal() ? (keycode == ui::VKEY_UP || keycode == ui::VKEY_DOWN)
+                     : (keycode == ui::VKEY_LEFT || keycode == ui::VKEY_RIGHT))
+    return ScrollAmount::kNone;
+
+  static const base::NoDestructor<
+      base::flat_map<ui::KeyboardCode, ScrollAmount>>
+      kMap({
+          {ui::VKEY_LEFT, ScrollAmount::kPrevLine},
+          {ui::VKEY_RIGHT, ScrollAmount::kNextLine},
+          {ui::VKEY_UP, ScrollAmount::kPrevLine},
+          {ui::VKEY_DOWN, ScrollAmount::kNextLine},
+          {ui::VKEY_PRIOR, ScrollAmount::kPrevPage},
+          {ui::VKEY_NEXT, ScrollAmount::kNextPage},
+          {ui::VKEY_HOME, ScrollAmount::kStart},
+          {ui::VKEY_END, ScrollAmount::kEnd},
+      });
+
+  const auto i = kMap->find(keycode);
+  return (i == kMap->end()) ? ScrollAmount::kNone : i->second;
+}
+
+base::Optional<int> ScrollBar::GetDesiredScrollOffset(ScrollAmount amount) {
+  switch (amount) {
+    case ScrollAmount::kStart:
+      return GetMinPosition();
+    case ScrollAmount::kEnd:
+      return GetMaxPosition();
+    case ScrollAmount::kPrevLine:
+      return contents_scroll_offset_ - GetScrollIncrement(false, false);
+    case ScrollAmount::kNextLine:
+      return contents_scroll_offset_ + GetScrollIncrement(false, true);
+    case ScrollAmount::kPrevPage:
+      return contents_scroll_offset_ - GetScrollIncrement(true, false);
+    case ScrollAmount::kNextPage:
+      return contents_scroll_offset_ + GetScrollIncrement(true, true);
+    default:
+      return base::nullopt;
+  }
+}
 }  // namespace views
diff --git a/ui/views/controls/scrollbar/scroll_bar.h b/ui/views/controls/scrollbar/scroll_bar.h
index ac162b7..de7b944 100644
--- a/ui/views/controls/scrollbar/scroll_bar.h
+++ b/ui/views/controls/scrollbar/scroll_bar.h
@@ -6,12 +6,27 @@
 #define UI_VIEWS_CONTROLS_SCROLLBAR_SCROLL_BAR_H_
 
 #include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/optional.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/views/animation/scroll_animator.h"
+#include "ui/views/context_menu_controller.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/scrollbar/scroll_bar.h"
+#include "ui/views/repeat_controller.h"
 #include "ui/views/view.h"
 #include "ui/views/views_export.h"
 
 namespace views {
 
+namespace test {
+class ScrollViewTestApi;
+}
+
+class BaseScrollBarThumb;
+class MenuRunner;
+
 class ScrollBar;
 
 /////////////////////////////////////////////////////////////////////////////
@@ -55,12 +70,24 @@
 // A scrollbar is either horizontal or vertical
 //
 /////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT ScrollBar : public View {
+class VIEWS_EXPORT ScrollBar : public View,
+                               public ScrollDelegate,
+                               public ContextMenuController,
+                               public ui::SimpleMenuModel::Delegate {
  public:
-  ~ScrollBar() override;
+  // An enumeration of different amounts of incremental scroll, representing
+  // events sent from different parts of the UI/keyboard.
+  enum class ScrollAmount {
+    kNone,
+    kStart,
+    kEnd,
+    kPrevLine,
+    kNextLine,
+    kPrevPage,
+    kNextPage,
+  };
 
-  // Overridden from View:
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  ~ScrollBar() override;
 
   // Returns whether this scrollbar is horizontal.
   bool IsHorizontal() const;
@@ -70,43 +97,170 @@
   }
   ScrollBarController* controller() const { return controller_; }
 
-  // Update the scrollbar appearance given a viewport size, content size and
-  // current position
-  virtual void Update(int viewport_size, int content_size, int current_pos);
+  void SetThumb(BaseScrollBarThumb* thumb);
+
+  // Scroll the contents by the specified type (see ScrollAmount above).
+  bool ScrollByAmount(ScrollAmount amount);
+
+  // Scroll the contents to the appropriate position given the supplied
+  // position of the thumb (thumb track coordinates). If |scroll_to_middle| is
+  // true, then the conversion assumes |thumb_position| is in the middle of the
+  // thumb rather than the top.
+  void ScrollToThumbPosition(int thumb_position, bool scroll_to_middle);
+
+  // Scroll the contents by the specified offset (contents coordinates).
+  bool ScrollByContentsOffset(int contents_offset);
 
   // Returns the max and min positions.
   int GetMaxPosition() const;
   int GetMinPosition() const;
 
   // Returns the position of the scrollbar.
-  virtual int GetPosition() const = 0;
+  int GetPosition() const;
 
-  // Get the width or height of this scrollbar. For a vertical scrollbar, this
-  // is the width of the scrollbar, likewise it is the height for a horizontal
-  // scrollbar.
-  virtual int GetThickness() const = 0;
+  // View:
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  bool OnMousePressed(const ui::MouseEvent& event) override;
+  void OnMouseReleased(const ui::MouseEvent& event) override;
+  void OnMouseCaptureLost() override;
+  bool OnKeyPressed(const ui::KeyEvent& event) override;
+  bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
+
+  // ScrollDelegate:
+  bool OnScroll(float dx, float dy) override;
+
+  // ContextMenuController:
+  void ShowContextMenuForViewImpl(View* source,
+                                  const gfx::Point& point,
+                                  ui::MenuSourceType source_type) override;
+
+  // ui::SimpleMenuModel::Delegate:
+  bool IsCommandIdChecked(int id) const override;
+  bool IsCommandIdEnabled(int id) const override;
+  void ExecuteCommand(int id, int event_flags) override;
 
   // Returns true if the scrollbar should sit on top of the content area (e.g.
   // for overlay scrollbars).
-  virtual bool OverlapsContent() const = 0;
+  virtual bool OverlapsContent() const;
+
+  // Update the scrollbar appearance given a viewport size, content size and
+  // current position.
+  virtual void Update(int viewport_size,
+                      int content_size,
+                      int contents_scroll_offset);
 
   // Called when a ScrollEvent (in any, or no, direction) is seen by the parent
   // ScrollView. E.g., this may reveal an overlay scrollbar to indicate
   // possible scrolling directions to the user.
   virtual void ObserveScrollEvent(const ui::ScrollEvent& event);
 
+  // Get the bounds of the "track" area that the thumb is free to slide within.
+  virtual gfx::Rect GetTrackBounds() const = 0;
+
+  // Get the width or height of this scrollbar. For a vertical scrollbar, this
+  // is the width of the scrollbar, likewise it is the height for a horizontal
+  // scrollbar.
+  virtual int GetThickness() const = 0;
+
  protected:
   // Create new scrollbar, either horizontal or vertical. These are protected
   // since you need to be creating either a NativeScrollBar or a
   // ImageScrollBar.
   explicit ScrollBar(bool is_horiz);
 
+  BaseScrollBarThumb* GetThumb() const;
+
+  // Wrapper functions that calls the controller. We need this since native
+  // scrollbars wrap around a different scrollbar. When calling the controller
+  // we need to pass in the appropriate scrollbar. For normal scrollbars it's
+  // the |this| scrollbar, for native scrollbars it's the native scrollbar used
+  // to create this.
+  virtual void ScrollToPosition(int position);
+  virtual int GetScrollIncrement(bool is_page, bool is_positive);
+
  private:
+  friend class test::ScrollViewTestApi;
+  FRIEND_TEST_ALL_PREFIXES(ScrollBarViewsTest, ScrollBarFitsToBottom);
+  FRIEND_TEST_ALL_PREFIXES(ScrollBarViewsTest, ThumbFullLengthOfTrack);
+
+  static base::RetainingOneShotTimer* GetHideTimerForTesting(
+      ScrollBar* scroll_bar);
+  int GetThumbSizeForTesting();
+
+  // Changes to 'pushed' state and starts a timer to scroll repeatedly.
+  void ProcessPressEvent(const ui::LocatedEvent& event);
+
+  // Called when the mouse is pressed down in the track area.
+  void TrackClicked();
+
+  // Responsible for scrolling the contents and also updating the UI to the
+  // current value of the Scroll Offset.
+  void ScrollContentsToOffset();
+
+  // Returns the size (width or height) of the track area of the ScrollBar.
+  int GetTrackSize() const;
+
+  // Calculate the position of the thumb within the track based on the
+  // specified scroll offset of the contents.
+  int CalculateThumbPosition(int contents_scroll_offset) const;
+
+  // Calculates the current value of the contents offset (contents coordinates)
+  // based on the current thumb position (thumb track coordinates). See
+  // ScrollToThumbPosition() for an explanation of |scroll_to_middle|.
+  int CalculateContentsOffset(float thumb_position,
+                              bool scroll_to_middle) const;
+
+  // Sets |contents_scroll_offset_| by given |contents_scroll_offset|.
+  // |contents_scroll_offset| is clamped between GetMinPosition() and
+  // GetMaxPosition().
+  void SetContentsScrollOffset(int contents_scroll_offset);
+
+  ScrollAmount DetermineScrollAmountByKeyCode(
+      const ui::KeyboardCode& keycode) const;
+
+  base::Optional<int> GetDesiredScrollOffset(ScrollAmount amount);
+
+  // The size of the scrolled contents, in pixels.
+  int contents_size_ = 0;
+
+  // The current amount the contents is offset by in the viewport.
+  int contents_scroll_offset_ = 0;
+
+  // The current size of the view port, in pixels.
+  int viewport_size_ = 0;
+
+  // The last amount of incremental scroll that this scrollbar performed. This
+  // is accessed by the callbacks for the auto-repeat up/down buttons to know
+  // what direction to repeatedly scroll in.
+  ScrollAmount last_scroll_amount_ = ScrollAmount::kNone;
+
+  // The position of the mouse within the scroll bar when the context menu
+  // was invoked.
+  int context_menu_mouse_position_ = 0;
+
   const bool is_horiz_;
 
-  ScrollBarController* controller_;
+  BaseScrollBarThumb* thumb_ = nullptr;
 
-  int max_pos_;
+  ScrollBarController* controller_ = nullptr;
+
+  int max_pos_ = 0;
+
+  // An instance of a RepeatController which scrolls the scrollbar continuously
+  // as the user presses the mouse button down on the up/down buttons or the
+  // track.
+  RepeatController repeater_;
+
+  // Difference between current position and cumulative deltas obtained from
+  // scroll update events.
+  // TODO(tdresser): This should be removed when raw pixel scrolling for views
+  // is enabled. See crbug.com/329354.
+  gfx::Vector2dF roundoff_error_;
+
+  std::unique_ptr<ui::SimpleMenuModel> menu_model_;
+  std::unique_ptr<MenuRunner> menu_runner_;
+  std::unique_ptr<ScrollAnimator> scroll_animator_;
 
   DISALLOW_COPY_AND_ASSIGN(ScrollBar);
 };
diff --git a/ui/views/controls/scrollbar/scroll_bar_views.cc b/ui/views/controls/scrollbar/scroll_bar_views.cc
index 0cac5c59..ab15a8e 100644
--- a/ui/views/controls/scrollbar/scroll_bar_views.cc
+++ b/ui/views/controls/scrollbar/scroll_bar_views.cc
@@ -47,7 +47,7 @@
 // Wrapper for the scroll thumb
 class ScrollBarThumb : public BaseScrollBarThumb {
  public:
-  explicit ScrollBarThumb(BaseScrollBar* scroll_bar);
+  explicit ScrollBarThumb(ScrollBar* scroll_bar);
   ~ScrollBarThumb() override;
 
   gfx::Size CalculatePreferredSize() const override;
@@ -138,7 +138,7 @@
 /////////////////////////////////////////////////////////////////////////////
 // ScrollBarThumb
 
-ScrollBarThumb::ScrollBarThumb(BaseScrollBar* scroll_bar)
+ScrollBarThumb::ScrollBarThumb(ScrollBar* scroll_bar)
     : BaseScrollBarThumb(scroll_bar), scroll_bar_(scroll_bar) {}
 
 ScrollBarThumb::~ScrollBarThumb() = default;
@@ -199,8 +199,7 @@
 
 const char ScrollBarViews::kViewClassName[] = "ScrollBarViews";
 
-ScrollBarViews::ScrollBarViews(bool horizontal)
-    : BaseScrollBar(horizontal) {
+ScrollBarViews::ScrollBarViews(bool horizontal) : ScrollBar(horizontal) {
   SetThumb(new ScrollBarThumb(this));
   if (horizontal) {
     prev_button_ = new ScrollBarButton(this, ScrollBarButton::LEFT);
@@ -295,9 +294,9 @@
 
 void ScrollBarViews::ButtonPressed(Button* sender, const ui::Event& event) {
   if (sender == prev_button_) {
-    ScrollByAmount(SCROLL_PREV_LINE);
+    ScrollByAmount(ScrollBar::ScrollAmount::kPrevLine);
   } else if (sender == next_button_) {
-    ScrollByAmount(SCROLL_NEXT_LINE);
+    ScrollByAmount(ScrollBar::ScrollAmount::kNextLine);
   }
 }
 
diff --git a/ui/views/controls/scrollbar/scroll_bar_views.h b/ui/views/controls/scrollbar/scroll_bar_views.h
index 4571a629..847a7811 100644
--- a/ui/views/controls/scrollbar/scroll_bar_views.h
+++ b/ui/views/controls/scrollbar/scroll_bar_views.h
@@ -10,7 +10,7 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/scrollbar/base_scroll_bar.h"
+#include "ui/views/controls/scrollbar/scroll_bar.h"
 #include "ui/views/view.h"
 
 namespace gfx {
@@ -20,8 +20,7 @@
 namespace views {
 
 // Views implementation for the scrollbar.
-class VIEWS_EXPORT ScrollBarViews : public BaseScrollBar,
-                                    public ButtonListener {
+class VIEWS_EXPORT ScrollBarViews : public ScrollBar, public ButtonListener {
  public:
   static const char kViewClassName[];
 
diff --git a/ui/views/controls/scrollbar/scrollbar_unittest.cc b/ui/views/controls/scrollbar/scrollbar_unittest.cc
index 88fc242..ddc3c35 100644
--- a/ui/views/controls/scrollbar/scrollbar_unittest.cc
+++ b/ui/views/controls/scrollbar/scrollbar_unittest.cc
@@ -80,7 +80,7 @@
   Widget* widget_ = nullptr;
 
   // This is the Views scrollbar.
-  BaseScrollBar* scrollbar_ = nullptr;
+  ScrollBar* scrollbar_ = nullptr;
 
   // Keep track of the size of the track. This is how we can tell when we
   // scroll to the middle.
@@ -114,16 +114,16 @@
   // Test the different fixed scrolling amounts. Generally used by buttons,
   // or click on track.
   scrollbar_->ScrollToThumbPosition(0, false);
-  scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_NEXT_LINE);
+  scrollbar_->ScrollByAmount(ScrollBar::ScrollAmount::kNextLine);
   EXPECT_EQ(10, controller_->last_position);
 
-  scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_PREV_LINE);
+  scrollbar_->ScrollByAmount(ScrollBar::ScrollAmount::kPrevLine);
   EXPECT_EQ(0, controller_->last_position);
 
-  scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_NEXT_PAGE);
+  scrollbar_->ScrollByAmount(ScrollBar::ScrollAmount::kNextPage);
   EXPECT_EQ(20, controller_->last_position);
 
-  scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_PREV_PAGE);
+  scrollbar_->ScrollByAmount(ScrollBar::ScrollAmount::kPrevPage);
   EXPECT_EQ(0, controller_->last_position);
 }
 
@@ -136,15 +136,15 @@
   // Scroll to the midpoint of the document.
   scrollbar_->Update(100, 1999, 950);
   EXPECT_EQ((scrollbar_->GetTrackBounds().width() -
-             scrollbar_->GetThumbSizeForTest()) /
+             scrollbar_->GetThumbSizeForTesting()) /
                 2,
             scrollbar_->GetPosition());
 
   // Scroll to the end of the document.
   scrollbar_->Update(100, 1999, 1899);
-  EXPECT_EQ(
-      scrollbar_->GetTrackBounds().width() - scrollbar_->GetThumbSizeForTest(),
-      scrollbar_->GetPosition());
+  EXPECT_EQ(scrollbar_->GetTrackBounds().width() -
+                scrollbar_->GetThumbSizeForTesting(),
+            scrollbar_->GetPosition());
 }
 
 TEST_F(ScrollBarViewsTest, ScrollToEndAfterShrinkAndExpand) {
@@ -162,23 +162,23 @@
   // Shrink content so that it fits within the viewport.
   scrollbar_->Update(100, 10, 0);
   EXPECT_EQ(scrollbar_->GetTrackBounds().width(),
-            scrollbar_->GetThumbSizeForTest());
+            scrollbar_->GetThumbSizeForTesting());
   // Emulate a click on the full size scroll bar.
   scrollbar_->ScrollToThumbPosition(0, false);
   EXPECT_EQ(0, scrollbar_->GetPosition());
   // Emulate a key down.
-  scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_NEXT_LINE);
+  scrollbar_->ScrollByAmount(ScrollBar::ScrollAmount::kNextLine);
   EXPECT_EQ(0, scrollbar_->GetPosition());
 
   // Expand content so that it fits *exactly* within the viewport.
   scrollbar_->Update(100, 100, 0);
   EXPECT_EQ(scrollbar_->GetTrackBounds().width(),
-            scrollbar_->GetThumbSizeForTest());
+            scrollbar_->GetThumbSizeForTesting());
   // Emulate a click on the full size scroll bar.
   scrollbar_->ScrollToThumbPosition(0, false);
   EXPECT_EQ(0, scrollbar_->GetPosition());
   // Emulate a key down.
-  scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_NEXT_LINE);
+  scrollbar_->ScrollByAmount(ScrollBar::ScrollAmount::kNextLine);
   EXPECT_EQ(0, scrollbar_->GetPosition());
 }
 
diff --git a/ui/views/controls/styled_label.cc b/ui/views/controls/styled_label.cc
index 37ec7ad..ee21d283 100644
--- a/ui/views/controls/styled_label.cc
+++ b/ui/views/controls/styled_label.cc
@@ -192,10 +192,10 @@
   displayed_on_background_color_ = color;
   displayed_on_background_color_set_ = true;
 
-  for (int i = 0, count = child_count(); i < count; ++i) {
-    DCHECK((child_at(i)->GetClassName() == Label::kViewClassName) ||
-           (child_at(i)->GetClassName() == Link::kViewClassName));
-    static_cast<Label*>(child_at(i))->SetBackgroundColor(color);
+  for (View* child : children()) {
+    DCHECK((child->GetClassName() == Label::kViewClassName) ||
+           (child->GetClassName() == Link::kViewClassName));
+    static_cast<Label*>(child)->SetBackgroundColor(color);
   }
 }
 
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc
index cdc1188a..a0bb177b 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -752,8 +752,8 @@
 
 gfx::Size TabbedPane::CalculatePreferredSize() const {
   gfx::Size size;
-  for (int i = 0; i < contents_->child_count(); ++i)
-    size.SetToMax(contents_->child_at(i)->GetPreferredSize());
+  for (const View* child : contents_->children())
+    size.SetToMax(child->GetPreferredSize());
   if (GetOrientation() == Orientation::kHorizontal)
     size.Enlarge(0, tab_strip_->GetPreferredSize().height());
   else
@@ -795,8 +795,8 @@
     contents_->SetBounds(tab_strip_->bounds().width(), 0,
                          std::max(0, width() - size.width()), height());
   }
-  for (int i = 0; i < contents_->child_count(); ++i)
-    contents_->child_at(i)->SetSize(contents_->size());
+  for (View* child : contents_->children())
+    child->SetSize(contents_->size());
 }
 
 void TabbedPane::ViewHierarchyChanged(
diff --git a/ui/views/debug_utils.cc b/ui/views/debug_utils.cc
index be167d07..996eaead 100644
--- a/ui/views/debug_utils.cc
+++ b/ui/views/debug_utils.cc
@@ -32,8 +32,8 @@
   *out << view;
   *out << '\n';
 
-  for (int i = 0, count = view->child_count(); i < count; ++i)
-    PrintViewHierarchyImp(view->child_at(i), indent + 2, out);
+  for (const View* child : view->children())
+    PrintViewHierarchyImp(child, indent + 2, out);
 }
 
 void PrintFocusHierarchyImp(const View* view,
@@ -137,8 +137,8 @@
     result.append("\n");
   }
 
-  for (int i = 0; i < view->child_count(); ++i)
-    result.append(PrintViewGraphImpl(view->child_at(i)));
+  for (const View* child : view->children())
+    result.append(PrintViewGraphImpl(child));
 
   return result;
 }
diff --git a/ui/views/examples/animated_image_view_example.cc b/ui/views/examples/animated_image_view_example.cc
index 09bf0eea..8e9ac20 100644
--- a/ui/views/examples/animated_image_view_example.cc
+++ b/ui/views/examples/animated_image_view_example.cc
@@ -113,7 +113,7 @@
       animated_image_view_->SetImageSize(gfx::Size(size_, size_));
     else
       animated_image_view_->ResetImageSize();
-    InvalidateLayout();
+    Layout();
   }
 
   AnimatedImageView* animated_image_view_;
diff --git a/ui/views/examples/box_layout_example.cc b/ui/views/examples/box_layout_example.cc
index 2d512a8..1fa7c23 100644
--- a/ui/views/examples/box_layout_example.cc
+++ b/ui/views/examples/box_layout_example.cc
@@ -124,8 +124,8 @@
   View* const panel = layout_panel();
   layout_ = panel->SetLayoutManager(std::move(layout));
   UpdateBorderInsets();
-  for (int i = 0; i < panel->child_count(); ++i) {
-    ChildPanel* child_panel = static_cast<ChildPanel*>(panel->child_at(i));
+  for (View* child : panel->children()) {
+    ChildPanel* child_panel = static_cast<ChildPanel*>(child);
     int flex = child_panel->GetFlex();
     if (flex < 0)
       layout_->ClearFlexForView(child_panel);
diff --git a/ui/views/examples/examples_window.cc b/ui/views/examples/examples_window.cc
index e70e1f4c..53cfe77 100644
--- a/ui/views/examples/examples_window.cc
+++ b/ui/views/examples/examples_window.cc
@@ -208,7 +208,7 @@
         combobox_model_->GetItemViewAt(combobox->selected_index()));
     example_shown_->RequestFocus();
     SetStatus(std::string());
-    InvalidateLayout();
+    Layout();
   }
 
   static ExamplesWindowContents* instance_;
diff --git a/ui/views/examples/flex_layout_example.cc b/ui/views/examples/flex_layout_example.cc
index 2d8f3fec..353bf30 100644
--- a/ui/views/examples/flex_layout_example.cc
+++ b/ui/views/examples/flex_layout_example.cc
@@ -93,8 +93,8 @@
 }
 
 void FlexLayoutExample::UpdateLayoutManager() {
-  for (int i = 0; i < layout_panel()->child_count(); ++i) {
-    ChildPanel* panel = static_cast<ChildPanel*>(layout_panel()->child_at(i));
+  for (View* child : layout_panel()->children()) {
+    ChildPanel* panel = static_cast<ChildPanel*>(child);
     int flex = panel->GetFlex();
     if (flex < 0)
       layout_->ClearFlexForView(panel);
diff --git a/ui/views/examples/label_example.cc b/ui/views/examples/label_example.cc
index 0f80eb2..ba39175 100644
--- a/ui/views/examples/label_example.cc
+++ b/ui/views/examples/label_example.cc
@@ -133,7 +133,7 @@
   } else if (button == selectable_) {
     custom_label_->SetSelectable(selectable_->checked());
   }
-  custom_label_->parent()->parent()->InvalidateLayout();
+  custom_label_->parent()->parent()->Layout();
   custom_label_->SchedulePaint();
 }
 
@@ -150,7 +150,7 @@
 void LabelExample::ContentsChanged(Textfield* sender,
                                    const base::string16& new_contents) {
   custom_label_->SetText(new_contents);
-  custom_label_->parent()->parent()->InvalidateLayout();
+  custom_label_->parent()->parent()->Layout();
 }
 
 void LabelExample::AddCustomLabel(View* container) {
diff --git a/ui/views/examples/layout_example_base.cc b/ui/views/examples/layout_example_base.cc
index f18ce90..67d85d0 100644
--- a/ui/views/examples/layout_example_base.cc
+++ b/ui/views/examples/layout_example_base.cc
@@ -120,8 +120,7 @@
     selected_ = value;
     SetBorder(CreateSolidBorder(1, selected_ ? SK_ColorBLACK : SK_ColorGRAY));
     if (selected_ && parent()) {
-      for (int i = 0; i < parent()->child_count(); ++i) {
-        View* child = parent()->child_at(i);
+      for (View* child : parent()->children()) {
         if (child != this && child->GetGroup() == GetGroup())
           static_cast<ChildPanel*>(child)->SetSelected(false);
       }
@@ -311,7 +310,7 @@
 void LayoutExampleBase::RefreshLayoutPanel(bool update_layout) {
   if (update_layout)
     UpdateLayoutManager();
-  layout_panel_->InvalidateLayout();
+  layout_panel_->Layout();
   layout_panel_->SchedulePaint();
 }
 
diff --git a/ui/views/examples/multiline_example.cc b/ui/views/examples/multiline_example.cc
index bbff7cd..3517a36 100644
--- a/ui/views/examples/multiline_example.cc
+++ b/ui/views/examples/multiline_example.cc
@@ -180,7 +180,7 @@
   render_text_view_->SetText(new_contents);
   if (label_checkbox_->checked())
     label_->SetText(new_contents);
-  container()->InvalidateLayout();
+  container()->Layout();
   container()->SchedulePaint();
 }
 
@@ -191,7 +191,7 @@
   } else if (sender == elision_checkbox_) {
     render_text_view_->SetMaxLines(elision_checkbox_->checked() ? 3 : 0);
   }
-  container()->InvalidateLayout();
+  container()->Layout();
   container()->SchedulePaint();
 }
 
diff --git a/ui/views/examples/scroll_view_example.cc b/ui/views/examples/scroll_view_example.cc
index f254ca6..59a3662 100644
--- a/ui/views/examples/scroll_view_example.cc
+++ b/ui/views/examples/scroll_view_example.cc
@@ -126,7 +126,7 @@
     scroll_view_->contents()->ScrollRectToVisible(
         gfx::Rect(20, 500, 1000, 500));
   }
-  scroll_view_->InvalidateLayout();
+  scroll_view_->Layout();
 }
 
 }  // namespace examples
diff --git a/ui/views/examples/vector_example.cc b/ui/views/examples/vector_example.cc
index 56b77985..e05e8f6 100644
--- a/ui/views/examples/vector_example.cc
+++ b/ui/views/examples/vector_example.cc
@@ -124,7 +124,7 @@
       image_view_->SetImage(
           gfx::CreateVectorIconFromSource(contents_, size_, color_));
     }
-    InvalidateLayout();
+    Layout();
   }
 
   // 36dp is one of the natural sizes for MD icons, and corresponds roughly to a
diff --git a/ui/views/layout/box_layout.cc b/ui/views/layout/box_layout.cc
index f74570f..313e035b 100644
--- a/ui/views/layout/box_layout.cc
+++ b/ui/views/layout/box_layout.cc
@@ -300,8 +300,8 @@
     int leading = 0;
     int trailing = 0;
     gfx::Rect child_view_area;
-    for (int i = 0; i < host_->child_count(); ++i) {
-      const ViewWrapper child(this, host_->child_at(i));
+    for (View* view : host_->children()) {
+      const ViewWrapper child(this, view);
       if (!child.visible())
         continue;
 
@@ -481,8 +481,8 @@
 gfx::Insets BoxLayout::CrossAxisMaxViewMargin() const {
   int leading = 0;
   int trailing = 0;
-  for (int i = 0; i < host_->child_count(); ++i) {
-    const ViewWrapper child(this, host_->child_at(i));
+  for (View* view : host_->children()) {
+    const ViewWrapper child(this, view);
     if (!child.visible())
       continue;
     leading = std::max(leading, CrossAxisLeadingInset(child.margins()));
diff --git a/ui/views/layout/fill_layout.cc b/ui/views/layout/fill_layout.cc
index 2bc66a72..50bceb1 100644
--- a/ui/views/layout/fill_layout.cc
+++ b/ui/views/layout/fill_layout.cc
@@ -16,8 +16,8 @@
   if (host->children().empty())
     return;
 
-  for (int i = 0; i < host->child_count(); ++i)
-    host->child_at(i)->SetBoundsRect(host->GetContentsBounds());
+  for (View* child : host->children())
+    child->SetBoundsRect(host->GetContentsBounds());
 }
 
 gfx::Size FillLayout::GetPreferredSize(const View* host) const {
@@ -25,8 +25,8 @@
     return gfx::Size();
 
   gfx::Size preferred_size;
-  for (int i = 0; i < host->child_count(); ++i)
-    preferred_size.SetToMax(host->child_at(i)->GetPreferredSize());
+  for (View* child : host->children())
+    preferred_size.SetToMax(child->GetPreferredSize());
   gfx::Rect rect(preferred_size);
   rect.Inset(-host->GetInsets());
   return rect.size();
@@ -38,11 +38,10 @@
 
   const gfx::Insets insets = host->GetInsets();
   int preferred_height = 0;
-  for (int i = 0; i < host->child_count(); ++i) {
+  for (View* child : host->children()) {
     int cur_preferred_height = 0;
     cur_preferred_height =
-        host->child_at(i)->GetHeightForWidth(width - insets.width()) +
-        insets.height();
+        child->GetHeightForWidth(width - insets.width()) + insets.height();
     preferred_height = std::max(preferred_height, cur_preferred_height);
   }
   return preferred_height;
diff --git a/ui/views/layout/flex_layout.cc b/ui/views/layout/flex_layout.cc
index 144c43e..cba84683 100644
--- a/ui/views/layout/flex_layout.cc
+++ b/ui/views/layout/flex_layout.cc
@@ -1046,8 +1046,7 @@
   // Add all the existing children when the layout manager is installed.
   // If new children are added, ViewAdded() will be called and we'll add data
   // there.
-  for (int i = 0; i < host->child_count(); ++i) {
-    View* const child = host->child_at(i);
+  for (View* child : host->children()) {
     internal::ChildLayoutParams child_layout_params;
     child_layout_params.hidden_by_owner = !child->visible();
     child_params_.emplace(child, child_layout_params);
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc
index bfbeadb..fa32589 100644
--- a/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -134,8 +134,10 @@
   void OnWindowPropertyChanged(aura::Window* window,
                                const void* key,
                                intptr_t old) override {
-    if (key == aura::client::kTopViewInset)
+    if (key == aura::client::kTopViewInset) {
       InvalidateLayout();
+      widget_->GetRootView()->Layout();
+    }
   }
 
   aura::Window* window() const {
@@ -966,7 +968,7 @@
   NonClientView* non_client_view =
       native_widget_delegate_->AsWidget()->non_client_view();
   if (non_client_view) {
-    non_client_view->InvalidateLayout();
+    non_client_view->Layout();
     non_client_view->SchedulePaint();
   }
 
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc
index 464992a..d24485b 100644
--- a/ui/views/test/views_test_base.cc
+++ b/ui/views/test/views_test_base.cc
@@ -246,11 +246,6 @@
 #endif
 }
 
-void ViewsTestBaseWithNativeWidgetType::SetUp() {
-  set_native_widget_type(GetParam());
-  ViewsTestBase::SetUp();
-}
-
 void ViewsTestWithDesktopNativeWidget::SetUp() {
   set_native_widget_type(NativeWidgetType::kDesktop);
   ViewsTestBase::SetUp();
diff --git a/ui/views/test/views_test_base.h b/ui/views/test/views_test_base.h
index e2e3d8e..6a169ce 100644
--- a/ui/views/test/views_test_base.h
+++ b/ui/views/test/views_test_base.h
@@ -140,20 +140,6 @@
   DISALLOW_COPY_AND_ASSIGN(ViewsTestBase);
 };
 
-class ViewsTestBaseWithNativeWidgetType
-    : public ViewsTestBase,
-      public testing::WithParamInterface<ViewsTestBase::NativeWidgetType> {
- public:
-  ViewsTestBaseWithNativeWidgetType() = default;
-  ~ViewsTestBaseWithNativeWidgetType() override = default;
-
-  // ViewsTestBase:
-  void SetUp() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ViewsTestBaseWithNativeWidgetType);
-};
-
 // A helper that makes it easier to declare basic views tests that want to test
 // desktop native widgets. See |ViewsTestBase::native_wiget_type_| and
 // |ViewsTestBase::CreateNativeWidgetForTest|. In short, for Aura, this will
diff --git a/ui/views/touchui/touch_selection_menu_views.cc b/ui/views/touchui/touch_selection_menu_views.cc
index d5caea6..bbde208 100644
--- a/ui/views/touchui/touch_selection_menu_views.cc
+++ b/ui/views/touchui/touch_selection_menu_views.cc
@@ -129,7 +129,7 @@
   // Finally, add ellipses button.
   AddChildView(
       CreateButton(base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag));
-  InvalidateLayout();
+  Layout();
 }
 
 LabelButton* TouchSelectionMenuViews::CreateButton(const base::string16& title,
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 99a1f50..52a65e76 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -260,8 +260,7 @@
     // will have changed. Update the child's layer bounds, or if it is not a
     // layer, the bounds of any layers inside the child.
     if (base::i18n::IsRTL() && bounds_.width() != prev.width()) {
-      for (int i = 0; i < child_count(); ++i) {
-        View* child = child_at(i);
+      for (View* child : children_) {
         child->UpdateChildLayerBounds(
             LayerOffsetData(layer()->device_scale_factor(),
                             child->GetMirroredPosition().OffsetFromOrigin()));
@@ -602,13 +601,8 @@
   if (layout_manager_)
     layout_manager_->InvalidateLayout();
 
-  if (parent_) {
+  if (parent_)
     parent_->InvalidateLayout();
-  } else {
-    Widget* widget = GetWidget();
-    if (widget)
-      widget->ScheduleLayout();
-  }
 }
 
 LayoutManager* View::GetLayoutManager() const {
@@ -2217,16 +2211,16 @@
 void View::RegisterChildrenForVisibleBoundsNotification(View* view) {
   if (view->GetNeedsNotificationWhenVisibleBoundsChange())
     view->RegisterForVisibleBoundsNotification();
-  for (int i = 0; i < view->child_count(); ++i)
-    RegisterChildrenForVisibleBoundsNotification(view->child_at(i));
+  for (View* child : view->children_)
+    RegisterChildrenForVisibleBoundsNotification(child);
 }
 
 // static
 void View::UnregisterChildrenForVisibleBoundsNotification(View* view) {
   if (view->GetNeedsNotificationWhenVisibleBoundsChange())
     view->UnregisterForVisibleBoundsNotification();
-  for (int i = 0; i < view->child_count(); ++i)
-    UnregisterChildrenForVisibleBoundsNotification(view->child_at(i));
+  for (View* child : view->children_)
+    UnregisterChildrenForVisibleBoundsNotification(child);
 }
 
 void View::RegisterForVisibleBoundsNotification() {
diff --git a/ui/views/view.h b/ui/views/view.h
index 125ac49..d95d572 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1432,7 +1432,6 @@
   friend class FocusManager;
   friend class ViewLayerTest;
   friend class ViewLayerPixelCanvasTest;
-  friend class ViewTestApi;
   friend class Widget;
   FRIEND_TEST_ALL_PREFIXES(ViewTest, PaintWithMovedViewUsesCache);
   FRIEND_TEST_ALL_PREFIXES(ViewTest, PaintWithMovedViewUsesCacheInRTL);
diff --git a/ui/views/view_model_utils.cc b/ui/views/view_model_utils.cc
index 4bb3ac4..bef36a6 100644
--- a/ui/views/view_model_utils.cc
+++ b/ui/views/view_model_utils.cc
@@ -14,10 +14,8 @@
 namespace {
 
 // Used in calculating ideal bounds.
-int primary_axis_coordinate(ViewModelUtils::Alignment alignment,
-                            int x,
-                            int y) {
-  return alignment == ViewModelUtils::HORIZONTAL ? x : y;
+int primary_axis_coordinate(bool is_horizontal, int x, int y) {
+  return is_horizontal ? x : y;
 }
 
 }  // namespace
@@ -41,15 +39,15 @@
 // static
 int ViewModelUtils::DetermineMoveIndex(const ViewModelBase& model,
                                        View* view,
-                                       Alignment alignment,
+                                       bool is_horizontal,
                                        int x,
                                        int y) {
-  int value = primary_axis_coordinate(alignment, x, y);
+  int value = primary_axis_coordinate(is_horizontal, x, y);
   int current_index = model.GetIndexOfView(view);
   DCHECK_NE(-1, current_index);
   for (int i = 0; i < current_index; ++i) {
     int mid_point = primary_axis_coordinate(
-        alignment,
+        is_horizontal,
         model.ideal_bounds(i).x() + model.ideal_bounds(i).width() / 2,
         model.ideal_bounds(i).y() + model.ideal_bounds(i).height() / 2);
     if (value < mid_point)
@@ -61,17 +59,16 @@
 
   // For indices after the current index ignore the bounds of the view being
   // dragged. This keeps the view from bouncing around as moved.
-  int delta = primary_axis_coordinate(
-      alignment,
-      model.ideal_bounds(current_index + 1).x() -
-      model.ideal_bounds(current_index).x(),
-      model.ideal_bounds(current_index + 1).y() -
-      model.ideal_bounds(current_index).y());
+  int delta =
+      primary_axis_coordinate(is_horizontal,
+                              model.ideal_bounds(current_index + 1).x() -
+                                  model.ideal_bounds(current_index).x(),
+                              model.ideal_bounds(current_index + 1).y() -
+                                  model.ideal_bounds(current_index).y());
   for (int i = current_index + 1; i < model.view_size(); ++i) {
     const gfx::Rect& bounds(model.ideal_bounds(i));
     int mid_point = primary_axis_coordinate(
-        alignment,
-        bounds.x() + bounds.width() / 2 - delta,
+        is_horizontal, bounds.x() + bounds.width() / 2 - delta,
         bounds.y() + bounds.height() / 2 - delta);
     if (value < mid_point)
       return i - 1;
diff --git a/ui/views/view_model_utils.h b/ui/views/view_model_utils.h
index 7bd2f20..e37b582f 100644
--- a/ui/views/view_model_utils.h
+++ b/ui/views/view_model_utils.h
@@ -15,11 +15,6 @@
 
 class VIEWS_EXPORT ViewModelUtils {
  public:
-  enum Alignment {
-    HORIZONTAL,
-    VERTICAL
-  };
-
   // Sets the bounds of each view to its ideal bounds.
   static void SetViewBoundsToIdealBounds(const ViewModelBase& model);
 
@@ -29,7 +24,7 @@
   // Returns the index to move |view| to based on a coordinate of |x| and |y|.
   static int DetermineMoveIndex(const ViewModelBase& model,
                                 View* view,
-                                Alignment alignment,
+                                bool is_horizontal,
                                 int x,
                                 int y);
 
diff --git a/ui/views/view_model_utils_unittest.cc b/ui/views/view_model_utils_unittest.cc
index 92004b7..5b9349e 100644
--- a/ui/views/view_model_utils_unittest.cc
+++ b/ui/views/view_model_utils_unittest.cc
@@ -32,46 +32,30 @@
   model.set_ideal_bounds(1, gfx::Rect(10, 0, 1000, 10));
   model.set_ideal_bounds(2, gfx::Rect(1010, 0, 2, 10));
 
-  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::HORIZONTAL, -10, 0));
-  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::HORIZONTAL, 4, 0));
-  EXPECT_EQ(1, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::HORIZONTAL, 506, 0));
-  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::HORIZONTAL, 1010, 0));
-  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::HORIZONTAL, 2000, 0));
+  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v1, true, -10, 0));
+  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v1, true, 4, 0));
+  EXPECT_EQ(1, ViewModelUtils::DetermineMoveIndex(model, &v1, true, 506, 0));
+  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v1, true, 1010, 0));
+  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v1, true, 2000, 0));
 
-  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
-                model, &v2, ViewModelUtils::HORIZONTAL, -10, 0));
-  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
-                model, &v2, ViewModelUtils::HORIZONTAL, 4, 0));
-  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
-                model, &v2, ViewModelUtils::HORIZONTAL, 12, 0));
+  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v2, true, -10, 0));
+  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v2, true, 4, 0));
+  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v2, true, 12, 0));
 
   // Try the same when vertical.
   model.set_ideal_bounds(0, gfx::Rect(0, 0, 10, 10));
   model.set_ideal_bounds(1, gfx::Rect(0, 10, 10, 1000));
   model.set_ideal_bounds(2, gfx::Rect(0, 1010, 10, 2));
 
-  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::VERTICAL, 0, -10));
-  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::VERTICAL, 0, 4));
-  EXPECT_EQ(1, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::VERTICAL, 0, 506));
-  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::VERTICAL, 0, 1010));
-  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
-                model, &v1, ViewModelUtils::VERTICAL, 0, 2000));
+  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v1, false, 0, -10));
+  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v1, false, 0, 4));
+  EXPECT_EQ(1, ViewModelUtils::DetermineMoveIndex(model, &v1, false, 0, 506));
+  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v1, false, 0, 1010));
+  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v1, false, 0, 2000));
 
-  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
-                model, &v2, ViewModelUtils::VERTICAL, 0, -10));
-  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(
-                model, &v2, ViewModelUtils::VERTICAL, 0, 4));
-  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(
-                model, &v2, ViewModelUtils::VERTICAL, 0, 12));
+  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v2, false, 0, -10));
+  EXPECT_EQ(0, ViewModelUtils::DetermineMoveIndex(model, &v2, false, 0, 4));
+  EXPECT_EQ(2, ViewModelUtils::DetermineMoveIndex(model, &v2, false, 0, 12));
 }
 
 }  // namespace views
diff --git a/ui/views/view_test_api.h b/ui/views/view_test_api.h
deleted file mode 100644
index 9c0f7acc..0000000
--- a/ui/views/view_test_api.h
+++ /dev/null
@@ -1,27 +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 UI_VIEWS_VIEW_TEST_API_H_
-#define UI_VIEWS_VIEW_TEST_API_H_
-
-#include "ui/views/view.h"
-
-namespace views {
-
-class VIEWS_EXPORT ViewTestApi {
- public:
-  explicit ViewTestApi(View* view) : view_(view) {}
-  ~ViewTestApi() = default;
-
-  bool needs_layout() { return view_->needs_layout(); }
-
- private:
-  View* view_;
-
-  DISALLOW_COPY_AND_ASSIGN(ViewTestApi);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_VIEW_TEST_API_H_
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 6c19974..5b0508b 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -911,13 +911,6 @@
     content_window_->SchedulePaintInRect(rect);
 }
 
-void DesktopNativeWidgetAura::ScheduleLayout() {
-  // ScheduleDraw() triggers a callback to
-  // WindowDelegate::UpdateVisualState().
-  if (content_window_)
-    content_window_->ScheduleDraw();
-}
-
 void DesktopNativeWidgetAura::SetCursor(gfx::NativeCursor cursor) {
   cursor_ = cursor;
   aura::client::CursorClient* cursor_client =
@@ -1091,10 +1084,6 @@
   native_widget_delegate_->GetHitTestMask(mask);
 }
 
-void DesktopNativeWidgetAura::UpdateVisualState() {
-  native_widget_delegate_->LayoutRootViewIfNecessary();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopNativeWidgetAura, ui::EventHandler implementation:
 
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index bed6fa5..45319529 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -173,7 +173,6 @@
                     int operation,
                     ui::DragDropTypes::DragEventSource source) override;
   void SchedulePaintInRect(const gfx::Rect& rect) override;
-  void ScheduleLayout() override;
   void SetCursor(gfx::NativeCursor cursor) override;
   bool IsMouseEventsEnabled() const override;
   bool IsMouseButtonDown() const override;
@@ -214,7 +213,6 @@
   void OnWindowTargetVisibilityChanged(bool visible) override;
   bool HasHitTestMask() const override;
   void GetHitTestMask(SkPath* mask) const override;
-  void UpdateVisualState() override;
 
   // Overridden from ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* event) override;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index ac7c92d..1afcdd74 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -549,6 +549,7 @@
     non_client_view->client_view()->InvalidateLayout();
     non_client_view->InvalidateLayout();
   }
+  widget->GetRootView()->Layout();
 }
 
 void DesktopWindowTreeHostPlatform::RemoveNonClientEventFilter() {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 26290c4..867867b53 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -2009,6 +2009,7 @@
     non_client_view->client_view()->InvalidateLayout();
     non_client_view->InvalidateLayout();
   }
+  widget->GetRootView()->Layout();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 1659e91..6de855c 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -700,12 +700,6 @@
     window_->SchedulePaintInRect(rect);
 }
 
-void NativeWidgetAura::ScheduleLayout() {
-  // ScheduleDraw() triggers a callback to WindowDelegate::UpdateVisualState().
-  if (window_)
-    window_->ScheduleDraw();
-}
-
 void NativeWidgetAura::SetCursor(gfx::NativeCursor cursor) {
   cursor_ = cursor;
   aura::client::CursorClient* cursor_client =
@@ -922,10 +916,6 @@
   delegate_->GetHitTestMask(mask);
 }
 
-void NativeWidgetAura::UpdateVisualState() {
-  delegate_->LayoutRootViewIfNecessary();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // NativeWidgetAura, aura::WindowObserver implementation:
 
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h
index 9f50fed..c71289dc 100644
--- a/ui/views/widget/native_widget_aura.h
+++ b/ui/views/widget/native_widget_aura.h
@@ -134,7 +134,6 @@
                     int operation,
                     ui::DragDropTypes::DragEventSource source) override;
   void SchedulePaintInRect(const gfx::Rect& rect) override;
-  void ScheduleLayout() override;
   void SetCursor(gfx::NativeCursor cursor) override;
   bool IsMouseEventsEnabled() const override;
   bool IsMouseButtonDown() const override;
@@ -174,7 +173,6 @@
   void OnWindowTargetVisibilityChanged(bool visible) override;
   bool HasHitTestMask() const override;
   void GetHitTestMask(SkPath* mask) const override;
-  void UpdateVisualState() override;
 
   // Overridden from aura::WindowObserver:
   void OnWindowPropertyChanged(aura::Window* window,
diff --git a/ui/views/widget/native_widget_delegate.h b/ui/views/widget/native_widget_delegate.h
index 57fdde7..8965822 100644
--- a/ui/views/widget/native_widget_delegate.h
+++ b/ui/views/widget/native_widget_delegate.h
@@ -155,9 +155,6 @@
       gfx::NativeView child,
       ui::Layer* child_layer,
       const gfx::Point& location) = 0;
-
-  // Called to process a previous call to ScheduleLayout().
-  virtual void LayoutRootViewIfNecessary() = 0;
 };
 
 }  // namespace internal
diff --git a/ui/views/widget/native_widget_mac.h b/ui/views/widget/native_widget_mac.h
index dba6b57..da7a220 100644
--- a/ui/views/widget/native_widget_mac.h
+++ b/ui/views/widget/native_widget_mac.h
@@ -80,11 +80,6 @@
                               WindowOpenDisposition window_open_disposition,
                               bool is_before_first_responder);
 
-  ui::Compositor* GetCompositor() {
-    return const_cast<ui::Compositor*>(
-        const_cast<const NativeWidgetMac*>(this)->GetCompositor());
-  }
-
   // internal::NativeWidgetPrivate:
   void InitNativeWidget(const Widget::InitParams& params) override;
   void OnWidgetInitDone() override;
@@ -156,7 +151,6 @@
                     int operation,
                     ui::DragDropTypes::DragEventSource source) override;
   void SchedulePaintInRect(const gfx::Rect& rect) override;
-  void ScheduleLayout() override;
   void SetCursor(gfx::NativeCursor cursor) override;
   void ShowEmojiPanel() override;
   bool IsMouseEventsEnabled() const override;
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index c464e86..be935af 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -576,12 +576,6 @@
     bridge_host_->layer()->SchedulePaint(rect);
 }
 
-void NativeWidgetMac::ScheduleLayout() {
-  ui::Compositor* compositor = GetCompositor();
-  if (compositor)
-    compositor->ScheduleDraw();
-}
-
 void NativeWidgetMac::SetCursor(gfx::NativeCursor cursor) {
   if (bridge_impl())
     bridge_impl()->SetCursor(cursor);
diff --git a/ui/views/widget/native_widget_private.h b/ui/views/widget/native_widget_private.h
index c02942b..e594c69 100644
--- a/ui/views/widget/native_widget_private.h
+++ b/ui/views/widget/native_widget_private.h
@@ -213,7 +213,6 @@
                             int operation,
                             ui::DragDropTypes::DragEventSource source) = 0;
   virtual void SchedulePaintInRect(const gfx::Rect& rect) = 0;
-  virtual void ScheduleLayout() = 0;
   virtual void SetCursor(gfx::NativeCursor cursor) = 0;
   virtual void ShowEmojiPanel();
   virtual bool IsMouseEventsEnabled() const = 0;
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 07ac221d..1bf59a1 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -56,8 +56,8 @@
   if (view->layer()) {
     views->push_back(view);
   } else {
-    for (int i = 0; i < view->child_count(); ++i)
-      BuildViewsWithLayers(view->child_at(i), views);
+    for (View* child : view->children())
+      BuildViewsWithLayers(child, views);
   }
 }
 
@@ -700,7 +700,7 @@
   native_widget_->SetFullscreen(fullscreen);
 
   if (non_client_view_)
-    non_client_view_->InvalidateLayout();
+    non_client_view_->Layout();
 }
 
 bool Widget::IsFullscreen() const {
@@ -815,10 +815,6 @@
   native_widget_->SchedulePaintInRect(rect);
 }
 
-void Widget::ScheduleLayout() {
-  native_widget_->ScheduleLayout();
-}
-
 void Widget::SetCursor(gfx::NativeCursor cursor) {
   native_widget_->SetCursor(cursor);
 }
@@ -1417,11 +1413,6 @@
   return true;
 }
 
-void Widget::LayoutRootViewIfNecessary() {
-  if (root_view_ && root_view_->needs_layout())
-    root_view_->Layout();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Widget, ui::EventSource implementation:
 ui::EventSink* Widget::GetEventSink() {
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 06119b2..6f1f45f 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -632,10 +632,6 @@
   // redrawn.
   virtual void SchedulePaintInRect(const gfx::Rect& rect);
 
-  // Schedule a layout to occur. This is called by RootView, client code should
-  // not need to call this.
-  void ScheduleLayout();
-
   // Sets the currently visible cursor. If |cursor| is NULL, the cursor used
   // before the current is restored.
   void SetCursor(gfx::NativeCursor cursor);
@@ -857,7 +853,6 @@
       gfx::NativeView child,
       ui::Layer* child_layer,
       const gfx::Point& location) override;
-  void LayoutRootViewIfNecessary() override;
 
   // Overridden from ui::EventSource:
   ui::EventSink* GetEventSink() override;
@@ -888,8 +883,8 @@
   virtual void OnDragComplete();
 
  private:
-  friend class ButtonTest;
   friend class ComboboxTest;
+  friend class ButtonTest;
   friend class TextfieldTest;
   friend class ViewAuraTest;
   friend void DisableActivationChangeHandlingForTests();
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc
index 445b318c..2f05546 100644
--- a/ui/views/widget/widget_interactive_uitest.cc
+++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -634,15 +634,12 @@
 // Tests mouse move outside of the window into the "resize controller" and back
 // will still generate an OnMouseEntered and OnMouseExited event..
 TEST_F(WidgetTestInteractive, CheckResizeControllerEvents) {
-  Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
+  Widget* toplevel = CreateTopLevelPlatformWidget();
 
   toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
 
   MouseView* view = new MouseView();
   view->SetBounds(90, 90, 10, 10);
-  // |view| needs to be a particular size. Reset the LayoutManager so that
-  // it doesn't get resized.
-  toplevel->GetRootView()->SetLayoutManager(nullptr);
   toplevel->GetRootView()->AddChildView(view);
 
   toplevel->Show();
@@ -814,9 +811,9 @@
   EXPECT_TRUE(::IsWindowEnabled(hwnd));
   EXPECT_EQ(hwnd, ::GetActiveWindow());
 
-  for (int i = 0; i < widget->GetContentsView()->child_count(); ++i) {
-    SCOPED_TRACE(base::StringPrintf("Child view %d", i));
-    View* view = widget->GetContentsView()->child_at(i);
+  for (View* view : widget->GetContentsView()->children()) {
+    SCOPED_TRACE(base::StringPrintf(
+        "Child view %d", widget->GetContentsView()->GetIndexOf(view)));
 
     view->RequestFocus();
     EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index ee89998..fea8ac0c 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -17,7 +17,6 @@
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/compositor/test/draw_waiter_for_test.h"
 #include "ui/events/event_observer.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/test/event_generator.h"
@@ -26,12 +25,10 @@
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/event_monitor.h"
-#include "ui/views/layout/fill_layout.h"
 #include "ui/views/test/native_widget_factory.h"
 #include "ui/views/test/test_views.h"
 #include "ui/views/test/test_widget_observer.h"
 #include "ui/views/test/widget_test.h"
-#include "ui/views/view_test_api.h"
 #include "ui/views/widget/native_widget_delegate.h"
 #include "ui/views/widget/native_widget_private.h"
 #include "ui/views/widget/root_view.h"
@@ -560,7 +557,68 @@
 // Test to verify using various Widget methods doesn't crash when the underlying
 // NativeView is destroyed.
 //
-using WidgetWithDestroyedNativeViewTest = ViewsTestBaseWithNativeWidgetType;
+class WidgetWithDestroyedNativeViewTest
+    : public ViewsTestBase,
+      public testing::WithParamInterface<ViewsTestBase::NativeWidgetType> {
+ public:
+  WidgetWithDestroyedNativeViewTest() = default;
+  ~WidgetWithDestroyedNativeViewTest() override = default;
+
+  // ViewsTestBase:
+  void SetUp() override {
+    set_native_widget_type(GetParam());
+    ViewsTestBase::SetUp();
+  }
+
+  void InvokeWidgetMethods(Widget* widget) {
+    widget->GetNativeView();
+    widget->GetNativeWindow();
+    ui::Accelerator accelerator;
+    widget->GetAccelerator(0, &accelerator);
+    widget->GetTopLevelWidget();
+    widget->GetWindowBoundsInScreen();
+    widget->GetClientAreaBoundsInScreen();
+    widget->SetBounds(gfx::Rect(0, 0, 100, 80));
+    widget->SetSize(gfx::Size(10, 11));
+    widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
+    widget->SetVisibilityChangedAnimationsEnabled(false);
+    widget->StackAtTop();
+    widget->IsClosed();
+    widget->Close();
+    widget->Hide();
+    widget->Activate();
+    widget->Deactivate();
+    widget->IsActive();
+    widget->SetAlwaysOnTop(true);
+    widget->IsAlwaysOnTop();
+    widget->Maximize();
+    widget->Minimize();
+    widget->Restore();
+    widget->IsMaximized();
+    widget->IsFullscreen();
+    widget->SetOpacity(0.f);
+    widget->FlashFrame(true);
+    widget->IsVisible();
+    widget->GetThemeProvider();
+    widget->GetNativeTheme();
+    widget->GetFocusManager();
+    widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
+    widget->IsMouseEventsEnabled();
+    widget->SetNativeWindowProperty("xx", widget);
+    widget->GetNativeWindowProperty("xx");
+    widget->GetFocusTraversable();
+    widget->GetLayer();
+    widget->ReorderNativeViews();
+    widget->SetCapture(widget->GetRootView());
+    widget->ReleaseCapture();
+    widget->HasCapture();
+    widget->GetWorkAreaBoundsInScreen();
+    widget->IsTranslucentWindowOpacitySupported();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
+};
 
 TEST_P(WidgetWithDestroyedNativeViewTest, Test) {
   Widget widget;
@@ -570,49 +628,7 @@
   widget.Show();
 
   widget.native_widget_private()->CloseNow();
-  widget.GetNativeView();
-  widget.GetNativeWindow();
-  ui::Accelerator accelerator;
-  widget.GetAccelerator(0, &accelerator);
-  widget.GetTopLevelWidget();
-  widget.GetWindowBoundsInScreen();
-  widget.GetClientAreaBoundsInScreen();
-  widget.SetBounds(gfx::Rect(0, 0, 100, 80));
-  widget.SetSize(gfx::Size(10, 11));
-  widget.SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
-  widget.SetVisibilityChangedAnimationsEnabled(false);
-  widget.StackAtTop();
-  widget.IsClosed();
-  widget.Close();
-  widget.Hide();
-  widget.Activate();
-  widget.Deactivate();
-  widget.IsActive();
-  widget.SetAlwaysOnTop(true);
-  widget.IsAlwaysOnTop();
-  widget.Maximize();
-  widget.Minimize();
-  widget.Restore();
-  widget.IsMaximized();
-  widget.IsFullscreen();
-  widget.SetOpacity(0.f);
-  widget.FlashFrame(true);
-  widget.IsVisible();
-  widget.GetThemeProvider();
-  widget.GetNativeTheme();
-  widget.GetFocusManager();
-  widget.SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
-  widget.IsMouseEventsEnabled();
-  widget.SetNativeWindowProperty("xx", &widget);
-  widget.GetNativeWindowProperty("xx");
-  widget.GetFocusTraversable();
-  widget.GetLayer();
-  widget.ReorderNativeViews();
-  widget.SetCapture(widget.GetRootView());
-  widget.ReleaseCapture();
-  widget.HasCapture();
-  widget.GetWorkAreaBoundsInScreen();
-  widget.IsTranslucentWindowOpacitySupported();
+  InvokeWidgetMethods(&widget);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -3324,8 +3340,6 @@
   EXPECT_FALSE(frame->fullscreen_layout_called());
   widget->SetFullscreen(true);
   widget->Show();
-  EXPECT_TRUE(ViewTestApi(frame).needs_layout());
-  widget->LayoutRootViewIfNecessary();
   RunPendingMessages();
 
   EXPECT_TRUE(frame->fullscreen_layout_called());
@@ -3797,84 +3811,6 @@
   EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSEWHEEL));
 }
 
-class LayoutCountingView : public View {
- public:
-  LayoutCountingView() = default;
-  ~LayoutCountingView() override = default;
-
-  void set_layout_closure(base::OnceClosure layout_closure) {
-    layout_closure_ = std::move(layout_closure);
-  }
-
-  size_t GetAndClearLayoutCount() {
-    const size_t count = layout_count_;
-    layout_count_ = 0u;
-    return count;
-  }
-
-  // View:
-  void Layout() override {
-    ++layout_count_;
-    View::Layout();
-    if (layout_closure_)
-      std::move(layout_closure_).Run();
-  }
-
- private:
-  size_t layout_count_ = 0u;
-
-  // If valid, this is run when Layout() is called.
-  base::OnceClosure layout_closure_;
-
-  DISALLOW_COPY_AND_ASSIGN(LayoutCountingView);
-};
-
-using WidgetInvalidateLayoutTest = ViewsTestBaseWithNativeWidgetType;
-
-TEST_P(WidgetInvalidateLayoutTest, InvalidateLayout) {
-  Widget widget;
-  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
-  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  widget.Init(params);
-  widget.SetBounds(gfx::Rect(0, 0, 600, 600));
-  LayoutCountingView* view =
-      widget.widget_delegate()->GetContentsView()->AddChildView(
-          std::make_unique<LayoutCountingView>());
-  view->parent()->SetLayoutManager(std::make_unique<FillLayout>());
-  // Force an initial Layout().
-  // TODO(sky): this shouldn't be necessary, adding a child view should trigger
-  // ScheduleLayout().
-  view->Layout();
-  widget.Show();
-
-  ui::Compositor* compositor = widget.GetCompositor();
-  ASSERT_TRUE(compositor);
-  compositor->ScheduleDraw();
-  ui::DrawWaiterForTest::WaitForCompositingEnded(compositor);
-
-  base::RunLoop run_loop;
-  view->GetAndClearLayoutCount();
-  // Don't use WaitForCompositingEnded() here as it's entirely possible nothing
-  // will be drawn (which means WaitForCompositingEnded() isn't run). Instead
-  // wait for Layout() to be called.
-  view->set_layout_closure(run_loop.QuitClosure());
-  EXPECT_FALSE(ViewTestApi(view).needs_layout());
-  EXPECT_FALSE(ViewTestApi(widget.GetRootView()).needs_layout());
-  view->InvalidateLayout();
-  EXPECT_TRUE(ViewTestApi(view).needs_layout());
-  EXPECT_TRUE(ViewTestApi(widget.GetRootView()).needs_layout());
-  run_loop.Run();
-  EXPECT_EQ(1u, view->GetAndClearLayoutCount());
-  EXPECT_FALSE(ViewTestApi(view).needs_layout());
-  EXPECT_FALSE(ViewTestApi(widget.GetRootView()).needs_layout());
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    WidgetInvalidateLayoutTest,
-    WidgetInvalidateLayoutTest,
-    ::testing::Values(ViewsTestBase::NativeWidgetType::kDefault,
-                      ViewsTestBase::NativeWidgetType::kDesktop));
-
 class WidgetShadowTest : public WidgetTest {
  public:
   WidgetShadowTest() = default;
diff --git a/ui/views/widget/window_reorderer.cc b/ui/views/widget/window_reorderer.cc
index b51ba17..2e167bb 100644
--- a/ui/views/widget/window_reorderer.cc
+++ b/ui/views/widget/window_reorderer.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <algorithm>
 #include <map>
 #include <vector>
 
@@ -53,8 +54,8 @@
     order->push_back(view);
   }
 
-  for (int i = 0; i < view->child_count(); ++i)
-    GetOrderOfViewsWithLayers(view->child_at(i), parent_layer, hosts, order);
+  for (views::View* child : view->children())
+    GetOrderOfViewsWithLayers(child, parent_layer, hosts, order);
 }
 
 }  // namespace
@@ -161,6 +162,8 @@
   GetOrderOfViewsWithLayers(root_view_, parent_window_->layer(), hosted_windows,
       &view_with_layer_order);
 
+  std::vector<ui::Layer*> children_layer_order;
+
   // For the sake of simplicity, reorder both the layers owned by views and the
   // layers of windows associated with a view. Iterate through
   // |view_with_layer_order| backwards and stack windows at the bottom so that
@@ -181,8 +184,10 @@
     DCHECK(layer);
     if (window)
       parent_window_->StackChildAtBottom(window);
-    parent_window_->layer()->StackAtBottom(layer);
+    children_layer_order.emplace_back(layer);
   }
+  std::reverse(children_layer_order.begin(), children_layer_order.end());
+  parent_window_->layer()->StackChildrenAtBottom(children_layer_order);
 }
 
 void WindowReorderer::OnWindowAdded(aura::Window* new_window) {
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc
index bf21e227..068aac6 100644
--- a/ui/views/window/dialog_client_view.cc
+++ b/ui/views/window/dialog_client_view.cc
@@ -264,11 +264,16 @@
   return GetWidget()->widget_delegate()->AsDialogDelegate();
 }
 
+void DialogClientView::ChildPreferredSizeChanged(View* child) {
+  if (!adding_or_removing_views_ && child == extra_view_)
+    Layout();
+}
+
 void DialogClientView::ChildVisibilityChanged(View* child) {
   // Showing or hiding |extra_view_| can alter which columns have linked sizes.
   if (child == extra_view_)
     UpdateDialogButtons();
-  InvalidateLayout();
+  ChildPreferredSizeChanged(child);
 }
 
 void DialogClientView::OnDialogChanged() {
diff --git a/ui/views/window/dialog_client_view.h b/ui/views/window/dialog_client_view.h
index 6a894a0..47c80e6e6 100644
--- a/ui/views/window/dialog_client_view.h
+++ b/ui/views/window/dialog_client_view.h
@@ -84,6 +84,7 @@
   DialogDelegate* GetDialogDelegate() const;
 
   // View implementation.
+  void ChildPreferredSizeChanged(View* child) override;
   void ChildVisibilityChanged(View* child) override;
 
   // DialogObserver:
diff --git a/ui/views/window/dialog_delegate_unittest.cc b/ui/views/window/dialog_delegate_unittest.cc
index b8e92a1..61f2f236 100644
--- a/ui/views/window/dialog_delegate_unittest.cc
+++ b/ui/views/window/dialog_delegate_unittest.cc
@@ -263,7 +263,6 @@
   const NonClientView* view = dialog()->GetWidget()->non_client_view();
   dialog()->set_title(base::ASCIIToUTF16("Title"));
   dialog()->GetWidget()->UpdateWindowTitle();
-  dialog()->GetWidget()->LayoutRootViewIfNecessary();
   BubbleFrameView* frame = static_cast<BubbleFrameView*>(view->frame_view());
 
   struct {
diff --git a/ui/views/window/non_client_view.cc b/ui/views/window/non_client_view.cc
index c8cb1ba..8786480 100644
--- a/ui/views/window/non_client_view.cc
+++ b/ui/views/window/non_client_view.cc
@@ -87,7 +87,7 @@
   Widget* widget = GetWidget();
   SetFrameView(widget->CreateNonClientFrameView());
   widget->ThemeChanged();
-  InvalidateLayout();
+  Layout();
   SchedulePaint();
 }
 
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html b/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html
index b8fef49..89cea2f 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html
@@ -32,7 +32,8 @@
       <div class="property-box single-column indented stretch">
         <network-property-list fields="[[ipConfigFields_]]"
             property-dict="[[ipConfig_]]"
-            edit-field-types="[[getIPEditFields_(automatic_)]]"
+            edit-field-types="[[getIPEditFields_(automatic_,
+                networkProperties)]]"
             on-property-change="onIPChange_">
         </network-property-list>
       </div>
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js b/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
index d96d0e3..0b3c8d2 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
@@ -109,14 +109,8 @@
    * @private
    */
   canChangeIPConfigType_: function(networkProperties) {
-    const controlledProps = [
-      'IPAddressConfigType', 'StaticIPConfig.IPAddress',
-      'StaticIPConfig.RoutingPrefix', 'StaticIPConfig.Gateway'
-    ];
-
-    return controlledProps.every(
-        setting =>
-            !this.isNetworkPolicyPathEnforced(networkProperties, setting));
+    return !this.isNetworkPolicyPathEnforced(
+        networkProperties, 'IPAddressConfigType');
   },
 
   /** @private */
@@ -209,17 +203,32 @@
   },
 
   /**
+   * @param {string} path path to a property inside of |networkProperties|
+   * dictionary.
+   * @return {string|undefined} Edit type to be used in network-property-list
+   * for the given path.
+   * @private
+   */
+  getIPFieldEditType_: function(path) {
+    return this.networkProperties &&
+            this.isNetworkPolicyPathEnforced(this.networkProperties, path) ?
+        undefined :
+        'String';
+  },
+
+  /**
    * @return {Object} An object with the edit type for each editable field.
    * @private
    */
   getIPEditFields_: function() {
-    if (this.automatic_) {
+    if (this.automatic_ || !this.networkProperties) {
       return {};
     }
     return {
-      'ipv4.IPAddress': 'String',
-      'ipv4.RoutingPrefix': 'String',
-      'ipv4.Gateway': 'String'
+      'ipv4.IPAddress': this.getIPFieldEditType_('StaticIPConfig.IPAddress'),
+      'ipv4.RoutingPrefix':
+          this.getIPFieldEditType_('StaticIPConfig.RoutingPrefix'),
+      'ipv4.Gateway': this.getIPFieldEditType_('StaticIPConfig.Gateway')
     };
   },
 
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js b/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
index c23d6435..356107a 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
@@ -725,3 +725,18 @@
   }
   return undefined;
 };
+
+/**
+ * Returns whether |properties| has a Cellular or Tether network type.
+ * @param {!CrOnc.NetworkProperties|!CrOnc.NetworkStateProperties|undefined}
+ *     properties The ONC property dictionary to be checked.
+ * @return {boolean}
+ */
+CrOnc.isMobileNetwork = function(properties) {
+  if (!properties) {
+    return false;
+  }
+
+  const type = properties.Type;
+  return type == CrOnc.Type.CELLULAR || type == CrOnc.Type.TETHER;
+};