diff --git a/DEPS b/DEPS
index 8fb6636..c38bccf9 100644
--- a/DEPS
+++ b/DEPS
@@ -110,11 +110,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': 'dd254486280df922f6ba845ddee6db440e5c0d6f',
+  'skia_revision': '0c583af06d50cf3a11a39f5804eccdeefd74fc02',
   # 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': 'fc50b795db2e0bb5875680b9757b7e413db67fa2',
+  'v8_revision': '9d59bf5f48d68b1f6114c2e90c5bb34233d64218',
   # 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.
@@ -122,7 +122,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '945dea36ab8ac7a6ad6b057eb83901c17bf72388',
+  'angle_revision': 'c4765aa782676fd7afb47dff626f57f69534e76f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -142,7 +142,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '2d98d49cf712ca7dc6f4b23b9c5f5542385d8dbe',
+  'boringssl_revision': 'dd412c428ad7c2a60ae4709dfbad6301e499dcb8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -170,7 +170,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '3d878160972c48a536fdf9be9a9d0ab2892dea47',
+  'catapult_revision': '1922eb00bbd96108cc21a72e4286d0f913e0e317',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -218,7 +218,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '9aa14a38f43441dcd299192dd915eecf693ab0a8',
+  'spv_tools_revision': '0e68bb36327cf7e1b125e41a29e5280855671b5e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -610,7 +610,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '324e0418e81073103d5c7c7f2cc7922c7d1b413a',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '364a0d6bd98c50464e9c3e9d93e06834c27dc84a',
       'condition': 'checkout_linux',
   },
 
@@ -635,7 +635,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '488362624b6d263e7e59f5198f10216db1f284e6',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c1e6594df5801603668f4dcea4473c78b08c9223',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -964,7 +964,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '6db99a9ca272f437f3276839838fb86c4e9a0335',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '3f3d4308509c4c837d7c81d9124d44da1e7159e3',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1116,7 +1116,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '09beff2cfd84c3481b79a490414355fb1bf682e7',
+    Var('webrtc_git') + '/src.git' + '@' + '78416b6e1851f86a2091b0e06bb906731faa98e5',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1147,7 +1147,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2d0fa5b178404982cb663b281e1465dae73cffaf',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2ec8dc1f8ab8da9b7e74a5826e6d9265b1441e57',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/tools/remove_preinstalled_webview.py b/android_webview/tools/remove_preinstalled_webview.py
new file mode 100755
index 0000000..64e60b20
--- /dev/null
+++ b/android_webview/tools/remove_preinstalled_webview.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+#
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Removes the preinstalled WebView on a device to avoid signature mismatches.
+
+This should only be used by developers. This script will fail on actual user
+devices (and this configuration is not recommended for user devices).
+
+The recommended development configuration for Googlers is to satisfy all of the
+below:
+  1. The device has a Google-provided image.
+  2. The device does not have an image based on AOSP.
+  3. Set `use_signing_keys = true` in GN args.
+
+If any of the above are not satisfied (or if you're external to Google), you can
+use this script to remove the system-image WebView on your device, which will
+allow you to install a local WebView build without triggering signature
+mismatches (which would otherwise block installing the APK).
+
+After running this script, you should be able to build and install
+system_webview_apk.
+  * If your device does *not* have an AOSP-based image, you will need to set
+    `system_webview_package_name = "com.google.android.webview"` in GN args.
+"""
+
+from __future__ import print_function
+
+import argparse
+import logging
+import os
+import sys
+
+
+sys.path.append(os.path.join(
+    os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android'))
+import devil_chromium  # pylint: disable=import-error
+from devil.android import device_utils  # pylint: disable=import-error
+from devil.android.sdk import keyevent  # pylint: disable=import-error
+from devil.android.sdk import version_codes  # pylint: disable=import-error
+from devil.android.tools import script_common  # pylint: disable=import-error
+from devil.android.tools import system_app  # pylint: disable=import-error
+
+
+WEBVIEW_SYSTEM_IMAGE_PATHS = ['/system/app/webview',
+                              '/system/app/WebViewGoogle',
+                              '/system/app/WebViewStub']
+WEBVIEW_PACKAGES = ['com.android.webview', 'com.google.android.webview']
+
+
+def _UnlockDevice(device):
+  device.SendKeyEvent(keyevent.KEYCODE_MENU)
+
+
+def UninstallWebViewSystemImages(device):
+  """Uninstalls system images for known WebView packages."""
+  print('Removing system images from %s...' % device.serial)
+  system_app.RemoveSystemApps(device, WEBVIEW_PACKAGES)
+  _UnlockDevice(device)
+
+
+def UninstallWebViewUpdates(device):
+  """Uninstalls updates for WebView packages, if updates exist."""
+  print('Uninstalling updates from %s...' % device.serial)
+  for webview_package in WEBVIEW_PACKAGES:
+    paths = device.GetApplicationPaths(webview_package)
+    if not paths:
+      return  # Package isn't installed, nothing to do
+    if set(paths) <= set(WEBVIEW_SYSTEM_IMAGE_PATHS):
+      # If we only have preinstalled paths, don't try to uninstall updates
+      # (necessary, otherwise we will raise an exception on some devices).
+      return
+    device.Uninstall(webview_package)
+
+
+def AllowStandaloneWebView(device):
+  if device.build_version_sdk < version_codes.NOUGAT:
+    return
+  allow_standalone_webview = ['cmd', 'webviewupdate',
+                              'enable-redundant-packages']
+  device.RunShellCommand(allow_standalone_webview, check_return=True)
+
+
+def RemovePreinstalledWebViews(device):
+  device.EnableRoot()
+  UninstallWebViewUpdates(device)
+  UninstallWebViewSystemImages(device)
+  AllowStandaloneWebView(device)
+
+
+def main():
+  parser = argparse.ArgumentParser(description="""
+Removes the preinstalled WebView APKs to avoid signature mismatches during
+development.
+""")
+
+  parser.add_argument('--verbose', '-v', default=False, action='store_true')
+  parser.add_argument('--quiet', '-q', default=False, action='store_true')
+  script_common.AddEnvironmentArguments(parser)
+  script_common.AddDeviceArguments(parser)
+
+  args = parser.parse_args()
+  if args.verbose:
+    logging.basicConfig(stream=sys.stderr, level=logging.INFO)
+  elif args.quiet:
+    logging.basicConfig(stream=sys.stderr, level=logging.ERROR)
+  else:
+    logging.basicConfig(stream=sys.stderr, level=logging.WARN)
+
+  devil_chromium.Initialize()
+  script_common.InitializeEnvironment(args)
+
+  devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices)
+  device_utils.DeviceUtils.parallel(devices).pMap(RemovePreinstalledWebViews)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index ddc109d..582c1d0 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1409,6 +1409,7 @@
     "//net",
     "//services/content/public/cpp",
     "//services/data_decoder/public/cpp",
+    "//services/media_session/public/mojom",
     "//services/preferences/public/cpp",
     "//services/service_manager/public/cpp",
     "//services/ws/gpu_host",
@@ -2056,6 +2057,7 @@
     "//mojo/core/embedder",
     "//net:net",
     "//services/catalog:lib",
+    "//services/media_session/public/cpp/test:test_support",
     "//services/service_manager/public/cpp:service_test_support",
     "//services/ws:test_support",
     "//services/ws/public/cpp/input_devices:test_support",
diff --git a/ash/DEPS b/ash/DEPS
index a85cdb8..b269365 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -27,6 +27,7 @@
   "+mojo/public",
   "+services/catalog/public",
   "+services/content/public",
+  "+services/media_session/public",
   "+services/preferences/public",
   "+services/service_manager/public",
   "+services/viz/public",
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index f3c4753a3..d8a662c 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -41,6 +41,7 @@
 #include "base/run_loop.h"
 #include "base/test/metrics/user_action_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "services/media_session/public/cpp/test/test_media_controller.h"
 #include "services/ws/public/mojom/window_tree_constants.mojom.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/test/test_window_delegate.h"
@@ -842,25 +843,6 @@
   GetAppListTestHelper()->CheckVisibility(true);
 }
 
-TEST_F(AcceleratorControllerTest, MediaGlobalAccelerators) {
-  TestMediaClient client;
-  Shell::Get()->media_controller()->SetClient(client.CreateAssociatedPtrInfo());
-  EXPECT_EQ(0, client.handle_media_next_track_count());
-  ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(1, client.handle_media_next_track_count());
-
-  EXPECT_EQ(0, client.handle_media_play_pause_count());
-  ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(1, client.handle_media_play_pause_count());
-
-  EXPECT_EQ(0, client.handle_media_prev_track_count());
-  ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(1, client.handle_media_prev_track_count());
-}
-
 TEST_F(AcceleratorControllerTest, ImeGlobalAccelerators) {
   ASSERT_EQ(0u, Shell::Get()->ime_controller()->available_imes().size());
 
@@ -1523,11 +1505,28 @@
     }
 
     AcceleratorControllerTest::SetUp();
+
+    client_ = std::make_unique<TestMediaClient>();
+    controller_ = std::make_unique<media_session::test::TestMediaController>();
+
+    MediaController* media_controller = Shell::Get()->media_controller();
+    media_controller->SetClient(client_->CreateAssociatedPtrInfo());
+    media_controller->SetMediaSessionControllerForTest(
+        controller_->CreateMediaControllerPtr());
+  }
+
+  TestMediaClient* client() const { return client_.get(); }
+
+  media_session::test::TestMediaController* controller() const {
+    return controller_.get();
   }
 
   bool service_enabled() const { return GetParam(); }
 
  private:
+  std::unique_ptr<TestMediaClient> client_;
+  std::unique_ptr<media_session::test::TestMediaController> controller_;
+
   base::test::ScopedFeatureList scoped_feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaSessionAcceleratorTest);
@@ -1571,4 +1570,38 @@
   }
 }
 
+TEST_P(MediaSessionAcceleratorTest, MediaGlobalAccelerators_NextTrack) {
+  EXPECT_EQ(0, client()->handle_media_next_track_count());
+
+  ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE));
+  Shell::Get()->media_controller()->FlushForTesting();
+
+  EXPECT_EQ(1, client()->handle_media_next_track_count());
+}
+
+TEST_P(MediaSessionAcceleratorTest, MediaGlobalAccelerators_PlayPause) {
+  EXPECT_EQ(0, client()->handle_media_play_pause_count());
+  EXPECT_EQ(0, controller()->toggle_suspend_resume_count());
+
+  ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE));
+  Shell::Get()->media_controller()->FlushForTesting();
+
+  if (service_enabled()) {
+    EXPECT_EQ(0, client()->handle_media_play_pause_count());
+    EXPECT_EQ(1, controller()->toggle_suspend_resume_count());
+  } else {
+    EXPECT_EQ(1, client()->handle_media_play_pause_count());
+    EXPECT_EQ(0, controller()->toggle_suspend_resume_count());
+  }
+}
+
+TEST_P(MediaSessionAcceleratorTest, MediaGlobalAccelerators_PrevTrack) {
+  EXPECT_EQ(0, client()->handle_media_prev_track_count());
+
+  ProcessInController(ui::Accelerator(ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE));
+  Shell::Get()->media_controller()->FlushForTesting();
+
+  EXPECT_EQ(1, client()->handle_media_prev_track_count());
+}
+
 }  // namespace ash
diff --git a/ash/app_list/home_launcher_gesture_handler.cc b/ash/app_list/home_launcher_gesture_handler.cc
index 6f3b384..5ba8f9f 100644
--- a/ash/app_list/home_launcher_gesture_handler.cc
+++ b/ash/app_list/home_launcher_gesture_handler.cc
@@ -571,8 +571,15 @@
   // If fling velocity is greater than the threshold, show the launcher if
   // sliding up, or hide the launcher if sliding down, irregardless of
   // |last_event_location_|.
-  if (std::fabs(last_scroll_y_) > kScrollVelocityThreshold)
-    return mode_ == Mode::kSlideUpToShow;
+  if (mode_ == Mode::kSlideUpToShow &&
+      last_scroll_y_ < -kScrollVelocityThreshold) {
+    return true;
+  }
+
+  if (mode_ == Mode::kSlideDownToHide &&
+      last_scroll_y_ > kScrollVelocityThreshold) {
+    return false;
+  }
 
   return last_event_location_
              ? IsLastEventInTopHalf(*last_event_location_, display_.work_area())
diff --git a/ash/app_list/home_launcher_gesture_handler_unittest.cc b/ash/app_list/home_launcher_gesture_handler_unittest.cc
index 44d92bc..962b98c 100644
--- a/ash/app_list/home_launcher_gesture_handler_unittest.cc
+++ b/ash/app_list/home_launcher_gesture_handler_unittest.cc
@@ -138,6 +138,14 @@
   auto window = CreateWindowForTesting();
   ASSERT_TRUE(window->IsVisible());
 
+  // Tests that flinging down in this mode will keep the window visible.
+  DoPress(Mode::kSlideUpToShow);
+  GetGestureHandler()->OnScrollEvent(gfx::Point(0, 300), 10.f);
+  GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 300), nullptr);
+  ASSERT_TRUE(window->IsVisible());
+
+  // Tests that flinging up in this mode will hide the window and show the
+  // home launcher.
   DoPress(Mode::kSlideUpToShow);
   GetGestureHandler()->OnScrollEvent(gfx::Point(0, 300), -10.f);
   GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 300), nullptr);
@@ -153,6 +161,13 @@
   wm::GetWindowState(window.get())->Minimize();
   ASSERT_FALSE(window->IsVisible());
 
+  // Tests that flinging up in this mode will not show the mru window.
+  DoPress(Mode::kSlideDownToHide);
+  GetGestureHandler()->OnScrollEvent(gfx::Point(0, 100), -10.f);
+  GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100), nullptr);
+  ASSERT_FALSE(window->IsVisible());
+
+  // Tests that flinging down in this mode will show the mru window.
   DoPress(Mode::kSlideDownToHide);
   GetGestureHandler()->OnScrollEvent(gfx::Point(0, 100), 10.f);
   GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100), nullptr);
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index bf456fd..1863ab2 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -138,7 +138,8 @@
     std::unique_ptr<ui::Layer> old_layer = views::View::RecreateLayer();
 
     // ui::Layer::Clone() does not copy mask layer, so set it explicitly here.
-    SetRoundedRectMaskLayer(mask_corner_radius_, mask_insets_);
+    if (mask_corner_radius_ != 0 || !mask_insets_.IsEmpty())
+      SetRoundedRectMaskLayer(mask_corner_radius_, mask_insets_);
     return old_layer;
   }
 
@@ -162,7 +163,7 @@
   std::unique_ptr<ui::LayerOwner> icon_mask_;
 
   // The corner radius of mask layer.
-  int mask_corner_radius_;
+  int mask_corner_radius_ = 0;
 
   // The insets of the mask layer.
   gfx::Insets mask_insets_;
@@ -198,8 +199,10 @@
 
   if (is_new_style_launcher_enabled_ && is_folder_) {
     // Set background blur for folder icon and use mask layer to clip it into
-    // circle.
-    icon_->layer()->SetBackgroundBlur(AppListConfig::instance().blur_radius());
+    // circle. Note that blur is only enabled in tablet mode to improve dragging
+    // smoothness.
+    if (apps_grid_view_->IsTabletMode())
+      SetBackgroundBlurEnabled(true);
     icon_->SetRoundedRectMaskLayer(
         AppListConfig::instance().folder_icon_radius(),
         gfx::Insets(AppListConfig::instance().folder_icon_insets()));
@@ -745,6 +748,12 @@
   dragged_view_hover_animation_->Hide();
 }
 
+void AppListItemView::SetBackgroundBlurEnabled(bool enabled) {
+  DCHECK(is_folder_);
+  icon_->layer()->SetBackgroundBlur(
+      enabled ? AppListConfig::instance().blur_radius() : 0);
+}
+
 void AppListItemView::AnimationProgressed(const gfx::Animation* animation) {
   if (is_folder_) {
     // Animate the folder icon via changing mask layer's corner radius and
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h
index f29c586..fdf2997 100644
--- a/ash/app_list/views/app_list_item_view.h
+++ b/ash/app_list/views/app_list_item_view.h
@@ -131,6 +131,9 @@
   void OnDraggedViewEnter();
   void OnDraggedViewExit();
 
+  // Enables background blur for folder icon if |enabled| is true.
+  void SetBackgroundBlurEnabled(bool enabled);
+
  private:
   class IconImageView;
 
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 2714e4f..14e09ee9 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -1162,6 +1162,7 @@
   is_tablet_mode_ = started;
   search_box_view_->OnTabletModeChanged(started);
   search_model_->SetTabletMode(started);
+  GetAppsContainerView()->OnTabletModeChanged(started);
 
   if (is_home_launcher_enabled_) {
     if (!started) {
diff --git a/ash/app_list/views/apps_container_view.cc b/ash/app_list/views/apps_container_view.cc
index 9fffa38..0462b618 100644
--- a/ash/app_list/views/apps_container_view.cc
+++ b/ash/app_list/views/apps_container_view.cc
@@ -209,6 +209,12 @@
   }
 }
 
+void AppsContainerView::OnTabletModeChanged(bool started) {
+  if (suggestion_chip_container_view_)
+    suggestion_chip_container_view_->OnTabletModeChanged(started);
+  apps_grid_view_->OnTabletModeChanged(started);
+}
+
 gfx::Size AppsContainerView::CalculatePreferredSize() const {
   if (is_new_style_launcher_enabled_)
     return contents_view_->GetPreferredSize();
diff --git a/ash/app_list/views/apps_container_view.h b/ash/app_list/views/apps_container_view.h
index 6f9c836c..23f334b 100644
--- a/ash/app_list/views/apps_container_view.h
+++ b/ash/app_list/views/apps_container_view.h
@@ -69,6 +69,9 @@
   // Updates y position and opacity of the items in this view during dragging.
   void UpdateYPositionAndOpacity();
 
+  // Called when tablet mode starts and ends.
+  void OnTabletModeChanged(bool started);
+
   // views::View overrides:
   gfx::Size CalculatePreferredSize() const override;
   void Layout() override;
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index da29611..fbb3e61 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -471,6 +471,15 @@
   }
 }
 
+void AppsGridView::OnTabletModeChanged(bool started) {
+  // Enable/Disable folder icons's background blur based on tablet mode.
+  for (int i = 0; i < view_model_.view_size(); ++i) {
+    auto* item_view = view_model_.view_at(i);
+    if (item_view->item()->is_folder())
+      item_view->SetBackgroundBlurEnabled(started);
+  }
+}
+
 void AppsGridView::SetModel(AppListModel* model) {
   if (model_)
     model_->RemoveObserver(this);
@@ -2023,6 +2032,10 @@
   return view_model_.view_at(last_index);
 }
 
+bool AppsGridView::IsTabletMode() const {
+  return contents_view_->app_list_view()->is_tablet_mode();
+}
+
 void AppsGridView::StartDragAndDropHostDrag(const gfx::Point& grid_location) {
   // When a drag and drop host is given, the item can be dragged out of the app
   // list window. In that case a proxy widget needs to be used.
@@ -2047,7 +2060,8 @@
   drag_and_drop_host_->CreateDragIconProxyByLocationWithNoAnimation(
       drag_view_->GetIconBoundsInScreen().origin(), drag_view_->GetIconImage(),
       drag_view_, kDragAndDropProxyScale * GetTransform().Scale2d().x(),
-      is_new_style_launcher_enabled_ && drag_view_->item()->is_folder()
+      is_new_style_launcher_enabled_ && drag_view_->item()->is_folder() &&
+              IsTabletMode()
           ? AppListConfig::instance().blur_radius()
           : 0);
 
diff --git a/ash/app_list/views/apps_grid_view.h b/ash/app_list/views/apps_grid_view.h
index 049df8f..3e53f4c 100644
--- a/ash/app_list/views/apps_grid_view.h
+++ b/ash/app_list/views/apps_grid_view.h
@@ -119,6 +119,9 @@
   // used to trap focus within the folder when it is opened.
   void DisableFocusForShowingActiveFolder(bool disabled);
 
+  // Called when tablet mode starts and ends.
+  void OnTabletModeChanged(bool started);
+
   // Sets |model| to use. Note this does not take ownership of |model|.
   void SetModel(AppListModel* model);
 
@@ -254,6 +257,9 @@
   // Returns the last app list item view in the selected page in the folder.
   AppListItemView* GetCurrentPageLastItemViewInFolder();
 
+  // Returns true if tablet mode is active.
+  bool IsTabletMode() const;
+
   // Return the view model.
   views::ViewModelT<AppListItemView>* view_model() { return &view_model_; }
 
diff --git a/ash/app_list/views/search_result_suggestion_chip_view.cc b/ash/app_list/views/search_result_suggestion_chip_view.cc
index 84a738dc..d537846 100644
--- a/ash/app_list/views/search_result_suggestion_chip_view.cc
+++ b/ash/app_list/views/search_result_suggestion_chip_view.cc
@@ -38,7 +38,11 @@
 
 SearchResultSuggestionChipView::SearchResultSuggestionChipView(
     AppListViewDelegate* view_delegate)
-    : view_delegate_(view_delegate), weak_ptr_factory_(this) {}
+    : view_delegate_(view_delegate), weak_ptr_factory_(this) {
+  suggestion_chip_view_ = new SuggestionChipView(
+      app_list::SuggestionChipView::Params(), /* listener */ this);
+  AddChildView(suggestion_chip_view_);
+}
 
 SearchResultSuggestionChipView::~SearchResultSuggestionChipView() {
   SetSearchResult(nullptr);
@@ -55,6 +59,7 @@
   if (item_)
     item_->AddObserver(this);
 
+  SetVisible(!!item_);
   UpdateSuggestionChipView();
 }
 
@@ -105,20 +110,16 @@
 }
 
 void SearchResultSuggestionChipView::UpdateSuggestionChipView() {
-  if (!item_)
+  if (!item_) {
+    suggestion_chip_view_->SetIcon(gfx::ImageSkia());
+    suggestion_chip_view_->SetText(base::string16());
+    suggestion_chip_view_->SetAccessibleName(base::string16());
     return;
-
-  if (suggestion_chip_view_) {
-    suggestion_chip_view_->SetIcon(item_->chip_icon());
-    suggestion_chip_view_->SetText(item_->title());
-  } else {
-    app_list::SuggestionChipView::Params params;
-    params.text = item_->title();
-    params.icon = item_->chip_icon();
-    suggestion_chip_view_ = new SuggestionChipView(params, /* listener */ this);
-    AddChildView(suggestion_chip_view_);
   }
 
+  suggestion_chip_view_->SetIcon(item_->chip_icon());
+  suggestion_chip_view_->SetText(item_->title());
+
   base::string16 accessible_name = item_->title();
   if (item_->id() == app_list::kInternalAppIdContinueReading) {
     accessible_name = l10n_util::GetStringFUTF16(
diff --git a/ash/app_list/views/suggestion_chip_container_view.cc b/ash/app_list/views/suggestion_chip_container_view.cc
index c2297c2..93026a1e 100644
--- a/ash/app_list/views/suggestion_chip_container_view.cc
+++ b/ash/app_list/views/suggestion_chip_container_view.cc
@@ -42,6 +42,13 @@
           kChipSpacing));
   layout_manager->set_main_axis_alignment(
       views::BoxLayout::MainAxisAlignment::MAIN_AXIS_ALIGNMENT_CENTER);
+
+  for (size_t i = 0; i < static_cast<size_t>(kNumStartPageTiles); ++i) {
+    SearchResultSuggestionChipView* chip =
+        new SearchResultSuggestionChipView(view_delegate_);
+    chip->SetIndexInSuggestionChipContainer(i);
+    suggestion_chip_views_.emplace_back(chip);
+  }
 }
 
 SuggestionChipContainerView::~SuggestionChipContainerView() = default;
@@ -50,29 +57,20 @@
   if (IgnoreUpdateAndLayout())
     return num_results();
 
-  // Clear all current suggestion chips.
-  for (size_t i = 0; i < suggestion_chip_views_.size(); ++i)
-    delete suggestion_chip_views_[i];
-  suggestion_chip_views_.clear();
-
   std::vector<SearchResult*> display_results =
       SearchModel::FilterSearchResultsByDisplayType(
           results(), ash::SearchResultDisplayType::kRecommendation,
           /*excludes=*/{}, kNumStartPageTiles);
 
-  // Create a suggestion chip for each search result, but wait until layout to
-  // add them as child views when we know this view's bounds.
-  for (size_t i = 0; i < display_results.size(); ++i) {
-    auto* result = display_results[i];
-    SearchResultSuggestionChipView* chip =
-        new SearchResultSuggestionChipView(view_delegate_);
-    chip->SetSearchResult(result);
-    chip->SetIndexInSuggestionChipContainer(i);
-    suggestion_chip_views_.emplace_back(chip);
+  // Update search results here, but wait until layout to add them as child
+  // views when we know this view's bounds.
+  for (size_t i = 0; i < static_cast<size_t>(kNumStartPageTiles); ++i) {
+    suggestion_chip_views_[i]->SetSearchResult(
+        i < display_results.size() ? display_results[i] : nullptr);
   }
 
   Layout();
-  return suggestion_chip_views_.size();
+  return std::min(kNumStartPageTiles, static_cast<int>(display_results.size()));
 }
 
 const char* SuggestionChipContainerView::GetClassName() const {
@@ -88,11 +86,14 @@
   int total_width = 0;
   const int max_width = GetContentsBounds().width();
   for (auto* chip : suggestion_chip_views_) {
-    const int chip_width = chip->GetPreferredSize().width();
-    if (chip_width + total_width > max_width)
+    if (!chip->result())
       break;
+    const gfx::Size size = chip->CalculatePreferredSize();
+    if (size.width() + total_width > max_width)
+      break;
+    chip->SetSize(size);
     AddChildView(chip);
-    total_width += (total_width == 0 ? 0 : kChipSpacing) + chip_width;
+    total_width += (total_width == 0 ? 0 : kChipSpacing) + size.width();
   }
 
   views::View::Layout();
@@ -126,6 +127,12 @@
     chip->suggestion_chip_view()->SetEnabled(!disabled);
 }
 
+void SuggestionChipContainerView::OnTabletModeChanged(bool started) {
+  // Enable/Disable chips' background blur based on tablet mode.
+  for (auto* chip : suggestion_chip_views_)
+    chip->suggestion_chip_view()->SetBackgroundBlurEnabled(started);
+}
+
 bool SuggestionChipContainerView::IgnoreUpdateAndLayout() const {
   // Ignore update and layout when this view is not shown.
   const ash::AppListState state = contents_view_->GetActiveState();
diff --git a/ash/app_list/views/suggestion_chip_container_view.h b/ash/app_list/views/suggestion_chip_container_view.h
index 14f33a2..1ce59ce 100644
--- a/ash/app_list/views/suggestion_chip_container_view.h
+++ b/ash/app_list/views/suggestion_chip_container_view.h
@@ -34,6 +34,9 @@
   // trap focus within the folder when it is opened.
   void DisableFocusForShowingActiveFolder(bool disabled);
 
+  // Called when tablet mode starts and ends.
+  void OnTabletModeChanged(bool started);
+
  private:
   // Returns true if update and layout should be ignored.
   bool IgnoreUpdateAndLayout() const;
diff --git a/ash/app_list/views/suggestion_chip_view.cc b/ash/app_list/views/suggestion_chip_view.cc
index 08944cf1..50a9d59c 100644
--- a/ash/app_list/views/suggestion_chip_view.cc
+++ b/ash/app_list/views/suggestion_chip_view.cc
@@ -67,27 +67,37 @@
   SetFocusBehavior(FocusBehavior::ALWAYS);
   SetInkDropMode(InkDropHostView::InkDropMode::ON);
 
-  if (!assistant_style_) {
-    // Set background blur for the chip and use mask layer to clip it into
-    // rounded rect.
-    SetPaintToLayer();
-    layer()->SetFillsBoundsOpaquely(false);
-    layer()->SetBackgroundBlur(kBlurRadius);
-    SetRoundedRectMaskLayer(kPreferredHeightDip / 2);
-  }
+  // Set background blur for the chip and use mask layer to clip it into
+  // rounded rect.
+  if (!assistant_style_)
+    SetBackgroundBlurEnabled(false);
 
   InitLayout(params);
 }
 
 SuggestionChipView::~SuggestionChipView() = default;
 
-gfx::Size SuggestionChipView::CalculatePreferredSize() const {
-  const int preferred_width = views::View::CalculatePreferredSize().width();
-  return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
+void SuggestionChipView::SetBackgroundBlurEnabled(bool enabled) {
+  DCHECK(!assistant_style_);
+
+  // Background blur is enabled if and only if layer exists.
+  if (!!layer() == enabled)
+    return;
+
+  if (!enabled) {
+    DestroyLayer();
+    return;
+  }
+
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+  layer()->SetBackgroundBlur(kBlurRadius);
+  SetRoundedRectMaskLayer(kPreferredHeightDip / 2);
 }
 
-int SuggestionChipView::GetHeightForWidth(int width) const {
-  return kPreferredHeightDip;
+gfx::Size SuggestionChipView::CalculatePreferredSize() const {
+  const int preferred_width = views::View::CalculatePreferredSize().width();
+  return gfx::Size(preferred_width, kPreferredHeightDip);
 }
 
 void SuggestionChipView::ChildVisibilityChanged(views::View* child) {
@@ -223,7 +233,7 @@
 void SuggestionChipView::SetText(const base::string16& text) {
   text_view_->SetText(text);
   if (!assistant_style_) {
-    gfx::Size size = text_view_->GetPreferredSize();
+    gfx::Size size = text_view_->CalculatePreferredSize();
     size.set_width(std::min(kAppListMaxTextWidth, size.width()));
     text_view_->SetPreferredSize(size);
   }
diff --git a/ash/app_list/views/suggestion_chip_view.h b/ash/app_list/views/suggestion_chip_view.h
index 7642e349..f169685 100644
--- a/ash/app_list/views/suggestion_chip_view.h
+++ b/ash/app_list/views/suggestion_chip_view.h
@@ -42,10 +42,12 @@
   SuggestionChipView(const Params& params, views::ButtonListener* listener);
   ~SuggestionChipView() override;
 
+  // Enables background blur for folder icon if |enabled| is true.
+  void SetBackgroundBlurEnabled(bool enabled);
+
   // views::View:
   gfx::Size CalculatePreferredSize() const override;
   void ChildVisibilityChanged(views::View* child) override;
-  int GetHeightForWidth(int width) const override;
   void OnPaintBackground(gfx::Canvas* canvas) override;
   void OnFocus() override;
   void OnBlur() override;
diff --git a/ash/display/screen_orientation_controller.h b/ash/display/screen_orientation_controller.h
index a977ea0..dd166d3 100644
--- a/ash/display/screen_orientation_controller.h
+++ b/ash/display/screen_orientation_controller.h
@@ -10,6 +10,7 @@
 #include "ash/ash_export.h"
 #include "ash/display/display_configuration_controller.h"
 #include "ash/display/window_tree_host_manager.h"
+#include "ash/public/interfaces/ash_window_manager.mojom.h"
 #include "ash/wm/tablet_mode/tablet_mode_observer.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
@@ -25,17 +26,7 @@
 
 namespace ash {
 
-enum class OrientationLockType {
-  kAny = 0,
-  kNatural,
-  kCurrent,
-  kPortrait,
-  kLandscape,
-  kPortraitPrimary,
-  kPortraitSecondary,
-  kLandscapePrimary,
-  kLandscapeSecondary
-};
+using OrientationLockType = mojom::OrientationLockType;
 
 // Test if the orientation lock type is primary/landscape/portrait.
 bool IsPrimaryOrientation(OrientationLockType type);
diff --git a/ash/display/screen_orientation_controller_test_api.h b/ash/display/screen_orientation_controller_test_api.h
index 44a3216..5920bee 100644
--- a/ash/display/screen_orientation_controller_test_api.h
+++ b/ash/display/screen_orientation_controller_test_api.h
@@ -11,7 +11,10 @@
 
 namespace ash {
 class ScreenOrientationController;
+
+namespace mojom {
 enum class OrientationLockType;
+}
 
 class ScreenOrientationControllerTestApi {
  public:
@@ -26,9 +29,9 @@
 
   void SetRotationLocked(bool rotation_locked);
 
-  OrientationLockType UserLockedOrientation() const;
+  mojom::OrientationLockType UserLockedOrientation() const;
 
-  OrientationLockType GetCurrentOrientation() const;
+  mojom::OrientationLockType GetCurrentOrientation() const;
 
   void UpdateNaturalOrientation();
 
diff --git a/ash/keyboard/ash_keyboard_controller.cc b/ash/keyboard/ash_keyboard_controller.cc
index 526bd2e..a838052 100644
--- a/ash/keyboard/ash_keyboard_controller.cc
+++ b/ash/keyboard/ash_keyboard_controller.cc
@@ -63,8 +63,8 @@
   std::unique_ptr<keyboard::KeyboardUI> keyboard_ui =
       Shell::Get()->shell_delegate()->CreateKeyboardUI();
   DCHECK(keyboard_ui);
-  keyboard_controller_->EnableKeyboard(
-      std::move(keyboard_ui), Shell::Get()->virtual_keyboard_controller());
+  keyboard_controller_->EnableKeyboard(std::move(keyboard_ui),
+                                       virtual_keyboard_controller_.get());
   ActivateKeyboard();
 }
 
@@ -77,6 +77,14 @@
   keyboard_controller_->DisableKeyboard();
 }
 
+void AshKeyboardController::CreateVirtualKeyboard() {
+  virtual_keyboard_controller_ = std::make_unique<VirtualKeyboardController>();
+}
+
+void AshKeyboardController::DestroyVirtualKeyboard() {
+  virtual_keyboard_controller_.reset();
+}
+
 void AshKeyboardController::AddObserver(
     mojom::KeyboardControllerObserverAssociatedPtrInfo observer) {
   mojom::KeyboardControllerObserverAssociatedPtr observer_ptr;
diff --git a/ash/keyboard/ash_keyboard_controller.h b/ash/keyboard/ash_keyboard_controller.h
index 43b0b681..1a08083 100644
--- a/ash/keyboard/ash_keyboard_controller.h
+++ b/ash/keyboard/ash_keyboard_controller.h
@@ -26,6 +26,7 @@
 namespace ash {
 
 class SessionController;
+class VirtualKeyboardController;
 
 // Contains and observes a keyboard::KeyboardController instance. Ash specific
 // behavior, including implementing the mojo interface, is implemented in this
@@ -49,6 +50,12 @@
   // Disables the keyboard.
   void DisableKeyboard();
 
+  // Create or destroy the virtual keyboard. Called from Shell. TODO(stevenjb):
+  // Fix dependencies so that the virtual keyboard can be created with the
+  // keyboard controller.
+  void CreateVirtualKeyboard();
+  void DestroyVirtualKeyboard();
+
   // mojom::KeyboardController:
   void GetKeyboardConfig(GetKeyboardConfigCallback callback) override;
   void SetKeyboardConfig(
@@ -67,6 +74,10 @@
     return keyboard_controller_.get();
   }
 
+  VirtualKeyboardController* virtual_keyboard_controller() {
+    return virtual_keyboard_controller_.get();
+  }
+
  private:
   // Ensures that the keyboard controller is activated for the primary window.
   void ActivateKeyboard();
@@ -83,6 +94,7 @@
 
   SessionController* session_controller_;  // unowned
   std::unique_ptr<keyboard::KeyboardController> keyboard_controller_;
+  std::unique_ptr<VirtualKeyboardController> virtual_keyboard_controller_;
   mojo::BindingSet<mojom::KeyboardController> bindings_;
   mojo::AssociatedInterfacePtrSet<mojom::KeyboardControllerObserver> observers_;
 
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc
index 4b6fcb2..921d6da 100644
--- a/ash/keyboard/virtual_keyboard_controller_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -10,6 +10,7 @@
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/ime/ime_controller.h"
 #include "ash/ime/test_ime_controller_client.h"
+#include "ash/keyboard/ash_keyboard_controller.h"
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/virtual_keyboard/virtual_keyboard_observer.h"
@@ -31,7 +32,7 @@
 namespace {
 
 VirtualKeyboardController* GetVirtualKeyboardController() {
-  return Shell::Get()->virtual_keyboard_controller();
+  return Shell::Get()->ash_keyboard_controller()->virtual_keyboard_controller();
 }
 
 }  // namespace
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index dc61d4fa..df054953 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -4,6 +4,8 @@
 
 #include "ash/login/login_screen_controller.h"
 
+#include <utility>
+
 #include "ash/focus_cycler.h"
 #include "ash/login/ui/lock_screen.h"
 #include "ash/login/ui/lock_window.h"
@@ -19,6 +21,7 @@
 #include "ash/system/status_area_widget_delegate.h"
 #include "ash/system/toast/toast_data.h"
 #include "ash/system/toast/toast_manager.h"
+#include "base/bind.h"
 #include "base/debug/alias.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -149,6 +152,20 @@
                      weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
+void LoginScreenController::EnrollUserWithExternalBinary(
+    OnAuthenticateCallback callback) {
+  if (!login_screen_client_) {
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+
+  login_screen_client_->EnrollUserWithExternalBinary(base::BindOnce(
+      [](OnAuthenticateCallback callback, bool success) {
+        std::move(callback).Run(base::make_optional<bool>(success));
+      },
+      std::move(callback)));
+}
+
 void LoginScreenController::AuthenticateUserWithEasyUnlock(
     const AccountId& account_id) {
   // TODO(jdufault): integrate this into authenticate stage after mojom is
@@ -537,7 +554,7 @@
     OnAuthenticateCallback callback,
     bool success) {
   authentication_stage_ = AuthenticationStage::kUserCallback;
-  std::move(callback).Run(success);
+  std::move(callback).Run(base::make_optional<bool>(success));
   authentication_stage_ = AuthenticationStage::kIdle;
 }
 
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index 62c7ee41..850cdaa 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -63,6 +63,7 @@
                                          OnAuthenticateCallback callback);
   void AuthenticateUserWithExternalBinary(const AccountId& account_id,
                                           OnAuthenticateCallback callback);
+  void EnrollUserWithExternalBinary(OnAuthenticateCallback callback);
   void AuthenticateUserWithEasyUnlock(const AccountId& account_id);
   void HardlockPod(const AccountId& account_id);
   void RecordClickOnLockIcon(const AccountId& account_id);
diff --git a/ash/login/mock_login_screen_client.cc b/ash/login/mock_login_screen_client.cc
index e058668..7751be5 100644
--- a/ash/login/mock_login_screen_client.cc
+++ b/ash/login/mock_login_screen_client.cc
@@ -5,6 +5,7 @@
 #include "ash/login/mock_login_screen_client.h"
 
 #include <memory>
+#include <utility>
 
 #include "ash/login/login_screen_controller.h"
 #include "ash/shell.h"
@@ -48,6 +49,16 @@
   }
 }
 
+void MockLoginScreenClient::EnrollUserWithExternalBinary(
+    EnrollUserWithExternalBinaryCallback callback) {
+  EnrollUserWithExternalBinary_(callback);
+  if (enroll_user_with_external_binary_callback_storage_) {
+    *enroll_user_with_external_binary_callback_storage_ = std::move(callback);
+  } else {
+    std::move(callback).Run(authenticate_user_callback_result_);
+  }
+}
+
 std::unique_ptr<MockLoginScreenClient> BindMockLoginScreenClient() {
   auto client = std::make_unique<MockLoginScreenClient>();
   Shell::Get()->login_screen_controller()->SetClient(
diff --git a/ash/login/mock_login_screen_client.h b/ash/login/mock_login_screen_client.h
index 71176e6..00cfd90 100644
--- a/ash/login/mock_login_screen_client.h
+++ b/ash/login/mock_login_screen_client.h
@@ -28,6 +28,8 @@
   MOCK_METHOD2(AuthenticateUserWithExternalBinary_,
                void(const AccountId& account_id,
                     AuthenticateUserWithExternalBinaryCallback& callback));
+  MOCK_METHOD1(EnrollUserWithExternalBinary_,
+               void(EnrollUserWithExternalBinaryCallback& callback));
 
   // Set the result that should be passed to |callback| in
   // |AuthenticateUserWithPasswordOrPin| or
@@ -46,6 +48,10 @@
       AuthenticateUserWithPasswordOrPinCallback* storage) {
     authenticate_user_with_external_binary_callback_storage_ = storage;
   }
+  void set_enroll_user_with_external_binary_storage(
+      EnrollUserWithExternalBinaryCallback* storage) {
+    enroll_user_with_external_binary_callback_storage_ = storage;
+  }
 
   // mojom::LoginScreenClient:
   void AuthenticateUserWithPasswordOrPin(
@@ -56,6 +62,8 @@
   void AuthenticateUserWithExternalBinary(
       const AccountId& account_id,
       AuthenticateUserWithExternalBinaryCallback callback) override;
+  void EnrollUserWithExternalBinary(
+      EnrollUserWithExternalBinaryCallback callback) override;
   MOCK_METHOD1(AuthenticateUserWithEasyUnlock,
                void(const AccountId& account_id));
   MOCK_METHOD1(HardlockPod, void(const AccountId& account_id));
@@ -93,6 +101,8 @@
       authenticate_user_with_password_or_pin_callback_storage_ = nullptr;
   AuthenticateUserWithExternalBinaryCallback*
       authenticate_user_with_external_binary_callback_storage_ = nullptr;
+  EnrollUserWithExternalBinaryCallback*
+      enroll_user_with_external_binary_callback_storage_ = nullptr;
 
   mojo::Binding<mojom::LoginScreenClient> binding_;
 
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 2ed146d..2776704 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -23,7 +23,9 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/night_light/time_of_day.h"
+#include "ash/system/toast/toast_manager.h"
 #include "ash/wallpaper/wallpaper_controller.h"
+#include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/user_manager/user.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -456,6 +458,8 @@
   // TODO(jdufault): Implement real UI.
   external_binary_auth_button_ = views::MdTextButton::Create(
       this, base::ASCIIToUTF16("Authenticate with external binary"));
+  external_binary_enrollment_button_ = views::MdTextButton::Create(
+      this, base::ASCIIToUTF16("Enroll with external binary"));
 
   SetPaintToLayer(ui::LayerType::LAYER_NOT_DRAWN);
 
@@ -479,6 +483,9 @@
       login_views_utils::WrapViewForPreferredSize(fingerprint_view_);
   auto* wrapped_external_binary_view =
       login_views_utils::WrapViewForPreferredSize(external_binary_auth_button_);
+  auto* wrapped_external_binary_enrollment_view =
+      login_views_utils::WrapViewForPreferredSize(
+          external_binary_enrollment_button_);
   auto* wrapped_padding_below_password_view =
       login_views_utils::WrapViewForPreferredSize(padding_below_password_view_);
 
@@ -489,6 +496,7 @@
   AddChildView(wrapped_pin_view);
   AddChildView(wrapped_fingerprint_view);
   AddChildView(wrapped_external_binary_view);
+  AddChildView(wrapped_external_binary_enrollment_view);
   AddChildView(wrapped_user_view);
   AddChildView(wrapped_padding_below_password_view);
 
@@ -519,6 +527,7 @@
   add_view(wrapped_pin_view);
   add_view(wrapped_fingerprint_view);
   add_view(wrapped_external_binary_view);
+  add_view(wrapped_external_binary_enrollment_view);
   add_padding(kDistanceFromPinKeyboardToBigUserViewBottomDp);
 
   // Update authentication UI.
@@ -565,6 +574,7 @@
   pin_view_->SetVisible(has_pin);
   fingerprint_view_->SetVisible(has_fingerprint);
   external_binary_auth_button_->SetVisible(has_external_binary);
+  external_binary_enrollment_button_->SetVisible(has_external_binary);
 
   int padding_view_height = kDistanceBetweenPasswordFieldAndPinKeyboardDp;
   if (has_fingerprint && !has_pin) {
@@ -778,10 +788,18 @@
   } else if (sender == external_binary_auth_button_) {
     password_view_->SetReadOnly(true);
     external_binary_auth_button_->SetEnabled(false);
+    external_binary_enrollment_button_->SetEnabled(false);
     Shell::Get()->login_screen_controller()->AuthenticateUserWithExternalBinary(
         current_user()->basic_user_info->account_id,
         base::BindOnce(&LoginAuthUserView::OnAuthComplete,
                        weak_factory_.GetWeakPtr()));
+  } else if (sender == external_binary_enrollment_button_) {
+    password_view_->SetReadOnly(true);
+    external_binary_auth_button_->SetEnabled(false);
+    external_binary_enrollment_button_->SetEnabled(false);
+    Shell::Get()->login_screen_controller()->EnrollUserWithExternalBinary(
+        base::BindOnce(&LoginAuthUserView::OnEnrollmentComplete,
+                       weak_factory_.GetWeakPtr()));
   }
 }
 
@@ -803,22 +821,39 @@
 }
 
 void LoginAuthUserView::OnAuthComplete(base::Optional<bool> auth_success) {
-  if (!auth_success.has_value())
-    return;
-
   // Clear the password only if auth fails. Make sure to keep the password view
   // disabled even if auth succeededs, as if the user submits a password while
   // animating the next lock screen will not work as expected. See
   // https://crbug.com/808486.
-  if (!auth_success.value()) {
+  if (!auth_success.has_value() || !auth_success.value()) {
     password_view_->Clear();
     password_view_->SetReadOnly(false);
     external_binary_auth_button_->SetEnabled(true);
+    external_binary_enrollment_button_->SetEnabled(true);
   }
 
   on_auth_.Run(auth_success.value());
 }
 
+void LoginAuthUserView::OnEnrollmentComplete(
+    base::Optional<bool> enrollment_success) {
+  password_view_->SetReadOnly(false);
+  external_binary_auth_button_->SetEnabled(true);
+  external_binary_enrollment_button_->SetEnabled(true);
+
+  std::string result_message;
+  if (!enrollment_success.has_value()) {
+    result_message = "Enrollment attempt failed to received response.";
+  } else {
+    result_message = enrollment_success.value() ? "Enrollment successful."
+                                                : "Enrollment failed.";
+  }
+
+  ToastData toast_data("EnrollmentToast", base::ASCIIToUTF16(result_message),
+                       2000, base::nullopt, true /*visible_on_lock_screen*/);
+  Shell::Get()->toast_manager()->Show(toast_data);
+}
+
 void LoginAuthUserView::OnUserViewTap() {
   if (HasAuthMethod(AUTH_TAP)) {
     Shell::Get()->login_screen_controller()->AuthenticateUserWithEasyUnlock(
diff --git a/ash/login/ui/login_auth_user_view.h b/ash/login/ui/login_auth_user_view.h
index 28246fc..18e87736 100644
--- a/ash/login/ui/login_auth_user_view.h
+++ b/ash/login/ui/login_auth_user_view.h
@@ -14,6 +14,7 @@
 #include "ash/login/ui/non_accessible_view.h"
 #include "ash/public/interfaces/user_info.mojom.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/scoped_observer.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/view.h"
@@ -141,6 +142,8 @@
   void OnAuthSubmit(const base::string16& password);
   // Called with the result of the request started in |OnAuthSubmit|.
   void OnAuthComplete(base::Optional<bool> auth_success);
+  // Called with the result of the external binary enrollment request.
+  void OnEnrollmentComplete(base::Optional<bool> enrollment_success);
 
   // Called when the user view has been tapped. This will run |on_auth_| if tap
   // to unlock is enabled, or run |OnOnlineSignInMessageTap| if the online
@@ -166,6 +169,7 @@
   DisabledAuthMessageView* disabled_auth_message_ = nullptr;
   FingerprintView* fingerprint_view_ = nullptr;
   views::LabelButton* external_binary_auth_button_ = nullptr;
+  views::LabelButton* external_binary_enrollment_button_ = nullptr;
 
   // Displays padding between:
   // 1. Password field and pin keyboard
diff --git a/ash/media_controller.cc b/ash/media_controller.cc
index d848977..7f0d5835 100644
--- a/ash/media_controller.cc
+++ b/ash/media_controller.cc
@@ -4,9 +4,15 @@
 
 #include "ash/media_controller.h"
 
+#include "ash/public/cpp/ash_features.h"
+#include "base/feature_list.h"
+#include "services/media_session/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
 namespace ash {
 
-MediaController::MediaController() = default;
+MediaController::MediaController(service_manager::Connector* connector)
+    : connector_(connector) {}
 
 MediaController::~MediaController() = default;
 
@@ -32,17 +38,29 @@
     observer.OnMediaCaptureChanged(capture_states);
 }
 
-void MediaController::HandleMediaNextTrack() {
-  if (client_)
-    client_->HandleMediaNextTrack();
-}
-
 void MediaController::HandleMediaPlayPause() {
+  // If media session media key handling is enabled. Toggle play pause using the
+  // media session service.
+  if (base::FeatureList::IsEnabled(features::kMediaSessionAccelerators)) {
+    if (GetMediaSessionController())
+      GetMediaSessionController()->ToggleSuspendResume();
+    return;
+  }
+
   if (client_)
     client_->HandleMediaPlayPause();
 }
 
+void MediaController::HandleMediaNextTrack() {
+  // TODO(beccahughes): Add media session service integration.
+
+  if (client_)
+    client_->HandleMediaNextTrack();
+}
+
 void MediaController::HandleMediaPrevTrack() {
+  // TODO(beccahughes): Add media session service integration.
+
   if (client_)
     client_->HandleMediaPrevTrack();
 }
@@ -57,4 +75,33 @@
     client_->SuspendMediaSessions();
 }
 
+void MediaController::SetMediaSessionControllerForTest(
+    media_session::mojom::MediaControllerPtr controller) {
+  media_session_controller_ptr_ = std::move(controller);
+}
+
+void MediaController::FlushForTesting() {
+  client_.FlushForTesting();
+  media_session_controller_ptr_.FlushForTesting();
+}
+
+media_session::mojom::MediaController*
+MediaController::GetMediaSessionController() {
+  // |connector_| can be null in tests.
+  if (connector_ && !media_session_controller_ptr_.is_bound()) {
+    connector_->BindInterface(media_session::mojom::kServiceName,
+                              &media_session_controller_ptr_);
+
+    media_session_controller_ptr_.set_connection_error_handler(
+        base::BindRepeating(&MediaController::OnMediaSessionControllerError,
+                            base::Unretained(this)));
+  }
+
+  return media_session_controller_ptr_.get();
+}
+
+void MediaController::OnMediaSessionControllerError() {
+  media_session_controller_ptr_.reset();
+}
+
 }  // namespace ash
diff --git a/ash/media_controller.h b/ash/media_controller.h
index 59a51ae..5c826203 100644
--- a/ash/media_controller.h
+++ b/ash/media_controller.h
@@ -5,12 +5,18 @@
 #ifndef ASH_MEDIA_CONTROLLER_H_
 #define ASH_MEDIA_CONTROLLER_H_
 
+#include "ash/ash_export.h"
 #include "ash/public/interfaces/media.mojom.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "components/account_id/interfaces/account_id.mojom.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/media_session/public/mojom/media_controller.mojom.h"
+
+namespace service_manager {
+class Connector;
+}  // namespace service_manager
 
 namespace ash {
 
@@ -29,9 +35,10 @@
 // Provides the MediaController interface to the outside world. This lets a
 // consumer of ash provide a MediaClient, which we will dispatch to if one has
 // been provided to us.
-class MediaController : public mojom::MediaController {
+class ASH_EXPORT MediaController : public mojom::MediaController {
  public:
-  MediaController();
+  // |connector| can be null in tests.
+  explicit MediaController(service_manager::Connector* connector);
   ~MediaController() override;
 
   void BindRequest(mojom::MediaControllerRequest request);
@@ -45,15 +52,41 @@
       const base::flat_map<AccountId, mojom::MediaCaptureState>& capture_states)
       override;
 
+  // If media session accelerators are enabled then this method will use the
+  // media session service to control playback. Otherwise it will forward to
+  // |client_|.
+  void HandleMediaPlayPause();
+
   // Methods that forward to |client_|.
   void HandleMediaNextTrack();
-  void HandleMediaPlayPause();
   void HandleMediaPrevTrack();
   void RequestCaptureState();
   void SuspendMediaSessions();
 
  private:
+  friend class MediaSessionAcceleratorTest;
   friend class MultiProfileMediaTrayItemTest;
+  FRIEND_TEST_ALL_PREFIXES(MediaSessionAcceleratorTest,
+                           MediaGlobalAccelerators_NextTrack);
+  FRIEND_TEST_ALL_PREFIXES(MediaSessionAcceleratorTest,
+                           MediaGlobalAccelerators_PlayPause);
+  FRIEND_TEST_ALL_PREFIXES(MediaSessionAcceleratorTest,
+                           MediaGlobalAccelerators_PrevTrack);
+
+  void SetMediaSessionControllerForTest(
+      media_session::mojom::MediaControllerPtr controller);
+
+  void FlushForTesting();
+
+  // Returns a pointer to the active media session controller.
+  media_session::mojom::MediaController* GetMediaSessionController();
+
+  void OnMediaSessionControllerError();
+
+  // Mojo pointer to the active media session controller.
+  media_session::mojom::MediaControllerPtr media_session_controller_ptr_;
+
+  service_manager::Connector* const connector_;
 
   // Bindings for users of the mojo interface.
   mojo::BindingSet<mojom::MediaController> bindings_;
diff --git a/ash/public/interfaces/ash_window_manager.mojom b/ash/public/interfaces/ash_window_manager.mojom
index aa881324..a6daf77 100644
--- a/ash/public/interfaces/ash_window_manager.mojom
+++ b/ash/public/interfaces/ash_window_manager.mojom
@@ -14,6 +14,18 @@
   kRight,  // The phantom window controller is previewing a snap to the left.
 };
 
+enum OrientationLockType {
+  kAny,
+  kNatural,
+  kCurrent,
+  kPortrait,
+  kLandscape,
+  kPortraitPrimary,
+  kPortraitSecondary,
+  kLandscapePrimary,
+  kLandscapeSecondary,
+};
+
 // Interface exposed via WindowTree::BindWindowManagerInterface(). This
 // interface is used for functionality specific to Ash that is associated with
 // windows created by the window service.
@@ -24,6 +36,12 @@
 
   CommitSnap(uint64 window_id, SnapDirection snap);
 
+  // Locks or unlocks the screen orientation. The provided window is the source
+  // of the orientation request and need not be a top level window, but the
+  // client connection type must not be an embedding (i.e. renderer).
+  LockOrientation(uint64 window_id, OrientationLockType type);
+  UnlockOrientation(uint64 window_id);
+
   // Maximizes the window in response to a double click or tap on the HTCAPTION
   // area.
   MaximizeWindowByCaptionClick(uint64 window_id, ui.mojom.PointerKind pointer);
diff --git a/ash/public/interfaces/login_screen.mojom b/ash/public/interfaces/login_screen.mojom
index 8337afdf..84180bc8 100644
--- a/ash/public/interfaces/login_screen.mojom
+++ b/ash/public/interfaces/login_screen.mojom
@@ -229,6 +229,9 @@
   AuthenticateUserWithExternalBinary(signin.mojom.AccountId account_id)
       => (bool auth_success);
 
+  // Attempt to enroll a user in the external binary authentication system.
+  EnrollUserWithExternalBinary() => (bool enrollment_success);
+
   // Try to authenticate |account_id| using easy unlock. This can be used on the
   // login or lock screen.
   // |account_id|: The account id of the user we are authenticating.
diff --git a/ash/shell.cc b/ash/shell.cc
index c267cbd8..10cbf073 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -56,7 +56,6 @@
 #include "ash/ime/ime_controller.h"
 #include "ash/ime/ime_focus_handler.h"
 #include "ash/keyboard/ash_keyboard_controller.h"
-#include "ash/keyboard/virtual_keyboard_controller.h"
 #include "ash/laser/laser_pointer_controller.h"
 #include "ash/login/login_screen_controller.h"
 #include "ash/login_status.h"
@@ -671,7 +670,7 @@
       locale_notification_controller_(
           std::make_unique<LocaleNotificationController>()),
       login_screen_controller_(std::make_unique<LoginScreenController>()),
-      media_controller_(std::make_unique<MediaController>()),
+      media_controller_(std::make_unique<MediaController>(connector)),
       new_window_controller_(std::make_unique<NewWindowController>()),
       session_controller_(std::make_unique<SessionController>(connector)),
       note_taking_controller_(std::make_unique<NoteTakingController>()),
@@ -755,7 +754,7 @@
   // Destroy the virtual keyboard controller before the tablet mode controller
   // since the latters destructor triggers events that the former is listening
   // to but no longer cares about.
-  virtual_keyboard_controller_.reset();
+  ash_keyboard_controller_->DestroyVirtualKeyboard();
 
   // Depends on |tablet_mode_controller_|.
   shelf_controller_->Shutdown();
@@ -1227,9 +1226,7 @@
                               ? std::make_unique<AssistantController>()
                               : nullptr;
 
-  // Needs to be created after InitDisplays() since it may cause the virtual
-  // keyboard to be deployed.
-  virtual_keyboard_controller_ = std::make_unique<VirtualKeyboardController>();
+  ash_keyboard_controller_->CreateVirtualKeyboard();
 
   cursor_manager_->HideCursor();  // Hide the mouse cursor on startup.
   cursor_manager_->SetCursor(ui::CursorType::kPointer);
diff --git a/ash/shell.h b/ash/shell.h
index 14b046a..d45ff2f 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -187,7 +187,6 @@
 class TouchDevicesController;
 class TrayAction;
 class TrayBluetoothHelper;
-class VirtualKeyboardController;
 class VideoActivityNotifier;
 class VideoDetector;
 class VoiceInteractionController;
@@ -531,9 +530,6 @@
   }
   UserMetricsRecorder* metrics() { return user_metrics_recorder_.get(); }
   VideoDetector* video_detector() { return video_detector_.get(); }
-  VirtualKeyboardController* virtual_keyboard_controller() {
-    return virtual_keyboard_controller_.get();
-  }
   VoiceInteractionController* voice_interaction_controller() {
     return voice_interaction_controller_.get();
   }
@@ -830,7 +826,6 @@
   std::unique_ptr<BluetoothPowerController> bluetooth_power_controller_;
   std::unique_ptr<TrayBluetoothHelper> tray_bluetooth_helper_;
   std::unique_ptr<AshKeyboardController> ash_keyboard_controller_;
-  std::unique_ptr<VirtualKeyboardController> virtual_keyboard_controller_;
   // Controls video output device state.
   std::unique_ptr<display::DisplayConfigurator> display_configurator_;
   std::unique_ptr<DisplayOutputProtection> display_output_protection_;
diff --git a/ash/system/flag_warning/flag_warning_tray.cc b/ash/system/flag_warning/flag_warning_tray.cc
index db7a83bb..9aa38e09 100644
--- a/ash/system/flag_warning/flag_warning_tray.cc
+++ b/ash/system/flag_warning/flag_warning_tray.cc
@@ -83,7 +83,7 @@
   }
 
   if (::features::IsSingleProcessMash()) {
-    button_->SetText(base::ASCIIToUTF16("a"));
+    button_->SetText(base::ASCIIToUTF16("SPM"));
     button_->SetTooltipText(
         base::ASCIIToUTF16("Running with feature SingleProcessMash"));
   } else if (::features::IsMultiProcessMash()) {
diff --git a/ash/system/ime_menu/ime_list_view.cc b/ash/system/ime_menu/ime_list_view.cc
index f52166d..2ffc8ee 100644
--- a/ash/system/ime_menu/ime_list_view.cc
+++ b/ash/system/ime_menu/ime_list_view.cc
@@ -6,6 +6,7 @@
 
 #include "ash/ime/ime_controller.h"
 #include "ash/ime/ime_switch_type.h"
+#include "ash/keyboard/ash_keyboard_controller.h"
 #include "ash/keyboard/virtual_keyboard_controller.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/interfaces/ime_info.mojom.h"
@@ -330,7 +331,10 @@
                                       const ui::Event& event) {
   DCHECK_EQ(sender, keyboard_status_row_->toggle());
 
-  Shell::Get()->virtual_keyboard_controller()->ToggleIgnoreExternalKeyboard();
+  Shell::Get()
+      ->ash_keyboard_controller()
+      ->virtual_keyboard_controller()
+      ->ToggleIgnoreExternalKeyboard();
   last_selected_item_id_.clear();
   last_item_selected_with_keyboard_ = false;
 }
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc
index cf57cdf8..b929150 100644
--- a/ash/system/ime_menu/ime_menu_tray.cc
+++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -6,6 +6,7 @@
 
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/ime/ime_controller.h"
+#include "ash/keyboard/ash_keyboard_controller.h"
 #include "ash/keyboard/virtual_keyboard_controller.h"
 #include "ash/public/cpp/ash_constants.h"
 #include "ash/resources/vector_icons/vector_icons.h"
@@ -397,8 +398,10 @@
     chromeos::input_method::mojom::ImeKeyset keyset) {
   CloseBubble();
 
-  Shell::Get()->virtual_keyboard_controller()->ForceShowKeyboardWithKeyset(
-      keyset);
+  Shell::Get()
+      ->ash_keyboard_controller()
+      ->virtual_keyboard_controller()
+      ->ForceShowKeyboardWithKeyset(keyset);
 }
 
 bool ImeMenuTray::ShouldShowBottomButtons() {
diff --git a/ash/wm/splitview/split_view_divider.h b/ash/wm/splitview/split_view_divider.h
index 25a8f3e..04fce3e 100644
--- a/ash/wm/splitview/split_view_divider.h
+++ b/ash/wm/splitview/split_view_divider.h
@@ -29,8 +29,11 @@
 
 namespace ash {
 
-class SplitViewController;
+namespace mojom {
 enum class OrientationLockType;
+}
+
+class SplitViewController;
 
 // Split view divider. It passes the mouse/gesture events to SplitViewController
 // to resize the left and right windows accordingly. The divider widget should
@@ -45,13 +48,13 @@
   // Gets the size of the divider widget. The divider widget is enlarged during
   // dragging. For now, it's a vertical rectangle.
   static gfx::Size GetDividerSize(const gfx::Rect& work_area_bounds,
-                                  OrientationLockType screen_orientation,
+                                  mojom::OrientationLockType screen_orientation,
                                   bool is_dragging);
 
   // static version of GetDividerBoundsInScreen(bool is_dragging) function.
   static gfx::Rect GetDividerBoundsInScreen(
       const gfx::Rect& work_area_bounds_in_screen,
-      OrientationLockType screen_orientation,
+      mojom::OrientationLockType screen_orientation,
       int divider_position,
       bool is_dragging);
 
diff --git a/ash/ws/ash_window_manager.cc b/ash/ws/ash_window_manager.cc
index 64a6dc33..895f912 100644
--- a/ash/ws/ash_window_manager.cc
+++ b/ash/ws/ash_window_manager.cc
@@ -4,6 +4,7 @@
 
 #include "ash/ws/ash_window_manager.h"
 
+#include "ash/display/screen_orientation_controller.h"
 #include "ash/shell.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
@@ -53,6 +54,40 @@
   }
 }
 
+void AshWindowManager::LockOrientation(
+    ws::Id window_id,
+    mojom::OrientationLockType lock_orientation) {
+  if (window_tree_->connection_type() ==
+      ws::WindowTree::ConnectionType::kEmbedding) {
+    DVLOG(1) << "LockOrientation not allowed from embed connection";
+    return;
+  }
+
+  aura::Window* window = window_tree_->GetWindowByTransportId(window_id);
+  if (window) {
+    Shell::Get()->screen_orientation_controller()->LockOrientationForWindow(
+        window, lock_orientation);
+  } else {
+    DVLOG(1) << "LockOrientation passed invalid window, id=" << window_id;
+  }
+}
+
+void AshWindowManager::UnlockOrientation(ws::Id window_id) {
+  if (window_tree_->connection_type() ==
+      ws::WindowTree::ConnectionType::kEmbedding) {
+    DVLOG(1) << "UnlockOrientation not allowed from embed connection";
+    return;
+  }
+
+  aura::Window* window = window_tree_->GetWindowByTransportId(window_id);
+  if (window) {
+    Shell::Get()->screen_orientation_controller()->UnlockOrientationForWindow(
+        window);
+  } else {
+    DVLOG(1) << "UnlockOrientation passed invalid window, id=" << window_id;
+  }
+}
+
 void AshWindowManager::MaximizeWindowByCaptionClick(
     ws::Id window_id,
     ui::mojom::PointerKind pointer) {
diff --git a/ash/ws/ash_window_manager.h b/ash/ws/ash_window_manager.h
index 47ab866c..2dc14cc 100644
--- a/ash/ws/ash_window_manager.h
+++ b/ash/ws/ash_window_manager.h
@@ -33,6 +33,9 @@
   void AddWindowToTabletMode(ws::Id window_id) override;
   void ShowSnapPreview(ws::Id window_id, mojom::SnapDirection snap) override;
   void CommitSnap(ws::Id window_id, mojom::SnapDirection snap) override;
+  void LockOrientation(ws::Id window_id,
+                       mojom::OrientationLockType lock_orientation) override;
+  void UnlockOrientation(ws::Id window_id) override;
   void MaximizeWindowByCaptionClick(ws::Id window_id,
                                     ui::mojom::PointerKind pointer) override;
   void BounceWindow(ws::Id window_id) override;
diff --git a/base/task/task_scheduler/task_tracker.cc b/base/task/task_scheduler/task_tracker.cc
index dd328eb..9bc5b717 100644
--- a/base/task/task_scheduler/task_tracker.cc
+++ b/base/task/task_scheduler/task_tracker.cc
@@ -133,17 +133,11 @@
                         : 0];
 }
 
-// Upper bound for the
-// TaskScheduler.BlockShutdownTasksPostedDuringShutdown histogram.
-constexpr HistogramBase::Sample kMaxBlockShutdownTasksPostedDuringShutdown =
-    1000;
-
-void RecordNumBlockShutdownTasksPostedDuringShutdown(
-    HistogramBase::Sample value) {
-  UMA_HISTOGRAM_CUSTOM_COUNTS(
-      "TaskScheduler.BlockShutdownTasksPostedDuringShutdown", value, 1,
-      kMaxBlockShutdownTasksPostedDuringShutdown, 50);
-}
+// Maximum number of BLOCK_SHUTDOWN tasks that can be posted during shutdown. If
+// that many BLOCK_SHUTDOWN tasks are posted during shutdown, it is possible
+// that buggy code is posting an infinite number of tasks and that shutdown will
+// never complete. The mitigation is to induce a crash.
+constexpr int kMaxBlockShutdownTasksPostedDuringShutdown = 1000;
 
 // Returns the maximum number of TaskPriority::BEST_EFFORT sequences that can be
 // scheduled concurrently based on command line flags.
@@ -707,20 +701,6 @@
     base::ThreadRestrictions::ScopedAllowWait allow_wait;
     shutdown_event_->Wait();
   }
-
-  {
-    AutoSchedulerLock auto_lock(shutdown_lock_);
-
-    // Record TaskScheduler.BlockShutdownTasksPostedDuringShutdown if less than
-    // |kMaxBlockShutdownTasksPostedDuringShutdown| BLOCK_SHUTDOWN tasks were
-    // posted during shutdown. Otherwise, the histogram has already been
-    // recorded in BeforePostTask().
-    if (num_block_shutdown_tasks_posted_during_shutdown_ <
-        kMaxBlockShutdownTasksPostedDuringShutdown) {
-      RecordNumBlockShutdownTasksPostedDuringShutdown(
-          num_block_shutdown_tasks_posted_during_shutdown_);
-    }
-  }
 }
 
 void TaskTracker::SetMaxNumScheduledSequences(int max_scheduled_sequences,
@@ -819,16 +799,8 @@
       }
 
       ++num_block_shutdown_tasks_posted_during_shutdown_;
-
-      if (num_block_shutdown_tasks_posted_during_shutdown_ ==
-          kMaxBlockShutdownTasksPostedDuringShutdown) {
-        // Record the TaskScheduler.BlockShutdownTasksPostedDuringShutdown
-        // histogram as soon as its upper bound is hit. That way, a value will
-        // be recorded even if an infinite number of BLOCK_SHUTDOWN tasks are
-        // posted, preventing shutdown to complete.
-        RecordNumBlockShutdownTasksPostedDuringShutdown(
-            num_block_shutdown_tasks_posted_during_shutdown_);
-      }
+      CHECK_LT(num_block_shutdown_tasks_posted_during_shutdown_,
+               kMaxBlockShutdownTasksPostedDuringShutdown);
     }
 
     return true;
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc
index dd5acbca..9328aaba 100644
--- a/base/test/test_timeouts.cc
+++ b/base/test/test_timeouts.cc
@@ -38,11 +38,21 @@
   // down significantly.
   // For MSan the slowdown depends heavily on the value of msan_track_origins
   // build flag. The multiplier below corresponds to msan_track_origins = 1.
+#if defined(OS_CHROMEOS)
+  // A handful of tests on ChromeOS run *very* close to the 6x limit used
+  // else where, so it's bumped to 7x.
+  constexpr int kTimeoutMultiplier = 7;
+#else
   constexpr int kTimeoutMultiplier = 6;
+#endif
 #elif defined(ADDRESS_SANITIZER) && defined(OS_WIN)
   // ASan/Win has not been optimized yet, give it a higher
   // timeout multiplier. See http://crbug.com/412471
   constexpr int kTimeoutMultiplier = 3;
+#elif defined(ADDRESS_SANITIZER) && defined(OS_CHROMEOS)
+  // A number of tests on ChromeOS run very close to the 2x limit, so ChromeOS
+  // gets 3x.
+  constexpr int kTimeoutMultiplier = 3;
 #elif defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
   constexpr int kTimeoutMultiplier = 2;
 #else
diff --git a/build/PRESUBMIT.py b/build/PRESUBMIT.py
deleted file mode 100644
index b886326..0000000
--- a/build/PRESUBMIT.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (c) 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Presubmit script for //build.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra tests.
-  """
-
-  def affects_gn_checker(f):
-    return 'check_gn_headers' in f.LocalPath()
-  if not change.AffectedFiles(file_filter=affects_gn_checker):
-    return []
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_chromium_dbg_ng',
-    ],
-    'Automatically added tests to run on CQ.')
diff --git a/cc/PRESUBMIT.py b/cc/PRESUBMIT.py
index 3e27d70..89f5675 100644
--- a/cc/PRESUBMIT.py
+++ b/cc/PRESUBMIT.py
@@ -287,17 +287,3 @@
   results += CheckForUseOfWrongClock(input_api, output_api)
   results += FindUselessIfdefs(input_api, output_api)
   return results
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook adds an extra try bot list to the CL description in order to run
-  Blink tests and additional GPU tests in addition to the CQ try bots.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'master.tryserver.blink:linux_trusty_blink_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added Blink and Android GPU trybots for CQ.')
diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc
index 9c516e3..639d875 100644
--- a/cc/raster/gpu_raster_buffer_provider.cc
+++ b/cc/raster/gpu_raster_buffer_provider.cc
@@ -456,6 +456,43 @@
     const gfx::AxisTransform2d& transform,
     const RasterSource::PlaybackSettings& playback_settings,
     const GURL& url) {
+  PendingRasterQuery query;
+  gpu::SyncToken raster_finished_token = PlaybackOnWorkerThreadInternal(
+      mailbox, texture_target, texture_is_overlay_candidate, sync_token,
+      resource_size, resource_format, color_space,
+      resource_has_previous_content, raster_source, raster_full_rect,
+      raster_dirty_rect, new_content_id, transform, playback_settings, url,
+      &query);
+
+  {
+    // Note that it is important to scope the raster context lock to
+    // PlaybackOnWorkerThreadInternal and release it before acquiring this lock
+    // to avoid a deadlock in CheckRasterFinishedQueries which acquires the
+    // raster context lock while holding this lock.
+    base::AutoLock hold(pending_raster_queries_lock_);
+    pending_raster_queries_.push_back(query);
+  }
+
+  return raster_finished_token;
+}
+
+gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal(
+    gpu::Mailbox* mailbox,
+    GLenum texture_target,
+    bool texture_is_overlay_candidate,
+    const gpu::SyncToken& sync_token,
+    const gfx::Size& resource_size,
+    viz::ResourceFormat resource_format,
+    const gfx::ColorSpace& color_space,
+    bool resource_has_previous_content,
+    const RasterSource* raster_source,
+    const gfx::Rect& raster_full_rect,
+    const gfx::Rect& raster_dirty_rect,
+    uint64_t new_content_id,
+    const gfx::AxisTransform2d& transform,
+    const RasterSource::PlaybackSettings& playback_settings,
+    const GURL& url,
+    PendingRasterQuery* query) {
   viz::RasterContextProvider::ScopedRasterContextLock scoped_context(
       worker_context_provider_, url.possibly_invalid_spec().c_str());
   gpu::raster::RasterInterface* ri = scoped_context.RasterInterface();
@@ -483,10 +520,8 @@
   }
 
   // Use a query to time the GPU side work for rasterizing this tile.
-  pending_raster_queries_.emplace_back();
-  auto& query = pending_raster_queries_.back();
-  ri->GenQueriesEXT(1, &query.query_id);
-  ri->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query.query_id);
+  ri->GenQueriesEXT(1, &query->query_id);
+  ri->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query->query_id);
 
   {
     base::ElapsedTimer timer;
@@ -507,7 +542,7 @@
                       ShouldUnpremultiplyAndDitherResource(resource_format),
                       max_tile_size_);
     }
-    query.worker_duration = timer.Elapsed();
+    query->worker_duration = timer.Elapsed();
   }
 
   ri->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
@@ -532,6 +567,10 @@
       base::TimeDelta::FromMilliseconds(100), 100);
 
 bool GpuRasterBufferProvider::CheckRasterFinishedQueries() {
+  base::AutoLock hold(pending_raster_queries_lock_);
+  if (pending_raster_queries_.empty())
+    return false;
+
   viz::RasterContextProvider::ScopedRasterContextLock scoped_context(
       worker_context_provider_);
   auto* ri = scoped_context.RasterInterface();
diff --git a/cc/raster/gpu_raster_buffer_provider.h b/cc/raster/gpu_raster_buffer_provider.h
index 2012687..be27975 100644
--- a/cc/raster/gpu_raster_buffer_provider.h
+++ b/cc/raster/gpu_raster_buffer_provider.h
@@ -114,7 +114,32 @@
     DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
   };
 
+  struct PendingRasterQuery {
+    // The id for querying the duration in executing the GPU side work.
+    GLuint query_id = 0u;
+
+    // The duration for executing the work on the raster worker thread.
+    base::TimeDelta worker_duration;
+  };
+
   bool ShouldUnpremultiplyAndDitherResource(viz::ResourceFormat format) const;
+  gpu::SyncToken PlaybackOnWorkerThreadInternal(
+      gpu::Mailbox* mailbox,
+      GLenum texture_target,
+      bool texture_is_overlay_candidate,
+      const gpu::SyncToken& sync_token,
+      const gfx::Size& resource_size,
+      viz::ResourceFormat resource_format,
+      const gfx::ColorSpace& color_space,
+      bool resource_has_previous_content,
+      const RasterSource* raster_source,
+      const gfx::Rect& raster_full_rect,
+      const gfx::Rect& raster_dirty_rect,
+      uint64_t new_content_id,
+      const gfx::AxisTransform2d& transform,
+      const RasterSource::PlaybackSettings& playback_settings,
+      const GURL& url,
+      PendingRasterQuery* query);
 
   viz::ContextProvider* const compositor_context_provider_;
   viz::RasterContextProvider* const worker_context_provider_;
@@ -125,15 +150,11 @@
   const bool unpremultiply_and_dither_low_bit_depth_tiles_;
   const bool enable_oop_rasterization_;
 
-  struct PendingRasterQuery {
-    // The id for querying the duration in executing the GPU side work.
-    GLuint query_id = 0u;
-
-    // The duration for executing the work on the raster worker thread.
-    base::TimeDelta worker_duration;
-  };
-  // This should only be accessed with the context lock acquired.
-  base::circular_deque<PendingRasterQuery> pending_raster_queries_;
+  // Note that this lock should never be acquired while holding the raster
+  // context lock.
+  base::Lock pending_raster_queries_lock_;
+  base::circular_deque<PendingRasterQuery> pending_raster_queries_
+      GUARDED_BY(pending_raster_queries_lock_);
 
   DISALLOW_COPY_AND_ASSIGN(GpuRasterBufferProvider);
 };
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index abbab26..e12b4a2d 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -640,10 +640,6 @@
       "//chrome/common:version_header",
     ]
 
-    if (is_chrome_branded) {
-      deps += [ ":chrome_helpers" ]
-    }
-
     if (enable_stripping) {
       # At link time, preserve the global symbols specified in the .exports
       # file. All other global symbols will be marked as private. The default
@@ -740,18 +736,6 @@
     ]
   }
 
-  if (is_chrome_branded) {
-    bundle_data("chrome_helpers") {
-      sources = [
-        "installer/mac/internal/keychain_reauthorizers/$chrome_mac_bundle_id",
-      ]
-
-      outputs = [
-        "{{bundle_contents_dir}}/Helpers/{{source_file_part}}",
-      ]
-    }
-  }
-
   bundle_data("chrome_versioned_bundle_data") {
     sources = [
       "$root_out_dir/$chrome_framework_name.framework",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
index f93b3f48..8e81875 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
@@ -150,6 +150,9 @@
     View getContainerView();
 
     /**
+     * TODO(twellington): Try to remove this method. It's only used to return an in-product help
+     *                    bubble anchor view... which should be moved out of tab and perhaps into
+     *                    the status bar icon component.
      * @return The view containing the security icon.
      */
     View getSecurityIconView();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 83e9215..28ba5223 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -4,20 +4,11 @@
 
 package org.chromium.chrome.browser.omnibox;
 
-import static org.chromium.chrome.browser.toolbar.ToolbarPhone.URL_FOCUS_CHANGE_ANIMATION_DURATION_MS;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
 import android.support.v4.view.MarginLayoutParamsCompat;
 import android.support.v4.view.ViewCompat;
@@ -33,9 +24,7 @@
 import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.TextView;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.CommandLine;
@@ -56,12 +45,12 @@
 import org.chromium.chrome.browser.omnibox.UrlBar.ScrollType;
 import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState;
 import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
+import org.chromium.chrome.browser.omnibox.status.StatusViewCoordinator;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator.AutocompleteDelegate;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsList;
-import org.chromium.chrome.browser.page_info.PageInfoController;
 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
@@ -72,15 +61,12 @@
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.browser.widget.ScrimView.ScrimParams;
-import org.chromium.chrome.browser.widget.TintedDrawable;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -90,7 +76,8 @@
  */
 public class LocationBarLayout extends FrameLayout
         implements OnClickListener, LocationBar, AutocompleteDelegate, FakeboxDelegate,
-                   ScrimView.ScrimObserver, LocationBarVoiceRecognitionHandler.Delegate {
+                   ScrimView.ScrimObserver, LocationBarVoiceRecognitionHandler.Delegate,
+                   StatusViewCoordinator.Delegate {
     private static final String TAG = "cr_LocationBar";
 
     private final int mLightScrimColor;
@@ -98,9 +85,6 @@
     /** Params that control how the location bar interacts with the scrim. */
     private ScrimParams mScrimParams;
 
-    protected ImageView mNavigationButton;
-    protected AppCompatImageButton mSecurityButton;
-    protected TextView mVerboseStatusTextView;
     protected AppCompatImageButton mDeleteButton;
     protected AppCompatImageButton mMicButton;
     protected View mUrlBar;
@@ -119,12 +103,7 @@
 
     private final List<Runnable> mDeferredNativeRunnables = new ArrayList<Runnable>();
 
-    // The type of the navigation button currently showing.
-    private @NavigationButtonType int mNavigationButtonType;
-
-    // The type of the security icon currently active.
-    @DrawableRes
-    private int mSecurityIconResource;
+    protected StatusViewCoordinator mStatusViewCoordiantor;
 
     private String mOriginalUrl = "";
 
@@ -140,12 +119,6 @@
 
     private boolean mVoiceSearchEnabled;
 
-    @LocationBarButtonType private int mLocationBarButtonType;
-
-    private AnimatorSet mLocationBarIconActiveAnimator;
-    private AnimatorSet mSecurityButtonShowAnimator;
-    private AnimatorSet mNavigationIconShowAnimator;
-
     private OmniboxPrerender mOmniboxPrerender;
 
     private boolean mUseDarkColors;
@@ -186,31 +159,6 @@
             return false;
         }
     }
-
-    /**
-     * Specifies the types of buttons shown to signify different types of navigation elements.
-     */
-    @IntDef({NavigationButtonType.PAGE, NavigationButtonType.MAGNIFIER, NavigationButtonType.EMPTY})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface NavigationButtonType {
-        int PAGE = 0;
-        int MAGNIFIER = 1;
-        int EMPTY = 2;
-    }
-
-    /** Specifies which button should be shown in location bar, if any. */
-    @IntDef({LocationBarButtonType.NONE, LocationBarButtonType.SECURITY_ICON,
-            LocationBarButtonType.NAVIGATION_ICON})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LocationBarButtonType {
-        /** No button should be shown. */
-        int NONE = 0;
-        /** Security button should be shown (includes offline icon). */
-        int SECURITY_ICON = 1;
-        /** Navigation button should be shown. */
-        int NAVIGATION_ICON = 2;
-    }
-
     public LocationBarLayout(Context context, AttributeSet attrs) {
         this(context, attrs, R.layout.location_bar);
     }
@@ -222,15 +170,7 @@
 
         mLightScrimColor = ApiCompatibilityUtils.getColor(
                 context.getResources(), R.color.omnibox_focused_fading_background_color_light);
-        mNavigationButton = (ImageView) findViewById(R.id.navigation_button);
-        assert mNavigationButton != null : "Missing navigation type view.";
         mIsTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(context);
-        mNavigationButtonType = mIsTablet ? NavigationButtonType.PAGE : NavigationButtonType.EMPTY;
-
-        mSecurityButton = (AppCompatImageButton) findViewById(R.id.security_button);
-        mSecurityIconResource = 0;
-
-        mVerboseStatusTextView = (TextView) findViewById(R.id.location_bar_verbose_status);
 
         mDeleteButton = (AppCompatImageButton) findViewById(R.id.delete_button);
 
@@ -290,45 +230,9 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mLocationBarButtonType = LocationBarButtonType.NONE;
-        mNavigationButton.setVisibility(INVISIBLE);
-        mSecurityButton.setVisibility(INVISIBLE);
-
         setLayoutTransition(null);
 
-        AnimatorListenerAdapter iconChangeAnimatorListener = new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (animation == mSecurityButtonShowAnimator) {
-                    mNavigationButton.setVisibility(INVISIBLE);
-                } else if (animation == mNavigationIconShowAnimator) {
-                    mSecurityButton.setVisibility(INVISIBLE);
-                }
-            }
-
-            @Override
-            public void onAnimationStart(Animator animation) {
-                if (animation == mSecurityButtonShowAnimator) {
-                    mSecurityButton.setVisibility(VISIBLE);
-                } else if (animation == mNavigationIconShowAnimator) {
-                    mNavigationButton.setVisibility(VISIBLE);
-                }
-            }
-        };
-
-        mSecurityButtonShowAnimator = new AnimatorSet();
-        mSecurityButtonShowAnimator.playTogether(
-                ObjectAnimator.ofFloat(mNavigationButton, ALPHA, 0),
-                ObjectAnimator.ofFloat(mSecurityButton, ALPHA, 1));
-        mSecurityButtonShowAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-        mSecurityButtonShowAnimator.addListener(iconChangeAnimatorListener);
-
-        mNavigationIconShowAnimator = new AnimatorSet();
-        mNavigationIconShowAnimator.playTogether(
-                ObjectAnimator.ofFloat(mNavigationButton, ALPHA, 1),
-                ObjectAnimator.ofFloat(mSecurityButton, ALPHA, 0));
-        mNavigationIconShowAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-        mNavigationIconShowAnimator.addListener(iconChangeAnimatorListener);
+        mStatusViewCoordiantor = new StatusViewCoordinator(mIsTablet, this, this);
 
         mUrlBar.setOnKeyListener(new UrlBarKeyListener());
 
@@ -379,6 +283,7 @@
         mWindowAndroid = windowAndroid;
 
         mUrlCoordinator.setWindowDelegate(windowDelegate);
+        mStatusViewCoordiantor.setWindowAndroid(windowAndroid);
     }
 
     /**
@@ -410,9 +315,7 @@
         mNativeInitialized = true;
 
         mAutocompleteCoordinator.onNativeInitialized();
-        mSecurityButton.setOnClickListener(this);
-        mNavigationButton.setOnClickListener(this);
-        mVerboseStatusTextView.setOnClickListener(this);
+        mStatusViewCoordiantor.onNativeInitialized();
         updateMicButtonState();
         mDeleteButton.setOnClickListener(this);
         mMicButton.setOnClickListener(this);
@@ -431,10 +334,8 @@
         updateMicButtonVisibility(mUrlFocusChangePercent);
     }
 
-    /**
-     * @return Whether or not to animate icon changes.
-     */
-    protected boolean shouldAnimateIconChanges() {
+    @Override
+    public boolean shouldAnimateIconChanges() {
         return mUrlHasFocus;
     }
 
@@ -453,52 +354,6 @@
         mOmniboxPrerender.initializeForProfile(profile);
     }
 
-    @LocationBarButtonType private int getLocationBarButtonToShow() {
-        // The navigation icon type is only applicable on tablets.  While smaller form factors do
-        // not have an icon visible to the user when the URL is focused, BUTTON_TYPE_NONE is not
-        // returned as it will trigger an undesired jump during the animation as it attempts to
-        // hide the icon.
-        if (mUrlHasFocus && mIsTablet) return LocationBarButtonType.NAVIGATION_ICON;
-
-        return mToolbarDataProvider.getSecurityIconResource(mIsTablet) != 0
-                ? LocationBarButtonType.SECURITY_ICON
-                : LocationBarButtonType.NONE;
-    }
-
-    private void changeLocationBarIcon() {
-        if (mLocationBarIconActiveAnimator != null && mLocationBarIconActiveAnimator.isRunning()) {
-            mLocationBarIconActiveAnimator.cancel();
-        }
-
-        mLocationBarButtonType = getLocationBarButtonToShow();
-
-        View viewToBeShown = null;
-        switch (mLocationBarButtonType) {
-            case LocationBarButtonType.SECURITY_ICON:
-                viewToBeShown = mSecurityButton;
-                mLocationBarIconActiveAnimator = mSecurityButtonShowAnimator;
-                break;
-            case LocationBarButtonType.NAVIGATION_ICON:
-                viewToBeShown = mNavigationButton;
-                mLocationBarIconActiveAnimator = mNavigationIconShowAnimator;
-                break;
-            case LocationBarButtonType.NONE:
-            default:
-                mLocationBarIconActiveAnimator = null;
-                return;
-        }
-
-        if (viewToBeShown.getVisibility() == VISIBLE && viewToBeShown.getAlpha() == 1) {
-            return;
-        }
-        if (shouldAnimateIconChanges()) {
-            mLocationBarIconActiveAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-        } else {
-            mLocationBarIconActiveAnimator.setDuration(0);
-        }
-        mLocationBarIconActiveAnimator.start();
-    }
-
     /** Focuses the current page. */
     private void focusCurrentTab() {
         if (mToolbarDataProvider.hasTab()) getCurrentTab().requestFocus();
@@ -604,9 +459,7 @@
 
         if (mToolbarDataProvider.isUsingBrandColor()) updateVisualsForState();
 
-        changeLocationBarIcon();
-        updateVerboseStatusVisibility();
-        updateLocationBarIconContainerVisibility();
+        mStatusViewCoordiantor.onUrlFocusChange(mUrlHasFocus);
 
         if (!mUrlFocusedWithoutAnimations) handleUrlFocusAnimation(hasFocus);
 
@@ -704,6 +557,7 @@
         updateButtonVisibility();
 
         mAutocompleteCoordinator.setToolbarDataProvider(toolbarDataProvider);
+        mStatusViewCoordiantor.setToolbarDataProvider(toolbarDataProvider);
         mUrlCoordinator.setOnFocusChangedCallback(this::onUrlFocusChange);
     }
 
@@ -727,28 +581,28 @@
         return mToolbarDataProvider;
     }
 
-    private static @NavigationButtonType int suggestionTypeToNavigationButtonType(
-            OmniboxSuggestion suggestion) {
+    private static @StatusViewCoordinator.NavigationButtonType
+    int suggestionTypeToNavigationButtonType(OmniboxSuggestion suggestion) {
         if (suggestion.isUrlSuggestion()) {
-            return NavigationButtonType.PAGE;
+            return StatusViewCoordinator.NavigationButtonType.PAGE;
         } else {
-            return NavigationButtonType.MAGNIFIER;
+            return StatusViewCoordinator.NavigationButtonType.MAGNIFIER;
         }
     }
 
     // Updates the navigation button based on the URL string
     private void updateNavigationButton() {
-        @NavigationButtonType
-        int type = NavigationButtonType.EMPTY;
+        @StatusViewCoordinator.NavigationButtonType
+        int type = StatusViewCoordinator.NavigationButtonType.EMPTY;
         if (mIsTablet && mAutocompleteCoordinator.getSuggestionCount() > 0) {
             // If there are suggestions showing, show the icon for the default suggestion.
             type = suggestionTypeToNavigationButtonType(
                     mAutocompleteCoordinator.getSuggestionAt(0));
         } else if (mIsTablet) {
-            type = NavigationButtonType.PAGE;
+            type = StatusViewCoordinator.NavigationButtonType.PAGE;
         }
 
-        if (type != mNavigationButtonType) setNavigationButtonType(type);
+        mStatusViewCoordiantor.setNavigationButtonType(type);
     }
 
     /**
@@ -756,130 +610,12 @@
      */
     @Override
     public void updateSecurityIcon() {
-        @DrawableRes
-        int id = mToolbarDataProvider.getSecurityIconResource(mIsTablet);
-        if (id == 0) {
-            mSecurityButton.setImageDrawable(null);
-        } else {
-            // ImageView#setImageResource is no-op if given resource is the current one.
-            mSecurityButton.setImageResource(id);
-            ApiCompatibilityUtils.setImageTintList(
-                    mSecurityButton, mToolbarDataProvider.getSecurityIconColorStateList());
-        }
-
-        int contentDescriptionId = getToolbarDataProvider().getSecurityIconContentDescription();
-        String contentDescription = getContext().getString(contentDescriptionId);
-        mSecurityButton.setContentDescription(contentDescription);
-
-        updateVerboseStatusVisibility();
-
-        if (mSecurityIconResource == id && mLocationBarButtonType == getLocationBarButtonToShow()) {
-            return;
-        }
-        mSecurityIconResource = id;
-
-        changeLocationBarIcon();
-        updateLocationBarIconContainerVisibility();
-
+        mStatusViewCoordiantor.updateSecurityIcon();
         // Update the URL in case the scheme change triggers a URL emphasis change.
         setUrlToPageUrl();
     }
 
     /**
-     * @return Whether the security button is currently being displayed.
-     */
-    @VisibleForTesting
-    public boolean isSecurityButtonShown() {
-        return mLocationBarButtonType == LocationBarButtonType.SECURITY_ICON;
-    }
-
-    /**
-     * @return The ID of the drawable currently shown in the security icon.
-     */
-    @VisibleForTesting
-    @DrawableRes
-    int getSecurityIconResourceId() {
-        return mSecurityIconResource;
-    }
-
-    /**
-     * Sets the type of the current navigation type and updates the UI to match it.
-     * @param buttonType The type of navigation button to be shown.
-     */
-    private void setNavigationButtonType(@NavigationButtonType int buttonType) {
-        if (!mIsTablet) return;
-        switch (buttonType) {
-            case NavigationButtonType.PAGE:
-                Drawable page = TintedDrawable.constructTintedDrawable(getContext(),
-                        R.drawable.ic_omnibox_page,
-                        mUseDarkColors ? R.color.dark_mode_tint : R.color.light_mode_tint);
-                mNavigationButton.setImageDrawable(page);
-                break;
-            case NavigationButtonType.MAGNIFIER:
-                Drawable search = TintedDrawable.constructTintedDrawable(getContext(),
-                        R.drawable.omnibox_search,
-                        mUseDarkColors ? R.color.dark_mode_tint : R.color.light_mode_tint);
-                mNavigationButton.setImageDrawable(search);
-                break;
-            case NavigationButtonType.EMPTY:
-                mNavigationButton.setImageDrawable(null);
-                break;
-            default:
-                assert false;
-        }
-
-        if (mNavigationButton.getVisibility() != VISIBLE) {
-            mNavigationButton.setVisibility(VISIBLE);
-        }
-        mNavigationButtonType = buttonType;
-
-        updateLocationBarIconContainerVisibility();
-    }
-
-    /**
-     * Update visibility of the verbose status based on the button type and focus state of the
-     * omnibox.
-     */
-    private void updateVerboseStatusVisibility() {
-        boolean verboseStatusVisible =
-                !mUrlHasFocus && mToolbarDataProvider.shouldShowVerboseStatus();
-
-        int verboseStatusVisibility = verboseStatusVisible ? VISIBLE : GONE;
-
-        mVerboseStatusTextView.setVisibility(verboseStatusVisibility);
-
-        View separator = findViewById(R.id.location_bar_verbose_status_separator);
-        separator.setVisibility(verboseStatusVisibility);
-
-        findViewById(R.id.location_bar_verbose_status_extra_space)
-                .setVisibility(verboseStatusVisibility);
-
-        if (!verboseStatusVisible) {
-            // Return early since everything past here requires the verbose status to be visible
-            // and able to be populated with content.
-            return;
-        }
-
-        mVerboseStatusTextView.setText(mToolbarDataProvider.getVerboseStatusString());
-        mVerboseStatusTextView.setTextColor(
-                mToolbarDataProvider.getVerboseStatusTextColor(getResources(), mUseDarkColors));
-
-        separator.setBackgroundColor(mToolbarDataProvider.getVerboseStatusSeparatorColor(
-                getResources(), mUseDarkColors));
-    }
-
-    /**
-     * Update the visibility of the location bar icon container based on the state of the
-     * security and navigation icons.
-     */
-    protected void updateLocationBarIconContainerVisibility() {
-        @LocationBarButtonType
-        int buttonToShow = getLocationBarButtonToShow();
-        findViewById(R.id.location_bar_icon)
-                .setVisibility(buttonToShow != LocationBarButtonType.NONE ? VISIBLE : GONE);
-    }
-
-    /**
      * @return The margin to be applied to the URL bar based on the buttons currently visible next
      *         to it, used to avoid text overlapping the buttons and vice versa.
      */
@@ -1094,13 +830,6 @@
         });
     }
 
-    /**
-     * Whether {@code v} is a view (location icon, verbose status, ...) which can be clicked to
-     * show the Page Info popup.
-     */
-    private boolean shouldShowPageInfoForView(View v) {
-        return v == mSecurityButton || v == mNavigationButton || v == mVerboseStatusTextView;
-    }
 
     @Override
     public void onClick(View v) {
@@ -1114,15 +843,6 @@
             mAutocompleteCoordinator.startZeroSuggest();
             RecordUserAction.record("MobileOmniboxDeleteUrl");
             return;
-        } else if (!mUrlHasFocus && shouldShowPageInfoForView(v)) {
-            if (mToolbarDataProvider.hasTab() && getCurrentTab().getWebContents() != null
-                    && mWindowAndroid != null) {
-                Activity activity = mWindowAndroid.getActivity().get();
-                if (activity != null) {
-                    PageInfoController.show(activity, getCurrentTab(), null,
-                            PageInfoController.OpenedFromSource.TOOLBAR);
-                }
-            }
         } else if (v == mMicButton && mVoiceRecognitionHandler != null) {
             RecordUserAction.record("MobileOmniboxVoiceSearch");
             mVoiceRecognitionHandler.startVoiceRecognition(
@@ -1287,7 +1007,7 @@
     public void updateLoadingState(boolean updateUrl) {
         if (updateUrl) setUrlToPageUrl();
         updateNavigationButton();
-        updateSecurityIcon();
+        mStatusViewCoordiantor.updateSecurityIcon();
     }
 
     /** @return The current active {@link Tab}. */
@@ -1430,14 +1150,12 @@
      */
     @Override
     public void updateVisualsForState() {
-        if (updateUseDarkColors()) updateSecurityIcon();
+        if (updateUseDarkColors()) mStatusViewCoordiantor.setUseDarkColors(mUseDarkColors);
         int id = mUseDarkColors ? R.color.dark_mode_tint : R.color.light_mode_tint;
         ColorStateList colorStateList = AppCompatResources.getColorStateList(getContext(), id);
         ApiCompatibilityUtils.setImageTintList(mMicButton, colorStateList);
         ApiCompatibilityUtils.setImageTintList(mDeleteButton, colorStateList);
 
-        setNavigationButtonType(mNavigationButtonType);
-
         // If the URL changed colors and is not focused, update the URL to account for the new
         // color scheme.
         if (mUrlCoordinator.setUseDarkTextColors(mUseDarkColors) && !mUrlBar.hasFocus()) {
@@ -1480,7 +1198,7 @@
 
     @Override
     public View getSecurityIconView() {
-        return mSecurityButton;
+        return mStatusViewCoordiantor.getSecurityIconView();
     }
 
     @Override
@@ -1493,4 +1211,9 @@
     public WindowAndroid getWindowAndroid() {
         return mWindowAndroid;
     }
+
+    @VisibleForTesting
+    public StatusViewCoordinator getStatusViewCoordinatorForTesting() {
+        return mStatusViewCoordiantor;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
index 44276d9..f4946aa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -165,7 +165,7 @@
     }
 
     @Override
-    protected boolean shouldAnimateIconChanges() {
+    public boolean shouldAnimateIconChanges() {
         return super.shouldAnimateIconChanges() || isUrlFocusChangeInProgress();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
index dfc71b7..2ea54363 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
@@ -198,8 +198,8 @@
     }
 
     private void finishUrlFocusChange(boolean hasFocus) {
+        mStatusViewCoordiantor.setSecurityButtonVisibility(!hasFocus);
         if (hasFocus) {
-            if (mSecurityButton.getVisibility() == VISIBLE) mSecurityButton.setVisibility(GONE);
             if (getWindowDelegate().getWindowSoftInputMode()
                     != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) {
                 getWindowDelegate().setWindowSoftInputMode(
@@ -207,12 +207,6 @@
             }
             getWindowAndroid().getKeyboardDelegate().showKeyboard(mUrlBar);
         } else {
-            if (mSecurityButton.getVisibility() == GONE
-                    && mSecurityButton.getDrawable() != null
-                    && mSecurityButton.getDrawable().getIntrinsicWidth() > 0
-                    && mSecurityButton.getDrawable().getIntrinsicHeight() > 0) {
-                mSecurityButton.setVisibility(VISIBLE);
-            }
             getWindowAndroid().getKeyboardDelegate().hideKeyboard(mUrlBar);
             // Convert the keyboard back to resize mode (delay the change for an arbitrary
             // amount of time in hopes the keyboard will be completely hidden before making
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java
new file mode 100644
index 0000000..ac4c9c0
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java
@@ -0,0 +1,421 @@
+// 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.omnibox.status;
+
+import static org.chromium.chrome.browser.toolbar.ToolbarPhone.URL_FOCUS_CHANGE_ANIMATION_DURATION_MS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IntDef;
+import android.support.v7.widget.AppCompatImageButton;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.page_info.PageInfoController;
+import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
+import org.chromium.chrome.browser.widget.TintedDrawable;
+import org.chromium.ui.base.WindowAndroid;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A component for displaying a status icon (e.g. security icon or navigation icon) and optional
+ * verbose status text.
+ */
+public class StatusViewCoordinator implements View.OnClickListener {
+    /**
+     * Specifies the types of buttons shown to signify different types of navigation elements.
+     */
+    @IntDef({NavigationButtonType.PAGE, NavigationButtonType.MAGNIFIER, NavigationButtonType.EMPTY})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NavigationButtonType {
+        int PAGE = 0;
+        int MAGNIFIER = 1;
+        int EMPTY = 2;
+    }
+
+    /** Specifies which button should be shown in location bar, if any. */
+    @IntDef({LocationBarButtonType.NONE, LocationBarButtonType.SECURITY_ICON,
+            LocationBarButtonType.NAVIGATION_ICON})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LocationBarButtonType {
+        /** No button should be shown. */
+        int NONE = 0;
+        /** Security button should be shown (includes offline icon). */
+        int SECURITY_ICON = 1;
+        /** Navigation button should be shown. */
+        int NAVIGATION_ICON = 2;
+    }
+
+    /**
+     * Delegate interface to provide additional information needed to display this view.
+     */
+    public interface Delegate {
+        /**
+         * @return Whether or not to animate icon changes.
+         */
+        boolean shouldAnimateIconChanges();
+    }
+
+    private final Delegate mDelegate;
+    private final boolean mIsTablet;
+    private final View mParentView;
+    private final ImageView mNavigationButton;
+    private final AppCompatImageButton mSecurityButton;
+    private final TextView mVerboseStatusTextView;
+
+    private ToolbarDataProvider mToolbarDataProvider;
+    private WindowAndroid mWindowAndroid;
+
+    // The type of the navigation button currently showing.
+    private @NavigationButtonType int mNavigationButtonType;
+
+    // The type of the security icon currently active.
+    @DrawableRes
+    private int mSecurityIconResource;
+
+    @LocationBarButtonType
+    private int mLocationBarButtonType;
+
+    private AnimatorSet mLocationBarIconActiveAnimator;
+    private AnimatorSet mSecurityButtonShowAnimator;
+    private AnimatorSet mNavigationIconShowAnimator;
+
+    private boolean mUrlHasFocus;
+    private boolean mUseDarkColors;
+
+    /**
+     * Creates a new StatusViewCoordinator.
+     * @param isTablet Whether the UI is shown on a tablet.
+     * @param parentView The parent view that contains the status view, used to retrieve views.
+     * @param delegate The delegate that provides additional information needed to display this
+     *                 view.
+     */
+    public StatusViewCoordinator(boolean isTablet, View parentView, Delegate delegate) {
+        mIsTablet = isTablet;
+        mParentView = parentView;
+        mDelegate = delegate;
+
+        mNavigationButton = mParentView.findViewById(R.id.navigation_button);
+        assert mNavigationButton != null : "Missing navigation type view.";
+        mNavigationButtonType = mIsTablet ? NavigationButtonType.PAGE : NavigationButtonType.EMPTY;
+
+        mSecurityButton = mParentView.findViewById(R.id.security_button);
+        mSecurityIconResource = 0;
+
+        mVerboseStatusTextView = mParentView.findViewById(R.id.location_bar_verbose_status);
+
+        mLocationBarButtonType = LocationBarButtonType.NONE;
+        mNavigationButton.setVisibility(View.INVISIBLE);
+        mSecurityButton.setVisibility(View.INVISIBLE);
+
+        AnimatorListenerAdapter iconChangeAnimatorListener = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (animation == mSecurityButtonShowAnimator) {
+                    mNavigationButton.setVisibility(View.INVISIBLE);
+                } else if (animation == mNavigationIconShowAnimator) {
+                    mSecurityButton.setVisibility(View.INVISIBLE);
+                }
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                if (animation == mSecurityButtonShowAnimator) {
+                    mSecurityButton.setVisibility(View.VISIBLE);
+                } else if (animation == mNavigationIconShowAnimator) {
+                    mNavigationButton.setVisibility(View.VISIBLE);
+                }
+            }
+        };
+
+        mSecurityButtonShowAnimator = new AnimatorSet();
+        mSecurityButtonShowAnimator.playTogether(
+                ObjectAnimator.ofFloat(mNavigationButton, View.ALPHA, 0),
+                ObjectAnimator.ofFloat(mSecurityButton, View.ALPHA, 1));
+        mSecurityButtonShowAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
+        mSecurityButtonShowAnimator.addListener(iconChangeAnimatorListener);
+
+        mNavigationIconShowAnimator = new AnimatorSet();
+        mNavigationIconShowAnimator.playTogether(
+                ObjectAnimator.ofFloat(mNavigationButton, View.ALPHA, 1),
+                ObjectAnimator.ofFloat(mSecurityButton, View.ALPHA, 0));
+        mNavigationIconShowAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
+        mNavigationIconShowAnimator.addListener(iconChangeAnimatorListener);
+    }
+
+    /**
+     * Provides data and state for the toolbar component.
+     * @param toolbarDataProvider The data provider.
+     */
+    public void setToolbarDataProvider(ToolbarDataProvider toolbarDataProvider) {
+        mToolbarDataProvider = toolbarDataProvider;
+    }
+
+    /**
+     * Provides the WindowAndroid for the parent component. Used to retreive the current activity
+     * on demand.
+     * @param windowAndroid The current {@link WindowAndroid}.
+     */
+    public void setWindowAndroid(WindowAndroid windowAndroid) {
+        mWindowAndroid = windowAndroid;
+    }
+
+    /**
+     * Signals that native initialization has completed.
+     */
+    public void onNativeInitialized() {
+        mSecurityButton.setOnClickListener(this);
+        mNavigationButton.setOnClickListener(this);
+        mVerboseStatusTextView.setOnClickListener(this);
+    }
+
+    /**
+     * @param urlHasFocus Whether the url currently has focus.
+     */
+    public void onUrlFocusChange(boolean urlHasFocus) {
+        mUrlHasFocus = urlHasFocus;
+        changeLocationBarIcon();
+        updateVerboseStatusVisibility();
+        updateLocationBarIconContainerVisibility();
+    }
+
+    /**
+     * @param useDarkColors Whether dark colors should be for the status icon and text.
+     */
+    public void setUseDarkColors(boolean useDarkColors) {
+        mUseDarkColors = useDarkColors;
+        updateSecurityIcon();
+        setNavigationButtonType(mNavigationButtonType);
+    }
+
+    @LocationBarButtonType
+    private int getLocationBarButtonToShow() {
+        // The navigation icon type is only applicable on tablets.  While smaller form factors do
+        // not have an icon visible to the user when the URL is focused, BUTTON_TYPE_NONE is not
+        // returned as it will trigger an undesired jump during the animation as it attempts to
+        // hide the icon.
+        if (mUrlHasFocus && mIsTablet) return LocationBarButtonType.NAVIGATION_ICON;
+
+        return mToolbarDataProvider.getSecurityIconResource(mIsTablet) != 0
+                ? LocationBarButtonType.SECURITY_ICON
+                : LocationBarButtonType.NONE;
+    }
+
+    private void changeLocationBarIcon() {
+        if (mLocationBarIconActiveAnimator != null && mLocationBarIconActiveAnimator.isRunning()) {
+            mLocationBarIconActiveAnimator.cancel();
+        }
+
+        mLocationBarButtonType = getLocationBarButtonToShow();
+
+        View viewToBeShown = null;
+        switch (mLocationBarButtonType) {
+            case LocationBarButtonType.SECURITY_ICON:
+                viewToBeShown = mSecurityButton;
+                mLocationBarIconActiveAnimator = mSecurityButtonShowAnimator;
+                break;
+            case LocationBarButtonType.NAVIGATION_ICON:
+                viewToBeShown = mNavigationButton;
+                mLocationBarIconActiveAnimator = mNavigationIconShowAnimator;
+                break;
+            case LocationBarButtonType.NONE:
+            default:
+                mLocationBarIconActiveAnimator = null;
+                return;
+        }
+
+        if (viewToBeShown.getVisibility() == View.VISIBLE && viewToBeShown.getAlpha() == 1) {
+            return;
+        }
+        if (mDelegate.shouldAnimateIconChanges()) {
+            mLocationBarIconActiveAnimator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
+        } else {
+            mLocationBarIconActiveAnimator.setDuration(0);
+        }
+        mLocationBarIconActiveAnimator.start();
+    }
+
+    /**
+     * Updates the security icon displayed in the LocationBar.
+     */
+    public void updateSecurityIcon() {
+        @DrawableRes
+        int id = mToolbarDataProvider.getSecurityIconResource(mIsTablet);
+        if (id == 0) {
+            mSecurityButton.setImageDrawable(null);
+        } else {
+            // ImageView#setImageResource is no-op if given resource is the current one.
+            mSecurityButton.setImageResource(id);
+            ApiCompatibilityUtils.setImageTintList(
+                    mSecurityButton, mToolbarDataProvider.getSecurityIconColorStateList());
+        }
+
+        int contentDescriptionId = mToolbarDataProvider.getSecurityIconContentDescription();
+        String contentDescription = mParentView.getContext().getString(contentDescriptionId);
+        mSecurityButton.setContentDescription(contentDescription);
+
+        updateVerboseStatusVisibility();
+
+        if (mSecurityIconResource == id && mLocationBarButtonType == getLocationBarButtonToShow()) {
+            return;
+        }
+        mSecurityIconResource = id;
+
+        changeLocationBarIcon();
+        updateLocationBarIconContainerVisibility();
+    }
+
+    /**
+     * @return The view displaying the security icon.
+     */
+    public View getSecurityIconView() {
+        return mSecurityButton;
+    }
+
+    /**
+     * @return Whether the security button is currently being displayed.
+     */
+    @VisibleForTesting
+    public boolean isSecurityButtonShown() {
+        return mLocationBarButtonType == LocationBarButtonType.SECURITY_ICON;
+    }
+
+    /**
+     * @return The ID of the drawable currently shown in the security icon.
+     */
+    @VisibleForTesting
+    @DrawableRes
+    public int getSecurityIconResourceId() {
+        return mSecurityIconResource;
+    }
+
+    /**
+     * Sets the type of the current navigation type and updates the UI to match it.
+     * @param buttonType The type of navigation button to be shown.
+     */
+    public void setNavigationButtonType(@NavigationButtonType int buttonType) {
+        // TODO(twellington): Return early if the navigation button type and tint hasn't changed.
+        if (!mIsTablet) return;
+        switch (buttonType) {
+            case NavigationButtonType.PAGE:
+                Drawable page = TintedDrawable.constructTintedDrawable(mParentView.getContext(),
+                        R.drawable.ic_omnibox_page,
+                        mUseDarkColors ? R.color.dark_mode_tint : R.color.light_mode_tint);
+                mNavigationButton.setImageDrawable(page);
+                break;
+            case NavigationButtonType.MAGNIFIER:
+                Drawable search = TintedDrawable.constructTintedDrawable(mParentView.getContext(),
+                        R.drawable.omnibox_search,
+                        mUseDarkColors ? R.color.dark_mode_tint : R.color.light_mode_tint);
+                mNavigationButton.setImageDrawable(search);
+                break;
+            case NavigationButtonType.EMPTY:
+                mNavigationButton.setImageDrawable(null);
+                break;
+            default:
+                assert false;
+        }
+
+        if (mNavigationButton.getVisibility() != View.VISIBLE) {
+            mNavigationButton.setVisibility(View.VISIBLE);
+        }
+        mNavigationButtonType = buttonType;
+
+        updateLocationBarIconContainerVisibility();
+    }
+
+    /**
+     * @param visible Whether the navigation button should be visible.
+     */
+    public void setSecurityButtonVisibility(boolean visible) {
+        if (!visible && mSecurityButton.getVisibility() == View.VISIBLE) {
+            mSecurityButton.setVisibility(View.GONE);
+        } else if (visible && mSecurityButton.getVisibility() == View.GONE
+                && mSecurityButton.getDrawable() != null
+                && mSecurityButton.getDrawable().getIntrinsicWidth() > 0
+                && mSecurityButton.getDrawable().getIntrinsicHeight() > 0) {
+            mSecurityButton.setVisibility(View.VISIBLE);
+        }
+    }
+
+    /**
+     * Update visibility of the verbose status based on the button type and focus state of the
+     * omnibox.
+     */
+    private void updateVerboseStatusVisibility() {
+        boolean verboseStatusVisible =
+                !mUrlHasFocus && mToolbarDataProvider.shouldShowVerboseStatus();
+
+        int verboseStatusVisibility = verboseStatusVisible ? View.VISIBLE : View.GONE;
+
+        mVerboseStatusTextView.setVisibility(verboseStatusVisibility);
+
+        View separator = mParentView.findViewById(R.id.location_bar_verbose_status_separator);
+        separator.setVisibility(verboseStatusVisibility);
+
+        mParentView.findViewById(R.id.location_bar_verbose_status_extra_space)
+                .setVisibility(verboseStatusVisibility);
+
+        if (!verboseStatusVisible) {
+            // Return early since everything past here requires the verbose status to be visible
+            // and able to be populated with content.
+            return;
+        }
+
+        mVerboseStatusTextView.setText(mToolbarDataProvider.getVerboseStatusString());
+        mVerboseStatusTextView.setTextColor(mToolbarDataProvider.getVerboseStatusTextColor(
+                mParentView.getResources(), mUseDarkColors));
+
+        separator.setBackgroundColor(mToolbarDataProvider.getVerboseStatusSeparatorColor(
+                mParentView.getResources(), mUseDarkColors));
+    }
+
+    /**
+     * Update the visibility of the location bar icon container based on the state of the
+     * security and navigation icons.
+     */
+    protected void updateLocationBarIconContainerVisibility() {
+        @LocationBarButtonType
+        int buttonToShow = getLocationBarButtonToShow();
+        mParentView.findViewById(R.id.location_bar_icon)
+                .setVisibility(
+                        buttonToShow != LocationBarButtonType.NONE ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Whether {@code v} is a view (location icon, verbose status, ...) which can be clicked to
+     * show the Page Info popup.
+     */
+    public boolean shouldShowPageInfoForView(View v) {
+        return v == mSecurityButton || v == mNavigationButton || v == mVerboseStatusTextView;
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (mUrlHasFocus || !shouldShowPageInfoForView(view)) return;
+
+        if (!mToolbarDataProvider.hasTab() || mToolbarDataProvider.getTab().getWebContents() == null
+                || mWindowAndroid == null) {
+            return;
+        }
+
+        Activity activity = mWindowAndroid.getActivity().get();
+        if (activity != null) {
+            PageInfoController.show(activity, mToolbarDataProvider.getTab(), null,
+                    PageInfoController.OpenedFromSource.TOOLBAR);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index b0ec39d4..3927cbf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -77,8 +77,8 @@
 /**
  * The Toolbar layout to be used for a custom tab. This is used for both phone and tablet UIs.
  */
-public class CustomTabToolbar extends ToolbarLayout implements LocationBar,
-        View.OnLongClickListener {
+public class CustomTabToolbar
+        extends ToolbarLayout implements LocationBar, View.OnLongClickListener {
     private static final Object ORIGIN_SPAN = new Object();
 
     /**
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 3fea9292..13615f1c 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
@@ -1055,6 +1055,9 @@
     }
 
     /**
+     * TODO(twellington): Try to remove this method. It's only used to return an in-product help
+     *                    bubble anchor view... which should be moved out of tab and perhaps into
+     *                    the status bar icon component.
      * @return The view containing the security icon.
      */
     public View getSecurityIconView() {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index ca46acb..742f51f 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2237,7 +2237,7 @@
         Open Online
       </message>
       <message name="IDS_PAGE_INFO_PREVIEW_MESSAGE" desc="This text is displayed in the page info bubble when the currently viewed page has been modified by Google to be a lighter and faster version of the original page. The word 'Lite' should match the translation in TC ID 1019734090540434451">
-        Lite page delivered by Google
+        Lite page provided by Google
       </message>
       <message name="IDS_PAGE_INFO_PREVIEW_LOAD_ORIGINAL" desc="This text, when clicked, loads the original page from its origin without any treatments. This text is shown in the page info bubble when the currently viewed page has been modified to be a lighter and faster version of the original page.">
         <ph name="BEGIN_LINK">&lt;link&gt;</ph>Load original page<ph name="END_LINK">&lt;/link&gt;</ph> from <ph name="DOMAIN_NAME">%1$s<ex>google.com</ex></ph>
@@ -3766,11 +3766,11 @@
       <message name="IDS_IPH_MEDIA_DOWNLOAD_ACCESSIBILITY_TEXT" desc="The in-product-help accessibility text to download a video.">
         Download videos to watch later using the Download button
       </message>
-      <message name="IDS_IPH_PREVIEWS_OMNIBOX_UI_TEXT" desc="The in-product-help text informing the user that the displayed page was modified to make it load faster or use less data. Prompts the user to tap the message and load the original, unaltered, page if they would like. The 'Lite page delivered by Google.' sentence should match TC ID 373879247902731825">
-        Lite page delivered by Google. Tap to load the original.
+      <message name="IDS_IPH_PREVIEWS_OMNIBOX_UI_TEXT" desc="The in-product-help text informing the user that the displayed page was modified to make it load faster or use less data. Prompts the user to tap the message and load the original, unaltered, page if they would like. The 'Lite page provided by Google.' sentence should match TC ID 373879247902731825">
+        Lite page provided by Google. Tap to load the original.
       </message>
-      <message name="IDS_IPH_PREVIEWS_OMNIBOX_UI_ACCESSIBILITY_TEXT" desc="The in-product-help text informing the user that the displayed page was modified to make it load faster or use less data. Prompts the user to tap the message and load the original, unaltered, page if they would like. The 'Lite page delivered by Google.' sentence should match TC ID 373879247902731825">
-        Lite page delivered by Google. Tap the load original button to load the original page.
+      <message name="IDS_IPH_PREVIEWS_OMNIBOX_UI_ACCESSIBILITY_TEXT" desc="The in-product-help text informing the user that the displayed page was modified to make it load faster or use less data. Prompts the user to tap the message and load the original, unaltered, page if they would like. The 'Lite page provided by Google.' sentence should match TC ID 373879247902731825">
+        Lite page provided by Google. Tap the load original button to load the original page.
       </message>
 
 
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 12005eb..8a0ec97 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1074,6 +1074,7 @@
   "java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java",
   "java/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworks.java",
   "java/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTracker.java",
+  "java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/AnswerTextBuilder.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/AnswersImage.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageTest.java
index 0b1a072..ffb114a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageTest.java
@@ -6,13 +6,18 @@
 
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.action.ViewActions.swipeLeft;
 import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
 
+import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.instanceOf;
 
+import static org.chromium.chrome.test.util.ViewUtils.VIEW_NULL;
+import static org.chromium.chrome.test.util.ViewUtils.waitForView;
+
 import android.support.test.InstrumentationRegistry;
 import android.support.test.espresso.contrib.RecyclerViewActions;
 import android.support.test.filters.MediumTest;
@@ -36,6 +41,7 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.ntp.cards.SignInPromo;
 import org.chromium.chrome.browser.ntp.snippets.SectionHeader;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.suggestions.SiteSuggestion;
@@ -61,6 +67,9 @@
 @CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
 @Features.EnableFeatures(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS)
 public class FeedNewTabPageTest {
+    private static final int SIGNIN_PROMO_POSITION = 1;
+    private static final int ARTICLE_SECTION_HEADER_POSITION = 2;
+
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
@@ -114,18 +123,21 @@
         // that sign-in promo is not shown.
         ThreadUtils.runOnUiThreadBlocking(signinObserver::onSignedIn);
         RecyclerViewTestUtils.waitForStableRecyclerView(recyclerView);
-        onView(instanceOf(RecyclerView.class)).perform(RecyclerViewActions.scrollToPosition(1));
+        onView(instanceOf(RecyclerView.class))
+                .perform(RecyclerViewActions.scrollToPosition(SIGNIN_PROMO_POSITION));
         onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
 
         // Simulate sign out, scroll to the position where sign-in promo could be placed, and verify
         // that sign-in promo is shown.
         ThreadUtils.runOnUiThreadBlocking(signinObserver::onSignedOut);
         RecyclerViewTestUtils.waitForStableRecyclerView(recyclerView);
-        onView(instanceOf(RecyclerView.class)).perform(RecyclerViewActions.scrollToPosition(1));
+        onView(instanceOf(RecyclerView.class))
+                .perform(RecyclerViewActions.scrollToPosition(SIGNIN_PROMO_POSITION));
         onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
 
         // Scroll to the article section header in case it is not visible.
-        onView(instanceOf(RecyclerView.class)).perform(RecyclerViewActions.scrollToPosition(2));
+        onView(instanceOf(RecyclerView.class))
+                .perform(RecyclerViewActions.scrollToPosition(ARTICLE_SECTION_HEADER_POSITION));
 
         // Hide articles and verify that the sign-in promo is not shown.
         onView(withId(R.id.header_title)).perform(click());
@@ -139,6 +151,41 @@
     @Test
     @MediumTest
     @Feature({"FeedNewTabPage"})
+    public void testSignInPromo_DismissBySwipe() {
+        boolean dismissed = ChromePreferenceManager.getInstance().readBoolean(
+                ChromePreferenceManager.NTP_SIGNIN_PROMO_DISMISSED, false);
+        if (dismissed) {
+            ChromePreferenceManager.getInstance().writeBoolean(
+                    ChromePreferenceManager.NTP_SIGNIN_PROMO_DISMISSED, false);
+        }
+
+        // Verify that sign-in promo is displayed initially.
+        onView(instanceOf(RecyclerView.class))
+                .perform(RecyclerViewActions.scrollToPosition(SIGNIN_PROMO_POSITION));
+        onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
+
+        // Swipe away the sign-in promo.
+        onView(instanceOf(RecyclerView.class))
+                .perform(RecyclerViewActions.actionOnItemAtPosition(
+                        SIGNIN_PROMO_POSITION, swipeLeft()));
+
+        ViewGroup view = (ViewGroup) mNtp.getStream().getView();
+        waitForView(view, withId(R.id.signin_promo_view_container), VIEW_NULL);
+        waitForView(view, allOf(withId(R.id.header_title), isDisplayed()));
+
+        // Verify that sign-in promo is gone, but new tab page layout and header are displayed.
+        onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
+        onView(withId(R.id.header_title)).check(matches(isDisplayed()));
+        onView(withId(R.id.ntp_content)).check(matches(isDisplayed()));
+
+        // Reset state.
+        ChromePreferenceManager.getInstance().writeBoolean(
+                ChromePreferenceManager.NTP_SIGNIN_PROMO_DISMISSED, dismissed);
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"FeedNewTabPage"})
     public void testArticleSectionHeader() throws Exception {
         // Disable the sign-in promo so the header is visible above the fold.
         SignInPromo.setDisablePromoForTests(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index eca8a37..0ae589ed 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -41,6 +41,7 @@
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.omnibox.status.StatusViewCoordinator;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController.OnSuggestionsReceivedListener;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsList;
@@ -673,12 +674,14 @@
             final LocationBarLayout locationBar =
                     (LocationBarLayout) mActivityTestRule.getActivity().findViewById(
                             R.id.location_bar);
-            boolean securityIcon = locationBar.isSecurityButtonShown();
+            StatusViewCoordinator statusViewCoordinator =
+                    locationBar.getStatusViewCoordinatorForTesting();
+            boolean securityIcon = statusViewCoordinator.isSecurityButtonShown();
             if (mActivityTestRule.getActivity().isTablet()) {
                 Assert.assertTrue("Omnibox should have a Security icon", securityIcon);
                 Assert.assertTrue(securityButton.isShown());
                 Assert.assertEquals(
-                        R.drawable.omnibox_info, locationBar.getSecurityIconResourceId());
+                        R.drawable.omnibox_info, statusViewCoordinator.getSecurityIconResourceId());
             } else {
                 Assert.assertFalse("Omnibox should not have a Security icon", securityIcon);
                 Assert.assertFalse(securityButton.isShown());
@@ -720,13 +723,15 @@
             final LocationBarLayout locationBar =
                     (LocationBarLayout) mActivityTestRule.getActivity().findViewById(
                             R.id.location_bar);
-            boolean securityIcon = locationBar.isSecurityButtonShown();
+            StatusViewCoordinator statusViewCoordinator =
+                    locationBar.getStatusViewCoordinatorForTesting();
+            boolean securityIcon = statusViewCoordinator.isSecurityButtonShown();
             Assert.assertTrue("Omnibox should have a Security icon", securityIcon);
             Assert.assertEquals("security_button with wrong resource-id", R.id.security_button,
                     securityButton.getId());
             Assert.assertTrue(securityButton.isShown());
-            Assert.assertEquals(
-                    R.drawable.omnibox_https_valid, locationBar.getSecurityIconResourceId());
+            Assert.assertEquals(R.drawable.omnibox_https_valid,
+                    statusViewCoordinator.getSecurityIconResourceId());
         } finally {
             httpsTestServer.stopAndDestroyServer();
         }
@@ -769,7 +774,8 @@
             ImageButton securityButton = (ImageButton) mActivityTestRule.getActivity().findViewById(
                     R.id.security_button);
 
-            boolean securityIcon = locationBarLayout.isSecurityButtonShown();
+            boolean securityIcon =
+                    locationBarLayout.getStatusViewCoordinatorForTesting().isSecurityButtonShown();
             Assert.assertTrue("Omnibox should have a Security icon", securityIcon);
             Assert.assertEquals("security_button with wrong resource-id", R.id.security_button,
                     securityButton.getId());
diff --git a/chrome/app/framework.order b/chrome/app/framework.order
index 4f8a717..ecf1d08 100644
--- a/chrome/app/framework.order
+++ b/chrome/app/framework.order
@@ -21,8 +21,5 @@
 # Entry point from the app mode loader.
 _ChromeAppModeStart_v4
 
-# Entry point for the keychain reauthorization stub.
-_KeychainReauthorizeIfNeededAtUpdate
-
 # _ChromeMain must be listed last.  That's the whole point of this file.
 _ChromeMain
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 78e662a..e3919ef 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -634,8 +634,6 @@
     "mac/exception_processor.mm",
     "mac/install_from_dmg.h",
     "mac/install_from_dmg.mm",
-    "mac/keychain_reauthorize.h",
-    "mac/keychain_reauthorize.mm",
     "mac/keystone_glue.h",
     "mac/keystone_glue.mm",
     "mac/keystone_registration.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 97eacf7..cdb73d5 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2958,10 +2958,6 @@
      flag_descriptions::kUseSurfaceLayerForVideoName,
      flag_descriptions::kUseSurfaceLayerForVideoDescription, kOsAll,
      FEATURE_VALUE_TYPE(media::kUseSurfaceLayerForVideo)},
-    {"enable-surfaces-for-videos-ms",
-     flag_descriptions::kUseSurfaceLayerForVideoMSName,
-     flag_descriptions::kUseSurfaceLayerForVideoMSDescription, kOsAll,
-     FEATURE_VALUE_TYPE(media::kUseSurfaceLayerForVideoMS)},
 #if defined(OS_CHROMEOS)
     {"quick-unlock-pin", flag_descriptions::kQuickUnlockPinName,
      flag_descriptions::kQuickUnlockPinDescription, kOsCrOS,
diff --git a/chrome/browser/cached_image_fetcher/cached_image_fetcher_service_factory.cc b/chrome/browser/cached_image_fetcher/cached_image_fetcher_service_factory.cc
index d2d2027a..acba3a0 100644
--- a/chrome/browser/cached_image_fetcher/cached_image_fetcher_service_factory.cc
+++ b/chrome/browser/cached_image_fetcher/cached_image_fetcher_service_factory.cc
@@ -14,10 +14,10 @@
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/suggestions/image_decoder_impl.h"
+#include "components/image_fetcher/core/cache/image_cache.h"
+#include "components/image_fetcher/core/cache/image_data_store_disk.h"
+#include "components/image_fetcher/core/cache/image_metadata_store_leveldb.h"
 #include "components/image_fetcher/core/cached_image_fetcher_service.h"
-#include "components/image_fetcher/core/storage/image_cache.h"
-#include "components/image_fetcher/core/storage/image_data_store_disk.h"
-#include "components/image_fetcher/core/storage/image_metadata_store_leveldb.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index 61163c8..3b588929 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -24,7 +24,6 @@
 #import "chrome/browser/chrome_browser_application_mac.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/mac/install_from_dmg.h"
-#include "chrome/browser/mac/keychain_reauthorize.h"
 #import "chrome/browser/mac/keystone_glue.h"
 #include "chrome/browser/mac/mac_startup_profiler.h"
 #include "chrome/browser/ui/cocoa/main_menu_builder.h"
@@ -135,17 +134,6 @@
                         l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), false);
   [app_controller mainMenuCreated];
 
-  // Do Keychain reauthorization. This gets two chances to run. If the first
-  // try doesn't complete successfully (crashes or is interrupted for any
-  // reason), there will be a second chance. Once this step completes
-  // successfully, it should never have to run again.
-  NSString* const keychain_reauthorize_pref =
-      @"KeychainReauthorizeInAppSpring2017";
-  const int kKeychainReauthorizeMaxTries = 2;
-
-  chrome::KeychainReauthorizeIfNeeded(keychain_reauthorize_pref,
-                                      kKeychainReauthorizeMaxTries);
-
   // Initialize the OSCrypt.
   PrefService* local_state = g_browser_process->local_state();
   DCHECK(local_state);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 35233fbc..1b98863 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -100,6 +100,7 @@
     "//chromeos/services/multidevice_setup/public/cpp:android_sms_app_helper_delegate",
     "//chromeos/services/multidevice_setup/public/cpp:android_sms_pairing_state_tracker",
     "//chromeos/services/multidevice_setup/public/cpp:auth_token_validator",
+    "//chromeos/services/multidevice_setup/public/cpp:oobe_completion_tracker",
     "//chromeos/services/multidevice_setup/public/cpp:prefs",
     "//chromeos/services/secure_channel/public/cpp/client",
     "//components/arc",
@@ -1361,6 +1362,8 @@
     "multidevice_setup/auth_token_validator_impl.h",
     "multidevice_setup/multidevice_setup_client_factory.cc",
     "multidevice_setup/multidevice_setup_client_factory.h",
+    "multidevice_setup/oobe_completion_tracker_factory.cc",
+    "multidevice_setup/oobe_completion_tracker_factory.h",
     "net/cert_verify_proc_chromeos.cc",
     "net/cert_verify_proc_chromeos.h",
     "net/client_cert_filter_chromeos.cc",
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index acb7ca39..777dfc29 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -32,6 +32,7 @@
 #include "chrome/browser/speech/tts_controller.h"
 #include "chrome/browser/speech/tts_platform.h"
 #include "chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_util.h"
+#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -78,6 +79,7 @@
 
   void TearDownOnMainThread() override {
     AccessibilityManager::SetBrailleControllerForTest(nullptr);
+    AutomationManagerAura::GetInstance()->Disable();
   }
 
   void SendKeyPress(ui::KeyboardCode key) {
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index ae877463..5ae6107 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -44,6 +44,7 @@
 namespace {
 constexpr char kLockDisplay[] = "lock";
 constexpr char kExternalBinaryAuth[] = "external_binary_auth";
+constexpr char kExternalBinaryEnrollment[] = "external_binary_enrollment";
 constexpr char kWebCameraDeviceContext[] = "WebCamera: WebCamera";
 constexpr base::TimeDelta kExternalBinaryAuthTimeout =
     base::TimeDelta::FromSeconds(2);
@@ -236,7 +237,7 @@
     const AccountId& account_id,
     AuthenticateUserWithExternalBinaryCallback callback) {
   authenticate_with_external_binary_callback_ = std::move(callback);
-  external_binary_auth_timer_.Start(
+  external_binary_timer_.Start(
       FROM_HERE, kExternalBinaryAuthTimeout,
       base::BindOnce(&ViewsScreenLocker::OnExternalBinaryAuthTimeout,
                      weak_factory_.GetWeakPtr()));
@@ -244,6 +245,17 @@
       &StartGraphIfNeeded, media_analytics_client_, kExternalBinaryAuth));
 }
 
+void ViewsScreenLocker::HandleEnrollUserWithExternalBinary(
+    EnrollUserWithExternalBinaryCallback callback) {
+  enroll_user_with_external_binary_callback_ = std::move(callback);
+  external_binary_timer_.Start(
+      FROM_HERE, kExternalBinaryAuthTimeout,
+      base::BindOnce(&ViewsScreenLocker::OnExternalBinaryEnrollmentTimeout,
+                     weak_factory_.GetWeakPtr()));
+  media_analytics_client_->GetState(base::BindOnce(
+      &StartGraphIfNeeded, media_analytics_client_, kExternalBinaryEnrollment));
+}
+
 void ViewsScreenLocker::HandleAuthenticateUserWithEasyUnlock(
     const AccountId& account_id) {
   user_selection_screen_->AttemptEasyUnlock(account_id);
@@ -338,21 +350,29 @@
 
 void ViewsScreenLocker::OnDetectionSignal(
     const mri::MediaPerception& media_perception) {
-  if (!authenticate_with_external_binary_callback_)
-    return;
+  if (authenticate_with_external_binary_callback_) {
+    const mri::FramePerception& frame = media_perception.frame_perception(0);
+    if (frame.frame_id() != 1)
+      return;
 
-  const mri::FramePerception& frame = media_perception.frame_perception(0);
-  if (frame.frame_id() != 1)
-    return;
+    mri::State new_state;
+    new_state.set_status(mri::State::SUSPENDED);
+    media_analytics_client_->SetState(new_state, base::DoNothing());
 
-  mri::State new_state;
-  new_state.set_status(mri::State::SUSPENDED);
-  media_analytics_client_->SetState(new_state, base::DoNothing());
+    external_binary_timer_.Stop();
+    std::move(authenticate_with_external_binary_callback_)
+        .Run(true /*auth_success*/);
+    ScreenLocker::Hide();
+  } else if (enroll_user_with_external_binary_callback_) {
+    const mri::FramePerception& frame = media_perception.frame_perception(0);
 
-  external_binary_auth_timer_.Stop();
-  std::move(authenticate_with_external_binary_callback_)
-      .Run(true /*auth_success*/);
-  ScreenLocker::Hide();
+    external_binary_timer_.Stop();
+    mri::State new_state;
+    new_state.set_status(mri::State::SUSPENDED);
+    media_analytics_client_->SetState(new_state, base::DoNothing());
+    std::move(enroll_user_with_external_binary_callback_)
+        .Run(frame.frame_id() == 1 /*enrollment_success*/);
+  }
 }
 
 void ViewsScreenLocker::UpdatePinKeyboardState(const AccountId& account_id) {
@@ -388,4 +408,12 @@
   media_analytics_client_->SetState(new_state, base::DoNothing());
 }
 
+void ViewsScreenLocker::OnExternalBinaryEnrollmentTimeout() {
+  std::move(enroll_user_with_external_binary_callback_)
+      .Run(false /*auth_success*/);
+  mri::State new_state;
+  new_state.set_status(mri::State::SUSPENDED);
+  media_analytics_client_->SetState(new_state, base::DoNothing());
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.h b/chrome/browser/chromeos/login/lock/views_screen_locker.h
index 26a063e3..bb6ff2f 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.h
@@ -61,6 +61,8 @@
   void HandleAuthenticateUserWithExternalBinary(
       const AccountId& account_id,
       AuthenticateUserWithExternalBinaryCallback callback) override;
+  void HandleEnrollUserWithExternalBinary(
+      EnrollUserWithExternalBinaryCallback) override;
   void HandleAuthenticateUserWithEasyUnlock(
       const AccountId& account_id) override;
   void HandleHardlockPod(const AccountId& account_id) override;
@@ -91,6 +93,7 @@
   void OnAllowedInputMethodsChanged();
   void OnPinCanAuthenticate(const AccountId& account_id, bool can_authenticate);
   void OnExternalBinaryAuthTimeout();
+  void OnExternalBinaryEnrollmentTimeout();
 
   std::unique_ptr<UserBoardViewMojo> user_board_view_mojo_;
   std::unique_ptr<UserSelectionScreen> user_selection_screen_;
@@ -114,6 +117,9 @@
   AuthenticateUserWithExternalBinaryCallback
       authenticate_with_external_binary_callback_;
 
+  EnrollUserWithExternalBinaryCallback
+      enroll_user_with_external_binary_callback_;
+
   // Callback registered as a lock screen apps focus handler - it should be
   // called to hand focus over to lock screen apps.
   LockScreenAppFocusCallback lock_screen_app_focus_handler_;
@@ -123,9 +129,9 @@
 
   chromeos::MediaAnalyticsClient* media_analytics_client_;
 
-  // Timer for external binary auth attempt. Allows repeated auth attempts up to
-  // a specific timeout.
-  base::OneShotTimer external_binary_auth_timer_;
+  // Timer for external binary auth/enrollment attempt. Allows repeated attempts
+  // up to a specific timeout.
+  base::OneShotTimer external_binary_timer_;
 
   ScopedObserver<chromeos::MediaAnalyticsClient, ViewsScreenLocker>
       scoped_observer_{this};
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
index 3f345de..b9952210 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
 
 #include "base/feature_list.h"
-#include "base/sys_info.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
@@ -40,19 +39,7 @@
          quick_unlock_whitelist->end();
 }
 
-std::string GetBoardName() {
-  const std::vector<std::string> board =
-      base::SplitString(base::SysInfo::GetLsbReleaseBoard(), "-",
-                        base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-  return board[0];
-}
-
 bool IsFingerprintDisabledByPolicy(const PrefService* pref_service) {
-  // Always allow fingerprint on nocturne. This is a temporary measure to allow
-  // dogfooding.
-  if (GetBoardName() == "nocturne")
-    return false;
-
   const bool enabled =
       HasPolicyValue(pref_service, kQuickUnlockWhitelistOptionAll) ||
       HasPolicyValue(pref_service, kQuickUnlockWhitelistOptionFingerprint);
diff --git a/chrome/browser/chromeos/login/screens/multidevice_setup_screen.cc b/chrome/browser/chromeos/login/screens/multidevice_setup_screen.cc
index aef7df9..f6b3d77 100644
--- a/chrome/browser/chromeos/login/screens/multidevice_setup_screen.cc
+++ b/chrome/browser/chromeos/login/screens/multidevice_setup_screen.cc
@@ -8,9 +8,11 @@
 #include "base/logging.h"
 #include "chrome/browser/chromeos/login/screens/multidevice_setup_screen_view.h"
 #include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
+#include "chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chromeos/chromeos_features.h"
 #include "chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
+#include "chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
 
 namespace chromeos {
 
@@ -67,6 +69,14 @@
   }
 
   view_->Show();
+
+  // Record that user was presented with setup flow to prevent spam
+  // notifications from suggesting setup in the future.
+  multidevice_setup::OobeCompletionTracker* oobe_completion_tracker =
+      multidevice_setup::OobeCompletionTrackerFactory::GetForProfile(
+          ProfileManager::GetActiveUserProfile());
+  DCHECK(oobe_completion_tracker);
+  oobe_completion_tracker->MarkOobeShown();
 }
 
 void MultiDeviceSetupScreen::Hide() {
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
index 95f6fb7d..c661f18 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
@@ -380,6 +380,12 @@
   std::move(callback).Run(false);
 }
 
+void LoginDisplayHostMojo::HandleEnrollUserWithExternalBinary(
+    EnrollUserWithExternalBinaryCallback callback) {
+  // Enroll in external binary auth system is not supported for login.
+  std::move(callback).Run(false);
+}
+
 void LoginDisplayHostMojo::HandleAuthenticateUserWithEasyUnlock(
     const AccountId& account_id) {
   user_selection_screen_->AttemptEasyUnlock(account_id);
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.h b/chrome/browser/chromeos/login/ui/login_display_host_mojo.h
index f07bea84..05ed24fd 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.h
+++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.h
@@ -106,6 +106,8 @@
   void HandleAuthenticateUserWithExternalBinary(
       const AccountId& account_id,
       AuthenticateUserWithExternalBinaryCallback callback) override;
+  void HandleEnrollUserWithExternalBinary(
+      EnrollUserWithExternalBinaryCallback callback) override;
   void HandleAuthenticateUserWithEasyUnlock(
       const AccountId& account_id) override;
   void HandleHardlockPod(const AccountId& account_id) override;
diff --git a/chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.cc b/chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.cc
new file mode 100644
index 0000000..d9cc8a0
--- /dev/null
+++ b/chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.cc
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.h"
+
+#include "base/macros.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/browser_context.h"
+
+namespace chromeos {
+
+namespace multidevice_setup {
+
+// static
+OobeCompletionTracker* OobeCompletionTrackerFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<OobeCompletionTracker*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+OobeCompletionTrackerFactory* OobeCompletionTrackerFactory::GetInstance() {
+  return base::Singleton<OobeCompletionTrackerFactory>::get();
+}
+
+OobeCompletionTrackerFactory::OobeCompletionTrackerFactory()
+    : BrowserContextKeyedServiceFactory(
+          "OobeCompletionTrackerFactory",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+OobeCompletionTrackerFactory::~OobeCompletionTrackerFactory() = default;
+
+KeyedService* OobeCompletionTrackerFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new OobeCompletionTracker();
+}
+
+}  // namespace multidevice_setup
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.h b/chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.h
new file mode 100644
index 0000000..1541451
--- /dev/null
+++ b/chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.h
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_OOBE_COMPLETION_TRACKER_FACTORY_H_
+#define CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_OOBE_COMPLETION_TRACKER_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class KeyedService;
+class Profile;
+
+namespace chromeos {
+
+namespace multidevice_setup {
+
+class OobeCompletionTracker;
+
+// Owns OobeCompletionTracker instances and associates them with Profiles.
+class OobeCompletionTrackerFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static OobeCompletionTracker* GetForProfile(Profile* profile);
+
+  static OobeCompletionTrackerFactory* GetInstance();
+
+ private:
+  friend struct base::DefaultSingletonTraits<OobeCompletionTrackerFactory>;
+
+  OobeCompletionTrackerFactory();
+  ~OobeCompletionTrackerFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(OobeCompletionTrackerFactory);
+};
+
+}  // namespace multidevice_setup
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_OOBE_COMPLETION_TRACKER_FACTORY_H_
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 7d0505a1..1ca84e1 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -246,6 +246,11 @@
   return chromeos::InstallAttributes::Get()->IsEnterpriseManaged();
 }
 
+bool BrowserPolicyConnectorChromeOS::HasMachineLevelPolicies() {
+  NOTREACHED() << "This method is only defined for desktop Chrome";
+  return false;
+}
+
 bool BrowserPolicyConnectorChromeOS::IsCloudManaged() const {
   return chromeos::InstallAttributes::Get()->IsCloudManaged();
 }
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
index f899f6c..b1206362 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
@@ -67,6 +67,8 @@
   // Checks whether this devices is under any kind of enterprise management.
   bool IsEnterpriseManaged() const override;
 
+  bool HasMachineLevelPolicies() override;
+
   // Shutdown() is called from BrowserProcessImpl::StartTearDown() but |this|
   // observes some objects that get destroyed earlier. PreShutdown() is called
   // from ChromeBrowserMainPartsChromeos::PostMainMessageLoopRun(), allowing the
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 80d05dc2..79991c8 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -139,6 +139,7 @@
 #include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/icu/source/common/unicode/locid.h"
+#include "ui/aura/test/mus/change_completion_waiter.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
@@ -213,6 +214,25 @@
 const char kPublicSessionLocale[] = "de";
 const char kPublicSessionInputMethodIDTemplate[] = "_comp_ime_%sxkb:de:neo:ger";
 
+bool IsLogoutConfirmationDialogShowing() {
+  // Wait for any browser window close mojo messages to propagate to ash.
+  aura::test::WaitForAllChangesToComplete();
+
+  // TODO(mash): Add mojo test API for this.
+  return !!ash::Shell::Get()
+               ->logout_confirmation_controller()
+               ->dialog_for_testing();
+}
+
+void CloseLogoutConfirmationDialog() {
+  // TODO(mash): Add mojo test API for this.
+  ash::LogoutConfirmationDialog* dialog =
+      ash::Shell::Get()->logout_confirmation_controller()->dialog_for_testing();
+  ASSERT_TRUE(dialog);
+  dialog->GetWidget()->Close();
+  base::RunLoop().RunUntilIdle();
+}
+
 // Helper that serves extension update manifests to Chrome.
 class TestingUpdateManifestProvider
     : public base::RefCountedThreadSafe<TestingUpdateManifestProvider> {
@@ -1498,10 +1518,7 @@
   app_window_registry->AddObserver(this);
 
   // Verify that the logout confirmation dialog is not showing.
-  ash::LogoutConfirmationController* logout_confirmation_controller =
-      ash::Shell::Get()->logout_confirmation_controller();
-  ASSERT_TRUE(logout_confirmation_controller);
-  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
+  EXPECT_FALSE(IsLogoutConfirmationDialogShowing());
 
   // Remove policy that allows only explicitly whitelisted apps to be installed
   // in a public session.
@@ -1552,7 +1569,7 @@
 
   // Verify that the logout confirmation dialog is not showing because an app
   // window is still open.
-  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
+  EXPECT_FALSE(IsLogoutConfirmationDialogShowing());
 
   // Open a browser window.
   Browser* first_browser = CreateBrowser(profile);
@@ -1567,7 +1584,7 @@
 
   // Verify that the logout confirmation dialog is not showing because a browser
   // window is still open.
-  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
+  EXPECT_FALSE(IsLogoutConfirmationDialogShowing());
 
   // Open a second browser window.
   Browser* second_browser = CreateBrowser(profile);
@@ -1585,7 +1602,7 @@
 
   // Verify that the logout confirmation dialog is not showing because a browser
   // window is still open.
-  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
+  EXPECT_FALSE(IsLogoutConfirmationDialogShowing());
 
   // Close the second browser window.
   browser_window = second_browser->window();
@@ -1598,17 +1615,13 @@
   EXPECT_TRUE(browser_list->empty());
 
   // Verify that the logout confirmation dialog is showing.
-  ash::LogoutConfirmationDialog* dialog =
-      logout_confirmation_controller->dialog_for_testing();
-  ASSERT_TRUE(dialog);
+  EXPECT_TRUE(IsLogoutConfirmationDialogShowing());
 
   // Deny the logout.
-  dialog->GetWidget()->Close();
-  dialog = NULL;
-  base::RunLoop().RunUntilIdle();
+  ASSERT_NO_FATAL_FAILURE(CloseLogoutConfirmationDialog());
 
   // Verify that the logout confirmation dialog is no longer showing.
-  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
+  EXPECT_FALSE(IsLogoutConfirmationDialogShowing());
 
   // Open a browser window.
   browser = CreateBrowser(profile);
@@ -1625,13 +1638,10 @@
   EXPECT_TRUE(browser_list->empty());
 
   // Verify that the logout confirmation dialog is showing again.
-  dialog = logout_confirmation_controller->dialog_for_testing();
-  ASSERT_TRUE(dialog);
+  EXPECT_TRUE(IsLogoutConfirmationDialogShowing());
 
   // Deny the logout.
-  dialog->GetWidget()->Close();
-  dialog = NULL;
-  base::RunLoop().RunUntilIdle();
+  ASSERT_NO_FATAL_FAILURE(CloseLogoutConfirmationDialog());
 
   app_window_registry->RemoveObserver(this);
 };
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 6c928ec..4c37bd6 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -226,8 +226,6 @@
     "api/image_writer_private/write_from_file_operation.h",
     "api/image_writer_private/write_from_url_operation.cc",
     "api/image_writer_private/write_from_url_operation.h",
-    "api/inline_install_private/inline_install_private_api.cc",
-    "api/inline_install_private/inline_install_private_api.h",
     "api/instance_id/instance_id_api.cc",
     "api/instance_id/instance_id_api.h",
     "api/language_settings_private/language_settings_private_api.cc",
diff --git a/chrome/browser/extensions/api/inline_install_private/inline_install_private_api.cc b/chrome/browser/extensions/api/inline_install_private/inline_install_private_api.cc
deleted file mode 100644
index f49f337..0000000
--- a/chrome/browser/extensions/api/inline_install_private/inline_install_private_api.cc
+++ /dev/null
@@ -1,142 +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.
-
-#include "chrome/browser/extensions/api/inline_install_private/inline_install_private_api.h"
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "chrome/browser/extensions/webstore_install_with_prompt.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/extensions/api/inline_install_private.h"
-#include "chrome/common/extensions/api/webstore/webstore_api_constants.h"
-#include "components/crx_file/id_util.h"
-#include "content/public/browser/browser_thread.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/view_type_utils.h"
-
-namespace extensions {
-
-namespace {
-
-class Installer : public WebstoreInstallWithPrompt {
- public:
-  Installer(const std::string& id,
-            const GURL& requestor_url,
-            Profile* profile,
-            const Callback& callback);
- protected:
-  friend class base::RefCountedThreadSafe<Installer>;
-  ~Installer() override;
-
-  std::unique_ptr<ExtensionInstallPrompt::Prompt> CreateInstallPrompt()
-      const override;
-
-  void OnManifestParsed() override;
-
-  GURL requestor_url_;
-};
-
-Installer::Installer(const std::string& id,
-                     const GURL& requestor_url,
-                     Profile* profile,
-                     const Callback& callback) :
-    WebstoreInstallWithPrompt(id, profile, callback),
-    requestor_url_(requestor_url) {
-  set_show_post_install_ui(false);
-}
-
-Installer::~Installer() {
-}
-
-std::unique_ptr<ExtensionInstallPrompt::Prompt> Installer::CreateInstallPrompt()
-    const {
-  std::unique_ptr<ExtensionInstallPrompt::Prompt> prompt(
-      new ExtensionInstallPrompt::Prompt(
-          ExtensionInstallPrompt::WEBSTORE_WIDGET_PROMPT));
-  prompt->SetWebstoreData(localized_user_count(),
-                          show_user_count(),
-                          average_rating(),
-                          rating_count());
-  return prompt;
-}
-
-
-void Installer::OnManifestParsed() {
-  if (manifest() == nullptr) {
-    CompleteInstall(webstore_install::INVALID_MANIFEST, std::string());
-    return;
-  }
-
-  Manifest parsed_manifest(Manifest::INTERNAL,
-                           base::WrapUnique(manifest()->DeepCopy()));
-
-  std::string manifest_error;
-  std::vector<InstallWarning> warnings;
-
-  if (!parsed_manifest.is_platform_app()) {
-    CompleteInstall(webstore_install::NOT_PERMITTED, std::string());
-    return;
-  }
-
-  ProceedWithInstallPrompt();
-}
-
-
-}  // namespace
-
-InlineInstallPrivateInstallFunction::
-    InlineInstallPrivateInstallFunction() {
-}
-
-InlineInstallPrivateInstallFunction::
-    ~InlineInstallPrivateInstallFunction() {
-}
-
-ExtensionFunction::ResponseAction
-InlineInstallPrivateInstallFunction::Run() {
-  typedef api::inline_install_private::Install::Params Params;
-  std::unique_ptr<Params> params(Params::Create(*args_));
-
-  if (!user_gesture())
-    return RespondNow(CreateResponse("Must be called with a user gesture",
-                                     webstore_install::NOT_PERMITTED));
-
-  content::WebContents* web_contents = GetSenderWebContents();
-  if (!web_contents || GetViewType(web_contents) != VIEW_TYPE_APP_WINDOW) {
-    return RespondNow(CreateResponse("Must be called from a foreground page",
-                                     webstore_install::NOT_PERMITTED));
-  }
-
-  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
-  if (registry->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING))
-    return RespondNow(CreateResponse("Already installed",
-                                     webstore_install::OTHER_ERROR));
-
-  scoped_refptr<Installer> installer = new Installer(
-      params->id, source_url(), Profile::FromBrowserContext(browser_context()),
-      base::Bind(&InlineInstallPrivateInstallFunction::InstallerCallback,
-                 this));
-  installer->BeginInstall();
-
-  return RespondLater();
-}
-
-void InlineInstallPrivateInstallFunction::InstallerCallback(
-    bool success,
-    const std::string& error,
-    webstore_install::Result result) {
-
-  Respond(CreateResponse(success ? std::string() : error, result));
-}
-
-ExtensionFunction::ResponseValue
-InlineInstallPrivateInstallFunction::CreateResponse(
-    const std::string& error, webstore_install::Result result) {
-  return ArgumentList(api::inline_install_private::Install::Results::Create(
-      error,
-      api::webstore::kInstallResultCodes[result]));
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/inline_install_private/inline_install_private_api.h b/chrome/browser/extensions/api/inline_install_private/inline_install_private_api.h
deleted file mode 100644
index c08091c9..0000000
--- a/chrome/browser/extensions/api/inline_install_private/inline_install_private_api.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_INLINE_INSTALL_PRIVATE_INLINE_INSTALL_PRIVATE_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_INLINE_INSTALL_PRIVATE_INLINE_INSTALL_PRIVATE_API_H_
-
-#include <memory>
-
-#include "chrome/common/extensions/webstore_install_result.h"
-#include "extensions/browser/extension_function.h"
-
-namespace extensions {
-
-class InlineInstallPrivateInstallFunction
-    : public UIThreadExtensionFunction {
- public:
-  InlineInstallPrivateInstallFunction();
-
- protected:
-  ~InlineInstallPrivateInstallFunction() override;
-
-  ResponseAction Run() override;
-
- private:
-  void InstallerCallback(bool success,
-                         const std::string& error,
-                         webstore_install::Result result);
-
-  // Helper to create a response to be returned either synchronously or in
-  // InstallerCallback.
-  ResponseValue CreateResponse(const std::string& error,
-                               webstore_install::Result result);
-
-  DECLARE_EXTENSION_FUNCTION("inlineInstallPrivate.install",
-                             INLINE_INSTALL_PRIVATE_INSTALL);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_INLINE_INSTALL_PRIVATE_INLINE_INSTALL_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/inline_install_private/inline_install_private_apitest.cc b/chrome/browser/extensions/api/inline_install_private/inline_install_private_apitest.cc
deleted file mode 100644
index eef8861..0000000
--- a/chrome/browser/extensions/api/inline_install_private/inline_install_private_apitest.cc
+++ /dev/null
@@ -1,75 +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.
-
-#include "base/command_line.h"
-#include "chrome/browser/extensions/api/inline_install_private/inline_install_private_api.h"
-#include "chrome/browser/extensions/extension_install_prompt.h"
-#include "chrome/browser/extensions/webstore_installer_test.h"
-#include "extensions/test/extension_test_message_listener.h"
-
-namespace extensions {
-
-class InlineInstallPrivateApiTestBase : public WebstoreInstallerTest {
- public:
-  InlineInstallPrivateApiTestBase(const std::string& basedir,
-                                  const std::string& extension_file) :
-      WebstoreInstallerTest("cws.com",
-                            basedir,
-                            extension_file,
-                            "test1.com",
-                            "test2.com") {
-  }
-
-  void Run(const std::string& testName) {
-    AutoAcceptInstall();
-    base::FilePath test_driver_path = test_data_dir_.AppendASCII(
-        "api_test/inline_install_private/test_driver");
-
-    ExtensionTestMessageListener ready_listener("ready", true);
-    ExtensionTestMessageListener success_listener("success", false);
-    LoadExtension(test_driver_path);
-    EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
-    ready_listener.Reply(testName);
-    ASSERT_TRUE(success_listener.WaitUntilSatisfied());
-  }
-};
-
-class InlineInstallPrivateApiTestApp :
-      public InlineInstallPrivateApiTestBase {
- public:
-  InlineInstallPrivateApiTestApp() :
-      InlineInstallPrivateApiTestBase(
-          "extensions/api_test/inline_install_private",
-          "app.crx") {}
-};
-
-IN_PROC_BROWSER_TEST_F(InlineInstallPrivateApiTestApp, SuccessfulInstall) {
-  ExtensionFunction::ScopedUserGestureForTests gesture;
-  Run("successfulInstall");
-}
-
-IN_PROC_BROWSER_TEST_F(InlineInstallPrivateApiTestApp, BackgroundInstall) {
-  ExtensionFunction::ScopedUserGestureForTests gesture;
-  Run("backgroundInstall");
-}
-
-IN_PROC_BROWSER_TEST_F(InlineInstallPrivateApiTestApp, NoGesture) {
-  Run("noGesture");
-}
-
-class InlineInstallPrivateApiTestExtension :
-      public InlineInstallPrivateApiTestBase {
- public:
-  InlineInstallPrivateApiTestExtension() :
-      InlineInstallPrivateApiTestBase(
-          "extensions/api_test/webstore_inline_install",
-          "extension.crx") {}
-};
-
-IN_PROC_BROWSER_TEST_F(InlineInstallPrivateApiTestExtension, OnlyApps) {
-  ExtensionFunction::ScopedUserGestureForTests gesture;
-  Run("onlyApps");
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
index 8fc0c4b..ab214b9 100644
--- a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
+++ b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
@@ -167,6 +167,26 @@
   EXPECT_TRUE(data_provider2.AllWriteDataConsumed());
 }
 
+TEST_F(TCPSocketUnitTest, SocketConnectDisconnectRace) {
+  // Regression test for https://crbug.com/882585, disconnect while connect
+  // is pending.
+  net::IPEndPoint ip_end_point(net::IPAddress::IPv4Localhost(), 1234);
+  net::StaticSocketDataProvider data_provider((base::span<net::MockRead>()),
+                                              base::span<net::MockWrite>());
+  data_provider.set_connect_data(
+      net::MockConnect(net::SYNCHRONOUS, net::ERR_FAILED, ip_end_point));
+  mock_client_socket_factory()->AddSocketDataProvider(&data_provider);
+  std::unique_ptr<TCPSocket> socket = CreateSocket();
+
+  net::AddressList address(ip_end_point);
+  net::TestCompletionCallback callback;
+  socket->Connect(address, callback.callback());
+  socket->Disconnect(false /* socket_destroying */);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(callback.have_result());
+}
+
 TEST_F(TCPSocketUnitTest, DestroyWhileReadPending) {
   const net::MockRead kReads[] = {
       net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)};
@@ -636,6 +656,21 @@
   EXPECT_EQ(client_addr, accept_client_addr);
 }
 
+TEST_F(TCPSocketServerTest, ListenDisconnectRace) {
+  // Create a server socket.
+  std::unique_ptr<TCPSocket> socket = CreateSocket();
+  net::TestCompletionCallback callback;
+  bool callback_ran = false;
+  socket->Listen(
+      "127.0.0.1", 0 /* port */, 1 /* backlog */,
+      base::BindLambdaForTesting([&](int result, const std::string& error_msg) {
+        callback_ran = true;
+      }));
+  socket->Disconnect(false /* socket_destroying */);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(callback_ran);
+}
+
 TEST_F(TCPSocketServerTest, ReadAndWrite) {
   // Create a server socket.
   std::unique_ptr<TCPSocket> socket = CreateSocket();
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index aa043ca..77bfc78 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1194,11 +1194,6 @@
 const char kUseSurfaceLayerForVideoDescription[] =
     "Enable compositing onto a Surface instead of a VideoLayer "
     "for videos.";
-const char kUseSurfaceLayerForVideoMSName[] =
-    "Enable the use of SurfaceLayer objects for media stream videos.";
-const char kUseSurfaceLayerForVideoMSDescription[] =
-    "Enable compositing onto a Surface instead of a VideoLayer "
-    "for media stream videos.";
 
 const char kNewUsbBackendName[] = "Enable new USB backend";
 const char kNewUsbBackendDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 7f47a2e..4cba0a6 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -739,9 +739,6 @@
 extern const char kUseSurfaceLayerForVideoName[];
 extern const char kUseSurfaceLayerForVideoDescription[];
 
-extern const char kUseSurfaceLayerForVideoMSName[];
-extern const char kUseSurfaceLayerForVideoMSDescription[];
-
 extern const char kNewUsbBackendName[];
 extern const char kNewUsbBackendDescription[];
 
diff --git a/chrome/browser/mac/keychain_reauthorize.h b/chrome/browser/mac/keychain_reauthorize.h
deleted file mode 100644
index d94488f..0000000
--- a/chrome/browser/mac/keychain_reauthorize.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MAC_KEYCHAIN_REAUTHORIZE_H_
-#define CHROME_BROWSER_MAC_KEYCHAIN_REAUTHORIZE_H_
-
-#ifdef __OBJC__
-@class NSString;
-#else
-class NSString;
-#endif
-
-namespace chrome {
-
-extern "C" {
-
-// Reauthorizes the keychain entry, but only if it's determined that it's
-// necessary. pref_key is looked up in the system's standard user defaults
-// (preferences) and it is associated with both the number of previous attempts,
-// and whether a previous attempt succeeded. Only if a previous attempt did not
-// succeed, and the number of previous tries is less than max_tries, is
-// reauthorization attempted. Before the attempt, the preference is
-// incremented, allowing a finite number of incomplete attempts at performing
-// the operation.
-
-// The system's standard user defaults for the application are used
-// (~/Library/Preferences/com.google.Chrome.plist,
-// com.google.Chrome.canary.plist, etc.) instead of Chrome preferences because
-// Keychain access is tied more closely to the bundle identifier and signed
-// product than it is to any specific profile (--user-data-dir).
-void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries);
-
-// A wrapper to call KeychainReauthorizeIfNeeded under a local autorelease pool.
-// This is used by the keychain_reauthorization stub executable, which is run at
-// update time or at browser launch. The name cannot be changed to indicate that
-// it is not only run at update because the stub is already built and signed.
-__attribute__((visibility("default"))) void KeychainReauthorizeIfNeededAtUpdate(
-    NSString* pref_key,
-    int max_tries);
-
-}  // extern "C"
-
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_MAC_KEYCHAIN_REAUTHORIZE_H_
diff --git a/chrome/browser/mac/keychain_reauthorize.mm b/chrome/browser/mac/keychain_reauthorize.mm
deleted file mode 100644
index aa955b1f..0000000
--- a/chrome/browser/mac/keychain_reauthorize.mm
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/mac/keychain_reauthorize.h"
-
-#import <Foundation/Foundation.h>
-#include <Security/Security.h>
-
-#include <crt_externs.h>
-#include <errno.h>
-#include <spawn.h>
-#include <string.h>
-
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/mac/bundle_locations.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_logging.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/path_service.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/scoped_generic.h"
-#include "base/strings/sys_string_conversions.h"
-#include "components/os_crypt/keychain_password_mac.h"
-#include "crypto/apple_keychain.h"
-
-namespace chrome {
-
-namespace {
-
-struct VectorScramblerTraits {
-  static std::vector<uint8_t>* InvalidValue() { return nullptr; }
-
-  static void Free(std::vector<uint8_t>* buf) {
-    memset(buf->data(), 0x11, buf->size());
-    delete buf;
-  }
-};
-
-typedef base::ScopedGeneric<std::vector<uint8_t>*, VectorScramblerTraits>
-    ScopedVectorScrambler;
-
-// Reauthorizes the Safe Storage keychain item, which protects the randomly
-// generated password that encrypts the user's saved passwords. This reads out
-// the keychain item, deletes it, and re-adds it to the keychain. This works
-// because the keychain uses an app's designated requirement as the ACL for
-// reading an item. Chrome will be signed with a designated requirement that
-// accepts both the old and new certificates.
-bool KeychainReauthorize() {
-  base::ScopedCFTypeRef<SecKeychainItemRef> storage_item;
-  UInt32 pw_length = 0;
-  void* password_data = nullptr;
-
-  crypto::AppleKeychain keychain;
-  OSStatus error = keychain.FindGenericPassword(
-      strlen(KeychainPassword::service_name), KeychainPassword::service_name,
-      strlen(KeychainPassword::account_name), KeychainPassword::account_name,
-      &pw_length, &password_data, storage_item.InitializeInto());
-
-  base::ScopedCFTypeRef<SecKeychainItemRef> backup_item;
-  std::string backup_service_name =
-      std::string(KeychainPassword::service_name) + ".bak";
-  if (error != noErr) {
-    // If the main entry does not exist, nor does the backup, exit.
-    if (keychain.FindGenericPassword(
-            backup_service_name.size(), backup_service_name.data(),
-            strlen(KeychainPassword::account_name),
-            KeychainPassword::account_name, &pw_length, &password_data,
-            backup_item.InitializeInto()) != noErr) {
-      OSSTATUS_LOG(ERROR, error)
-          << "KeychainReauthorize failed. Cannot retrieve item.";
-      return false;
-    }
-  }
-
-  // At this point, a password was retrieved, either from the main or backup.
-  ScopedVectorScrambler password;
-  password.reset(new std::vector<uint8_t>(
-      static_cast<uint8_t*>(password_data),
-      static_cast<uint8_t*>(password_data) + pw_length));
-  memset(password_data, 0x11, pw_length);
-  keychain.ItemFreeContent(password_data);
-
-  if (backup_item.get() == nullptr) {
-    // If writing the backup fails, still attempt the re-auth.
-    keychain.AddGenericPassword(
-        backup_service_name.size(), backup_service_name.data(),
-        strlen(KeychainPassword::account_name), KeychainPassword::account_name,
-        password.get()->size(), password.get()->data(),
-        backup_item.InitializeInto());
-  }
-
-  if (storage_item) {
-    error = keychain.ItemDelete(storage_item);
-    if (error != noErr) {
-      OSSTATUS_LOG(WARNING, error)
-          << "KeychainReauthorize failed to delete item.";
-    }
-  }
-
-  error = keychain.AddGenericPassword(
-      strlen(KeychainPassword::service_name), KeychainPassword::service_name,
-      strlen(KeychainPassword::account_name), KeychainPassword::account_name,
-      password.get()->size(), password.get()->data(), nullptr);
-
-  if (error != noErr) {
-    OSSTATUS_LOG(ERROR, error) << "Failed to re-add storage password.";
-    return false;
-  }
-
-  if (backup_item.get() == nullptr) {
-    // Attempt to get the backup entry in case one exists. Ignore return value.
-    // This could happen if Chrome crashed after writing the backup entry and
-    // before deleting the main entry.
-    keychain.FindGenericPassword(
-        backup_service_name.size(), backup_service_name.data(),
-        strlen(KeychainPassword::account_name), KeychainPassword::account_name,
-        &pw_length, &password_data, backup_item.InitializeInto());
-  }
-
-  if (backup_item.get()) {
-    error = keychain.ItemDelete(backup_item);
-    if (error != noErr) {
-      OSSTATUS_LOG(WARNING, error) << "Deleting backup entry failed.";
-    }
-  }
-
-  return true;
-}
-
-// This performs the re-reauthorization from the stub executable.
-void KeychainReauthorizeFromStub(NSString* pref_key) {
-  NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults];
-
-  NSString* success_pref_key = [pref_key stringByAppendingString:@"Success"];
-  BOOL success_value = [user_defaults boolForKey:success_pref_key];
-  if (success_value)
-    return;
-
-  bool success = KeychainReauthorize();
-  if (!success)
-    return;
-
-  [user_defaults setBool:YES forKey:success_pref_key];
-  [user_defaults synchronize];
-}
-
-}  // namespace
-
-void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries) {
-#if defined(GOOGLE_CHROME_BUILD)
-  // Only launch the stub executable when running in the browser.
-  DCHECK(base::mac::AmIBundled());
-
-  NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults];
-  int pref_value = [user_defaults integerForKey:pref_key];
-
-  if (pref_value >= max_tries)
-    return;
-
-  NSString* success_pref_key = [pref_key stringByAppendingString:@"Success"];
-  BOOL success_value = [user_defaults boolForKey:success_pref_key];
-  if (success_value)
-    return;
-
-  if (pref_value > 0) {
-    // Logs the number of previous tries that didn't complete.
-    base::UmaHistogramSparse("OSX.KeychainReauthorizeIfNeeded", pref_value);
-  }
-
-  ++pref_value;
-  [user_defaults setInteger:pref_value forKey:pref_key];
-  [user_defaults synchronize];
-
-  NSBundle* main_bundle = base::mac::OuterBundle();
-  std::string identifier =
-      base::SysNSStringToUTF8([main_bundle bundleIdentifier]);
-  std::string bundle_path = base::SysNSStringToUTF8([main_bundle bundlePath]);
-
-  base::FilePath reauth_binary = base::FilePath(bundle_path)
-                                     .Append("Contents")
-                                     .Append("Helpers")
-                                     .Append(identifier);
-
-  std::string framework_path =
-      base::SysNSStringToUTF8([base::mac::FrameworkBundle() executablePath]);
-
-  std::vector<std::string> argv = {reauth_binary.value(), framework_path};
-  std::vector<char*> argv_cstr;
-  argv_cstr.reserve(argv.size() + 1);
-  for (size_t i = 0; i < argv.size(); ++i) {
-    argv_cstr.push_back(const_cast<char*>(argv[i].c_str()));
-  }
-  argv_cstr.push_back(nullptr);
-
-  pid_t pid;
-  char** new_environ = *_NSGetEnviron();
-  errno = posix_spawn(&pid, reauth_binary.value().c_str(), nullptr, nullptr,
-                      &argv_cstr[0], new_environ);
-  if (errno != 0) {
-    PLOG(ERROR) << "posix_spawn";
-    return;
-  } else {
-    // If execution does not block on the helper stub, there is a
-    // race condition between it and Chrome creating a new keychain entry.
-    int status;
-    if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid || status != 0) {
-      return;
-    }
-  }
-
-  // Find out if the re-authorization succeeded by querying cfprefs.
-  bool stub_result = [user_defaults boolForKey:success_pref_key];
-  // Logs the try number (1, 2) that succeeded.
-  if (stub_result) {
-    base::UmaHistogramSparse("OSX.KeychainReauthorizeIfNeededSuccess",
-                             pref_value);
-  }
-#endif  // defined(GOOGLE_CHROME_BUILD)
-}
-
-void KeychainReauthorizeIfNeededAtUpdate(NSString* pref_key, int max_tries) {
-  @autoreleasepool {
-    KeychainReauthorizeFromStub(pref_key);
-  }
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index 76732b2..470caf9 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -31,6 +31,7 @@
 #include "media/cdm/supported_cdm_versions.h"
 #include "media/media_buildflags.h"
 #include "testing/gtest/include/gtest/gtest-spi.h"
+#include "third_party/libaom/av1_buildflags.h"
 #include "third_party/widevine/cdm/buildflags.h"
 #include "third_party/widevine/cdm/widevine_cdm_common.h"
 
@@ -88,6 +89,10 @@
     "video/mp4; codecs=\"vp09.00.10.08.01.02.02.02.00\"";
 const char kMp4Vp9Profile2VideoOnly[] =
     "video/mp4; codecs=\"vp09.02.10.10.01.02.02.02.00\"";
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+const char kWebMAv1VideoOnly[] = "video/webm; codecs=\"av01.0.04M.08\"";
+const char kMp4Av1VideoOnly[] = "video/mp4; codecs=\"av01.0.04M.08\"";
+#endif  // BUILDFLAG(ENABLE_AV1_DECODER)
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
 const char kWebMVp8VideoOnly[] = "video/webm; codecs=\"vp8\"";
 #endif
@@ -559,18 +564,6 @@
   TestSimplePlayback("bear-320x240-opus-av_enc-v.webm", kWebMOpusAudioVp9Video);
 }
 
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VP9Profile2Video_WebM) {
-#if BUILDFLAG(ENABLE_WIDEVINE)
-  // TODO(crbug.com/707128): Update Widevine CDM to support VP9 profile 1/2/3.
-  if (IsWidevine(CurrentKeySystem())) {
-    DVLOG(0) << "Skipping test - Widevine CDM does not support VP9 profile 2";
-    return;
-  }
-#endif
-  TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.webm",
-                     kWebMVp9Profile2VideoOnly);
-}
-
 // TODO(xhwang): Test is flaky. https://crbug.com/890124.
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
                        DISABLED_Playback_Multiple_VideoAudio_WebM) {
@@ -599,6 +592,19 @@
   TestSimplePlayback("bear-320x240-v_frag-vp9-cenc.mp4", kMp4Vp9VideoOnly);
 }
 
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
+                       Playback_VideoOnly_WebM_VP9Profile2) {
+#if BUILDFLAG(ENABLE_WIDEVINE)
+  // TODO(crbug.com/707128): Update Widevine CDM to support VP9 profile 1/2/3.
+  if (IsWidevine(CurrentKeySystem())) {
+    DVLOG(0) << "Skipping test - Widevine CDM does not support VP9 profile 2";
+    return;
+  }
+#endif
+  TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.webm",
+                     kWebMVp9Profile2VideoOnly);
+}
+
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_VP9Profile2) {
   // MP4 without MSE is not support yet, http://crbug.com/170793.
   if (CurrentSourceType() != SrcType::MSE) {
@@ -616,6 +622,35 @@
                      kMp4Vp9Profile2VideoOnly);
 }
 
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_AV1) {
+#if BUILDFLAG(ENABLE_WIDEVINE)
+  // TODO(crbug.com/884845): Update Widevine CDM to support AV1.
+  if (IsWidevine(CurrentKeySystem())) {
+    DVLOG(0) << "Skipping test - Widevine CDM does not support AV1";
+    return;
+  }
+#endif
+  TestSimplePlayback("bear-av1-cenc.webm", kWebMAv1VideoOnly);
+}
+
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_AV1) {
+  // MP4 without MSE is not support yet, http://crbug.com/170793.
+  if (CurrentSourceType() != SrcType::MSE) {
+    DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
+    return;
+  }
+#if BUILDFLAG(ENABLE_WIDEVINE)
+  // TODO(crbug.com/884845): Update Widevine CDM to support AV1.
+  if (IsWidevine(CurrentKeySystem())) {
+    DVLOG(0) << "Skipping test - Widevine CDM does not support AV1";
+    return;
+  }
+#endif
+  TestSimplePlayback("bear-av1-cenc.mp4", kMp4Av1VideoOnly);
+}
+#endif  // BUILDFLAG(ENABLE_AV1_DECODER)
+
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, InvalidResponseKeyError) {
   RunInvalidResponseTest();
 }
@@ -797,7 +832,13 @@
                        kUnitTestSuccess);
 }
 
-IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, MessageTypeTest) {
+// Intermittent leaks on ASan/LSan runs: crbug.com/889923
+#if defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
+#define MAYBE_MessageTypeTest DISABLED_MessageTypeTest
+#else
+#define MAYBE_MessageTypeTest MessageTypeTest
+#endif
+IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, MAYBE_MessageTypeTest) {
   TestPlaybackCase(kExternalClearKeyMessageTypeTestKeySystem, kNoSessionToLoad,
                    media::kEnded);
 
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_browsertest.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_browsertest.cc
index 50b68c1..9541f9a 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_browsertest.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_browsertest.cc
@@ -3,7 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/metrics/subprocess_metrics_provider.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/pref_names.h"
@@ -56,7 +59,7 @@
 
 }  // namespace
 
-class DataReductionProxyBrowsertest : public InProcessBrowserTest {
+class DataReductionProxyBrowsertestBase : public InProcessBrowserTest {
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     net::HostPortPair host_port_pair = embedded_test_server()->host_port_pair();
@@ -67,10 +70,15 @@
         ProxyServer::UNSPECIFIED_TYPE, 0.5f, false));
     command_line->AppendSwitchASCII(
         switches::kDataReductionProxyServerClientConfig, config);
-    command_line->AppendSwitch(
-        switches::kDisableDataReductionProxyWarmupURLFetch);
     command_line->AppendSwitchASCII(
         network::switches::kForceEffectiveConnectionType, "4G");
+
+    secure_proxy_check_server_.RegisterRequestHandler(
+        base::BindRepeating(&BasicResponse, "OK"));
+    ASSERT_TRUE(secure_proxy_check_server_.Start());
+    command_line->AppendSwitchASCII(
+        switches::kDataReductionProxySecureProxyCheckURL,
+        secure_proxy_check_server_.base_url().spec());
   }
 
   void SetUp() override {
@@ -79,7 +87,7 @@
     param_feature_list_.InitAndEnableFeatureWithParameters(
         features::kDataReductionProxyRobustConnection,
         {{params::GetMissingViaBypassParamName(), "true"},
-         {params::GetWarmupCallbackParamName(), "true"}});
+         {"warmup_fetch_callback_enabled", "true"}});
     ASSERT_TRUE(embedded_test_server()->Start());
     InProcessBrowserTest::SetUp();
   }
@@ -118,6 +126,16 @@
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   base::test::ScopedFeatureList param_feature_list_;
+  net::EmbeddedTestServer secure_proxy_check_server_;
+};
+
+class DataReductionProxyBrowsertest : public DataReductionProxyBrowsertestBase {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    DataReductionProxyBrowsertestBase::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(
+        switches::kDisableDataReductionProxyWarmupURLFetch);
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, ChromeProxyHeaderSet) {
@@ -395,4 +413,114 @@
   EXPECT_EQ(core_request_count_, 1);
 }
 
+class DataReductionProxyWarmupURLBrowsertest
+    : public DataReductionProxyBrowsertestBase,
+      public testing::WithParamInterface<ProxyServer_ProxyScheme> {
+ public:
+  DataReductionProxyWarmupURLBrowsertest()
+      : primary_server_(GetTestServerType()),
+        secondary_server_(GetTestServerType()) {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    DataReductionProxyBrowsertestBase::SetUpCommandLine(command_line);
+
+    ASSERT_TRUE(primary_server_.InitializeAndListen());
+    ASSERT_TRUE(secondary_server_.InitializeAndListen());
+
+    net::HostPortPair primary_host_port_pair = primary_server_.host_port_pair();
+    net::HostPortPair secondary_host_port_pair =
+        secondary_server_.host_port_pair();
+    std::string config = EncodeConfig(CreateConfig(
+        kSessionKey, 1000, 0, GetParam(), primary_host_port_pair.host(),
+        primary_host_port_pair.port(), ProxyServer::UNSPECIFIED_TYPE,
+        GetParam(), secondary_host_port_pair.host(),
+        secondary_host_port_pair.port(), ProxyServer::CORE, 0.5f, false));
+    command_line->AppendSwitchASCII(
+        switches::kDataReductionProxyServerClientConfig, config);
+  }
+
+  void SetUpOnMainThread() override {
+    primary_server_loop_ = std::make_unique<base::RunLoop>();
+    primary_server_.RegisterRequestHandler(base::BindRepeating(
+        &DataReductionProxyWarmupURLBrowsertest::WaitForWarmupRequest,
+        base::Unretained(this), primary_server_loop_.get()));
+    primary_server_.StartAcceptingConnections();
+
+    secondary_server_loop_ = std::make_unique<base::RunLoop>();
+    secondary_server_.RegisterRequestHandler(base::BindRepeating(
+        &DataReductionProxyWarmupURLBrowsertest::WaitForWarmupRequest,
+        base::Unretained(this), secondary_server_loop_.get()));
+    secondary_server_.StartAcceptingConnections();
+
+    DataReductionProxyBrowsertestBase::SetUpOnMainThread();
+  }
+
+  void SetViaHeader(const std::string& via_header) { via_header_ = via_header; }
+
+  std::string GetHistogramName(ProxyServer::ProxyType type) {
+    return base::StrCat(
+        {"DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch.",
+         GetParam() == ProxyServer_ProxyScheme_HTTP ? "Insecure" : "Secure",
+         "Proxy.", type == ProxyServer::CORE ? "Core" : "NonCore"});
+  }
+
+  std::unique_ptr<base::RunLoop> primary_server_loop_;
+  std::unique_ptr<base::RunLoop> secondary_server_loop_;
+  base::HistogramTester histogram_tester_;
+
+ private:
+  net::EmbeddedTestServer::Type GetTestServerType() {
+    if (GetParam() == ProxyServer_ProxyScheme_HTTP)
+      return net::EmbeddedTestServer::TYPE_HTTP;
+    return net::EmbeddedTestServer::TYPE_HTTPS;
+  }
+
+  std::unique_ptr<net::test_server::HttpResponse> WaitForWarmupRequest(
+      base::RunLoop* run_loop,
+      const net::test_server::HttpRequest& request) {
+    if (base::StartsWith(request.relative_url, "/e2e_probe",
+                         base::CompareCase::SENSITIVE)) {
+      run_loop->Quit();
+    }
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_content("content");
+    response->AddCustomHeader("via", via_header_);
+    return response;
+  }
+
+  std::string via_header_;
+  net::EmbeddedTestServer primary_server_;
+  net::EmbeddedTestServer secondary_server_;
+};
+
+IN_PROC_BROWSER_TEST_P(DataReductionProxyWarmupURLBrowsertest,
+                       WarmupURLsFetchedForEachProxy) {
+  SetViaHeader("1.1 Chrome-Compression-Proxy");
+  primary_server_loop_->Run();
+  secondary_server_loop_->Run();
+
+  SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+  histogram_tester_.ExpectUniqueSample(
+      GetHistogramName(ProxyServer::UNSPECIFIED_TYPE), true, 1);
+  histogram_tester_.ExpectUniqueSample(GetHistogramName(ProxyServer::CORE),
+                                       true, 1);
+}
+
+IN_PROC_BROWSER_TEST_P(DataReductionProxyWarmupURLBrowsertest, WarmupURLsFail) {
+  SetViaHeader("bad");
+  primary_server_loop_->Run();
+  secondary_server_loop_->Run();
+
+  SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+  histogram_tester_.ExpectUniqueSample(
+      GetHistogramName(ProxyServer::UNSPECIFIED_TYPE), false, 1);
+  histogram_tester_.ExpectUniqueSample(GetHistogramName(ProxyServer::CORE),
+                                       false, 1);
+}
+
+INSTANTIATE_TEST_CASE_P(,
+                        DataReductionProxyWarmupURLBrowsertest,
+                        testing::Values(ProxyServer_ProxyScheme_HTTP,
+                                        ProxyServer_ProxyScheme_HTTPS));
+
 }  // namespace data_reduction_proxy
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc
index a9d311b..99c4e81 100644
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc
@@ -18,6 +18,7 @@
 #include "net/base/mime_util.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
+#include "third_party/blink/public/common/download/download_stats.h"
 #include "third_party/blink/public/common/mime_util/mime_util.h"
 #include "url/gurl.h"
 
@@ -85,6 +86,26 @@
                           base::CompareCase::SENSITIVE);
 }
 
+bool IsSubframeSameOriginToMainFrame(content::RenderFrameHost* sub_host,
+                                     bool use_parent_origin) {
+  DCHECK(sub_host);
+  content::RenderFrameHost* main_host =
+      content::WebContents::FromRenderFrameHost(sub_host)->GetMainFrame();
+  if (use_parent_origin)
+    sub_host = sub_host->GetParent();
+  url::Origin subframe_origin = sub_host->GetLastCommittedOrigin();
+  url::Origin mainframe_origin = main_host->GetLastCommittedOrigin();
+  return subframe_origin.IsSameOriginWith(mainframe_origin);
+}
+
+void RecordDownloadMetrics(blink::DownloadStats::FrameType frame_type,
+                           bool has_user_gesture) {
+  blink::DownloadStats::GestureType gesture_type =
+      has_user_gesture ? blink::DownloadStats::GestureType::kWithGesture
+                       : blink::DownloadStats::GestureType::kWithoutGesture;
+  blink::DownloadStats::Record(frame_type, gesture_type);
+}
+
 using ResourceMimeType = AdsPageLoadMetricsObserver::ResourceMimeType;
 
 }  // namespace
@@ -182,13 +203,8 @@
   if (!ad_data && ad_types.any()) {
     AdOriginStatus origin_status = AdOriginStatus::kUnknown;
     if (ad_host) {
-      content::RenderFrameHost* main_host =
-          content::WebContents::FromRenderFrameHost(ad_host)->GetMainFrame();
       // For ads triggered on render, their origin is their parent's origin.
-      if (!frame_navigated)
-        ad_host = ad_host->GetParent();
-      origin_status = main_host->GetLastCommittedOrigin().IsSameOriginWith(
-                          ad_host->GetLastCommittedOrigin())
+      origin_status = IsSubframeSameOriginToMainFrame(ad_host, !frame_navigated)
                           ? AdOriginStatus::kSame
                           : AdOriginStatus::kCross;
     }
@@ -217,15 +233,37 @@
     content::NavigationHandle* navigation_handle) {
   FrameTreeNodeId frame_tree_node_id = navigation_handle->GetFrameTreeNodeId();
   AdTypes ad_types = DetectAds(navigation_handle);
+
   // NOTE: Frame look-up only used for determining cross-origin status, not
   // granting security permissions.
   content::RenderFrameHost* ad_host = FindFrameMaybeUnsafe(navigation_handle);
 
+  if (navigation_handle->IsDownload()) {
+    blink::DownloadStats::FrameType frame_type =
+        IsSubframeSameOriginToMainFrame(ad_host, /*use_parent_origin=*/false)
+            ? ad_types.any()
+                  ? blink::DownloadStats::FrameType::kSameOriginAdSubframe
+                  : blink::DownloadStats::FrameType::kSameOriginNonAdSubframe
+            : ad_types.any()
+                  ? blink::DownloadStats::FrameType::kCrossOriginAdSubframe
+                  : blink::DownloadStats::FrameType::kCrossOriginNonAdSubframe;
+    RecordDownloadMetrics(frame_type, navigation_handle->HasUserGesture());
+  }
+
   RecordAdFrameData(frame_tree_node_id, ad_types, ad_host,
                     /*frame_navigated=*/true);
   ProcessOngoingNavigationResource(frame_tree_node_id);
 }
 
+void AdsPageLoadMetricsObserver::OnDidInternalNavigationAbort(
+    content::NavigationHandle* navigation_handle) {
+  // Main frame navigation
+  if (navigation_handle->IsDownload()) {
+    RecordDownloadMetrics(blink::DownloadStats::FrameType::kMainFrame,
+                          navigation_handle->HasUserGesture());
+  }
+}
+
 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
 AdsPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
     const page_load_metrics::mojom::PageLoadTiming& timing,
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h
index 1f03c58..21e3bed5db 100644
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h
@@ -76,6 +76,8 @@
                          bool frame_navigated);
   void OnDidFinishSubFrameNavigation(
       content::NavigationHandle* navigation_handle) override;
+  void OnDidInternalNavigationAbort(
+      content::NavigationHandle* navigation_handle) override;
   ObservePolicy FlushMetricsOnAppEnterBackground(
       const page_load_metrics::mojom::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& extra_info) override;
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
index 82e333e..0d1ce150 100644
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
@@ -9,8 +9,10 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/metrics/subprocess_metrics_provider.h"
 #include "chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_features.h"
@@ -25,18 +27,65 @@
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/download_test_observer.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_source.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/download/download_stats.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
 
 namespace {
+
 const char kCrossOriginHistogramId[] =
     "PageLoad.Clients.Ads.Google.FrameCounts.AdFrames.PerFrame.OriginStatus";
+
+enum class Origin {
+  kNavigation,
+  kAnchorAttribute,
+};
+
+using FrameType = blink::DownloadStats::FrameType;
+using GestureType = blink::DownloadStats::GestureType;
+using MetadataInfo = std::tuple<Origin, FrameType, GestureType>;
+
+std::string ToString(Origin origin) {
+  switch (origin) {
+    case Origin::kNavigation:
+      return "Navigation";
+    case Origin::kAnchorAttribute:
+      return "AnchorAttribute";
+  }
+}
+
+std::string ToString(FrameType type) {
+  switch (type) {
+    case FrameType::kMainFrame:
+      return "MainFrame";
+    case FrameType::kSameOriginAdSubframe:
+      return "SameOriginAdSubframe";
+    case FrameType::kSameOriginNonAdSubframe:
+      return "SameOriginNonAdSubframe";
+    case FrameType::kCrossOriginAdSubframe:
+      return "CrossOriginAdSubframe";
+    case FrameType::kCrossOriginNonAdSubframe:
+      return "CrossOriginNonAdSubframe";
+  }
+}
+
+std::string ToString(GestureType gesture) {
+  switch (gesture) {
+    case GestureType::kWithoutGesture:
+      return "Without_Gesture";
+    case GestureType::kWithGesture:
+      return "With_Gesture";
+  }
+}
+
 }  // namespace
 
 class AdsPageLoadMetricsObserverBrowserTest
@@ -186,7 +235,8 @@
 };
 
 class AdsPageLoadMetricsObserverResourceBrowserTest
-    : public subresource_filter::SubresourceFilterBrowserTest {
+    : public subresource_filter::SubresourceFilterBrowserTest,
+      public ::testing::WithParamInterface<MetadataInfo> {
  public:
   AdsPageLoadMetricsObserverResourceBrowserTest() {
     scoped_feature_list_.InitAndEnableFeature(features::kAdsFeature);
@@ -197,7 +247,25 @@
     host_resolver()->AddRule("*", "127.0.0.1");
     SetRulesetWithRules(
         {subresource_filter::testing::CreateSuffixRule("ad_script.js"),
-         subresource_filter::testing::CreateSuffixRule("create_frame.js")});
+         subresource_filter::testing::CreateSuffixRule("ad_script_2.js"),
+         subresource_filter::testing::CreateSuffixRule("disallow.zip")});
+  }
+
+  void OpenLinkInFrame(const content::ToRenderFrameHost& adapter,
+                       const std::string& link_id,
+                       GestureType gesture) {
+    std::string open_link_script = base::StringPrintf(
+        R"(
+            var evt = document.createEvent("MouseEvent");
+            evt.initMouseEvent('click', true, true);
+            document.getElementById('%s').dispatchEvent(evt);
+        )",
+        link_id.c_str());
+    if (gesture == GestureType::kWithGesture) {
+      EXPECT_TRUE(ExecuteScript(adapter, open_link_script));
+    } else {
+      EXPECT_TRUE(ExecuteScriptWithoutUserGesture(adapter, open_link_script));
+    }
   }
 
  protected:
@@ -223,7 +291,7 @@
   ui_test_utils::NavigateToURL(
       browser(),
       embedded_test_server()->GetURL("foo.com", "/frame_factory.html"));
-  // Both subresources should have been reported as ads.
+  // Two subresources should have been reported as ads.
   waiter->AddMinimumAdResourceExpectation(2);
   waiter->Wait();
 }
@@ -244,9 +312,9 @@
       browser(),
       embedded_test_server()->GetURL("foo.com", "/frame_factory.html"));
   contents->GetMainFrame()->ExecuteJavaScriptForTests(
-      base::ASCIIToUTF16("createFrame('frame_factory.html', '');"));
-  // Both pages subresources should have been reported as ad. The iframe
-  // resource should also be reported as an ad.
+      base::ASCIIToUTF16("createAdFrame('frame_factory.html', '');"));
+  // Two pages subresources should have been reported as ad. The iframe resource
+  // should also be reported as an ad.
   waiter->AddMinimumAdResourceExpectation(5);
   waiter->Wait();
 }
@@ -267,14 +335,14 @@
       browser(),
       embedded_test_server()->GetURL("foo.com", "/frame_factory.html"));
   contents->GetMainFrame()->ExecuteJavaScriptForTests(
-      base::ASCIIToUTF16("createFrame('frame_factory.html', 'test');"));
+      base::ASCIIToUTF16("createAdFrame('frame_factory.html', 'test');"));
   waiter->AddMinimumAdResourceExpectation(5);
   waiter->Wait();
   NavigateIframeToURL(
       web_contents(), "test",
       embedded_test_server()->GetURL("foo.com", "/frame_factory.html"));
-  // All resources except the top-level main resource should be reported as an
-  // ad.
+  // The new subframe as well as two of its page subresources should be reported
+  // as an ad.
   waiter->AddMinimumAdResourceExpectation(8);
   waiter->Wait();
 }
@@ -435,7 +503,7 @@
   GURL url = embedded_test_server()->GetURL("foo.com", "/frame_factory.html");
   ui_test_utils::NavigateToURL(browser(), url);
   contents->GetMainFrame()->ExecuteJavaScriptForTests(
-      base::ASCIIToUTF16("createFrame('multiple_mimes.html', 'test');"));
+      base::ASCIIToUTF16("createAdFrame('multiple_mimes.html', 'test');"));
   waiter->AddMinimumAdResourceExpectation(8);
   waiter->Wait();
 
@@ -483,3 +551,119 @@
                 entries.front(), ukm::builders::AdPageLoad::kAdVideoBytesName),
             0);
 }
+
+// Download gets blocked when LoadPolicy is DISALLOW for the navigation
+// to download
+IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest,
+                       DownloadBlocked) {
+  ResetConfiguration(subresource_filter::Configuration(
+      subresource_filter::mojom::ActivationLevel::kEnabled,
+      subresource_filter::ActivationScope::ALL_SITES));
+
+  base::HistogramTester histogram_tester;
+
+  embedded_test_server()->ServeFilesFromSourceDirectory(
+      "chrome/test/data/ad_tagging");
+  content::SetupCrossSiteRedirector(embedded_test_server());
+  ASSERT_TRUE(embedded_test_server()->Start());
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  std::string host_name = "foo.com";
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL(host_name, "/frame_factory.html"));
+  content::TestNavigationObserver navigation_observer(web_contents());
+  contents->GetMainFrame()->ExecuteJavaScriptForTests(
+      base::ASCIIToUTF16("createFrame('download.html', 'test');"));
+  navigation_observer.Wait();
+
+  content::RenderFrameHost* rfh = content::FrameMatchingPredicate(
+      web_contents(), base::BindRepeating(&content::FrameMatchesName, "test"));
+  OpenLinkInFrame(rfh, "blocked_nav_download_id", GestureType::kWithoutGesture);
+
+  SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+  histogram_tester.ExpectTotalCount("Download.FrameGesture", 0);
+}
+
+// Download events are reported correctly.
+IN_PROC_BROWSER_TEST_P(AdsPageLoadMetricsObserverResourceBrowserTest,
+                       Download) {
+  Origin origin;
+  FrameType frame_type;
+  GestureType gesture_type;
+  std::tie(origin, frame_type, gesture_type) = GetParam();
+  SCOPED_TRACE(::testing::Message()
+               << "origin = " << ToString(origin) << ", "
+               << "frame_type = " << ToString(frame_type) << ", "
+               << "gesture_type = " << ToString(gesture_type));
+
+  base::HistogramTester histogram_tester;
+  std::unique_ptr<content::DownloadTestObserver> download_observer(
+      new content::DownloadTestObserverTerminal(
+          content::BrowserContext::GetDownloadManager(browser()->profile()),
+          1 /* wait_count */,
+          content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL));
+
+  embedded_test_server()->ServeFilesFromSourceDirectory(
+      "chrome/test/data/ad_tagging");
+  content::SetupCrossSiteRedirector(embedded_test_server());
+  ASSERT_TRUE(embedded_test_server()->Start());
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  std::string host_name = "foo.com";
+  std::string initial_url = (frame_type == FrameType::kMainFrame)
+                                ? "/download.html"
+                                : "/frame_factory.html";
+  ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL(host_name, initial_url));
+
+  std::string link_id =
+      origin == Origin::kNavigation ? "nav_download_id" : "anchor_download_id";
+
+  if (frame_type == FrameType::kMainFrame) {
+    OpenLinkInFrame(web_contents(), link_id, gesture_type);
+  } else {
+    bool same_origin = frame_type == FrameType::kSameOriginAdSubframe ||
+                       frame_type == FrameType::kSameOriginNonAdSubframe;
+    bool ad_subframe = frame_type == FrameType::kSameOriginAdSubframe ||
+                       frame_type == FrameType::kCrossOriginAdSubframe;
+    content::TestNavigationObserver navigation_observer(web_contents());
+    std::string script = base::StringPrintf(
+        "%s('%s','%s');", ad_subframe ? "createAdFrame" : "createFrame",
+        embedded_test_server()
+            ->GetURL(same_origin ? host_name : "bar.com", "/download.html")
+            .spec()
+            .c_str(),
+        "test");
+    contents->GetMainFrame()->ExecuteJavaScriptForTests(
+        base::ASCIIToUTF16(script));
+    navigation_observer.Wait();
+
+    content::RenderFrameHost* rfh = content::FrameMatchingPredicate(
+        web_contents(),
+        base::BindRepeating(&content::FrameMatchesName, "test"));
+    OpenLinkInFrame(rfh, link_id, gesture_type);
+  }
+
+  download_observer->WaitForFinished();
+  SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+  histogram_tester.ExpectUniqueSample(
+      "Download.FrameGesture",
+      blink::DownloadStats::GetMetricsEnum(frame_type, gesture_type),
+      1 /* expected_count */);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    /* no prefix */,
+    AdsPageLoadMetricsObserverResourceBrowserTest,
+    ::testing::Combine(::testing::Values(Origin::kNavigation,
+                                         Origin::kAnchorAttribute),
+                       ::testing::Values(FrameType::kMainFrame,
+                                         FrameType::kSameOriginAdSubframe,
+                                         FrameType::kSameOriginNonAdSubframe,
+                                         FrameType::kCrossOriginAdSubframe,
+                                         FrameType::kCrossOriginNonAdSubframe),
+                       ::testing::Values(GestureType::kWithoutGesture,
+                                         GestureType::kWithGesture)));
diff --git a/chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.cc
index 2785314..ab89c511a 100644
--- a/chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.cc
@@ -67,6 +67,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_46:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.ParseTiming.NavigationToParseStart",
@@ -125,6 +126,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_46:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.PaintTiming."
@@ -189,6 +191,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_46:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.Experimental.PaintTiming."
@@ -243,6 +246,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_46:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.DocumentTiming."
@@ -292,6 +296,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_46:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       PAGE_LOAD_HISTOGRAM(
           "PageLoad.Clients.Protocol.QUIC.DocumentTiming."
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index e056598..27fbd9de 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -6,7 +6,6 @@
 
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/devtools/devtools_window_testing.h"
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
@@ -25,7 +24,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
-#include "media/base/media_switches.h"
 #include "net/dns/mock_host_resolver.h"
 #include "skia/ext/image_operations.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -79,9 +77,7 @@
 class PictureInPictureWindowControllerBrowserTest
     : public InProcessBrowserTest {
  public:
-  PictureInPictureWindowControllerBrowserTest() {
-    feature_list_.InitWithFeatures({media::kUseSurfaceLayerForVideoMS}, {});
-  }
+  PictureInPictureWindowControllerBrowserTest() = default;
 
   void SetUpOnMainThread() override {
     host_resolver()->AddRule("*", "127.0.0.1");
@@ -151,7 +147,6 @@
 
  private:
   content::PictureInPictureWindowController* pip_window_controller_ = nullptr;
-  base::test::ScopedFeatureList feature_list_;
   MockPictureInPictureWindowController mock_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(PictureInPictureWindowControllerBrowserTest);
diff --git a/chrome/browser/policy/chrome_browser_policy_connector.cc b/chrome/browser/policy/chrome_browser_policy_connector.cc
index 4e798a66..e438e01 100644
--- a/chrome/browser/policy/chrome_browser_policy_connector.cc
+++ b/chrome/browser/policy/chrome_browser_policy_connector.cc
@@ -67,6 +67,16 @@
 #endif  // !defined(OS_CHROMEOS) && BUILDFLAG(ENABLE_EXTENSIONS)
 }
 
+bool ProviderHasPolicies(const ConfigurationPolicyProvider* provider) {
+  if (!provider)
+    return false;
+  for (const auto& pair : provider->policies()) {
+    if (!pair.second->empty())
+      return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 ChromeBrowserPolicyConnector::ChromeBrowserPolicyConnector()
@@ -107,6 +117,16 @@
   return false;
 }
 
+bool ChromeBrowserPolicyConnector::HasMachineLevelPolicies() {
+  if (ProviderHasPolicies(GetPlatformProvider()))
+    return true;
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+  if (ProviderHasPolicies(machine_level_user_cloud_policy_manager_))
+    return true;
+#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+  return false;
+}
+
 void ChromeBrowserPolicyConnector::Shutdown() {
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   // Reset the controller before calling base class so that
diff --git a/chrome/browser/policy/chrome_browser_policy_connector.h b/chrome/browser/policy/chrome_browser_policy_connector.h
index 4cfa9efa..4a9efb1 100644
--- a/chrome/browser/policy/chrome_browser_policy_connector.h
+++ b/chrome/browser/policy/chrome_browser_policy_connector.h
@@ -49,6 +49,8 @@
 
   bool IsEnterpriseManaged() const override;
 
+  bool HasMachineLevelPolicies() override;
+
   void Shutdown() override;
 
   ConfigurationPolicyProvider* GetPlatformProvider();
diff --git a/chrome/browser/policy/chrome_browser_policy_connector_unittest.cc b/chrome/browser/policy/chrome_browser_policy_connector_unittest.cc
new file mode 100644
index 0000000..118b275
--- /dev/null
+++ b/chrome/browser/policy/chrome_browser_policy_connector_unittest.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
+
+#include <memory>
+
+#include "base/values.h"
+#include "build/build_config.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+#if !defined(OS_CHROMEOS)
+// HasMachineLevelPolicies() is not implemented on ChromeOS.
+TEST(ChromeBrowserPolicyConnectorTest, HasMachineLevelPolicies) {
+  MockConfigurationPolicyProvider provider;
+  BrowserPolicyConnectorBase::SetPolicyProviderForTesting(&provider);
+
+  ChromeBrowserPolicyConnector connector;
+  EXPECT_FALSE(connector.HasMachineLevelPolicies());
+
+  PolicyMap map;
+  map.Set("test-policy", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+          POLICY_SOURCE_PLATFORM, std::make_unique<base::Value>("hello"),
+          nullptr);
+  provider.UpdateChromePolicy(map);
+  EXPECT_TRUE(connector.HasMachineLevelPolicies());
+}
+#endif  // !defined(OS_CHROMEOS)
+
+}  // namespace policy
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 897eca5..d9fb637f 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -85,7 +85,7 @@
 #include "components/feature_engagement/buildflags.h"
 #include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/gcm_driver/gcm_channel_status_syncer.h"
-#include "components/image_fetcher/core/storage/image_cache.h"
+#include "components/image_fetcher/core/cache/image_cache.h"
 #include "components/invalidation/impl/invalidator_registrar_with_memory.h"
 #include "components/invalidation/impl/per_user_topic_registration_manager.h"
 #include "components/language/content/browser/geo_language_provider.h"
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 607eed6d..b975e29 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -152,6 +152,7 @@
 #include "chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.h"
 #include "chrome/browser/chromeos/multidevice_setup/auth_token_validator_factory.h"
 #include "chrome/browser/chromeos/multidevice_setup/auth_token_validator_impl.h"
+#include "chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.h"
 #include "chrome/browser/chromeos/net/delay_network_call.h"
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.h"
@@ -1497,6 +1498,8 @@
       chromeos::device_sync::DeviceSyncClientFactory::GetForProfile(this),
       chromeos::multidevice_setup::AuthTokenValidatorFactory::GetForProfile(
           this),
+      chromeos::multidevice_setup::OobeCompletionTrackerFactory::GetForProfile(
+          this),
       std::make_unique<
           chromeos::multidevice_setup::AndroidSmsAppHelperDelegateImpl>(this),
       std::make_unique<
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/kbexplorer.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/kbexplorer.js
index a3338b7..a6fa438e 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/kbexplorer.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/kbexplorer.js
@@ -44,21 +44,6 @@
   backgroundWindow['BrailleCommandHandler']['setEnabled'](false);
   backgroundWindow['GestureCommandHandler']['setEnabled'](false);
 
-  window.onbeforeunload = function(evt) {
-    backgroundWindow.removeEventListener(
-        'keydown', cvox.KbExplorer.onKeyDown, true);
-    backgroundWindow.removeEventListener(
-        'keyup', cvox.KbExplorer.onKeyUp, true);
-    backgroundWindow.removeEventListener(
-        'keypress', cvox.KbExplorer.onKeyPress, true);
-    chrome.brailleDisplayPrivate.onKeyEvent.removeListener(
-        cvox.KbExplorer.onBrailleKeyEvent);
-    chrome.accessibilityPrivate.onAccessibilityGesture.removeListener(
-        cvox.KbExplorer.onAccessibilityGesture);
-    chrome.accessibilityPrivate.setKeyboardListener(true, false);
-    backgroundWindow['BrailleCommandHandler']['setEnabled'](true);
-    backgroundWindow['GestureCommandHandler']['setEnabled'](true);
-  };
   if (localStorage['useClassic'] != 'true') {
     cvox.ChromeVoxKbHandler.handlerKeyMap = cvox.KeyMap.fromNext();
     cvox.ChromeVox.modKeyStr = 'Search';
@@ -87,8 +72,10 @@
       cvox.KeyUtil.getReadableNameForKeyCode(evt.keyCode), false,
       cvox.AbstractTts.PERSONALITY_ANNOTATION);
 
-  // Allow Ctrl+W to be handled.
-  if (evt.keyCode == 87 && evt.ctrlKey) {
+  // Allow Ctrl+W or escape to be handled.
+  if ((evt.key == 'w' && evt.ctrlKey) || evt.key == 'Escape') {
+    cvox.KbExplorer.resetListeners_();
+    window.close();
     return true;
   }
 
@@ -248,3 +235,20 @@
   chrome.extension.getBackgroundPage()['ChromeVoxState']['instance']
                                       ['setCurrentRange'](null);
 };
+
+/** @private */
+cvox.KbExplorer.resetListeners_ = function() {
+  var backgroundWindow = chrome.extension.getBackgroundPage();
+  backgroundWindow.removeEventListener(
+      'keydown', cvox.KbExplorer.onKeyDown, true);
+  backgroundWindow.removeEventListener('keyup', cvox.KbExplorer.onKeyUp, true);
+  backgroundWindow.removeEventListener(
+      'keypress', cvox.KbExplorer.onKeyPress, true);
+  chrome.brailleDisplayPrivate.onKeyEvent.removeListener(
+      cvox.KbExplorer.onBrailleKeyEvent);
+  chrome.accessibilityPrivate.onAccessibilityGesture.removeListener(
+      cvox.KbExplorer.onAccessibilityGesture);
+  chrome.accessibilityPrivate.setKeyboardListener(true, false);
+  backgroundWindow['BrailleCommandHandler']['setEnabled'](true);
+  backgroundWindow['GestureCommandHandler']['setEnabled'](true);
+};
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
index b3898d1..12122c88 100644
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -24,7 +24,7 @@
    *     in the output; otherwise it's hard or impossible to determine
    *     from screen captures or print-to-PDFs.
    */
-  let cursorPositionUsed = -1;
+  let cursorPosition = -1;
 
   /**
    * Returns a simple object with information about how to display an
@@ -43,15 +43,67 @@
      *     presented as a tooltip when the mouse is hovered over the column title.
      */
     constructor(header, url, propertyName, displayAlways, tooltip) {
+      /** @type {string} */
       this.header = header;
-      this.urlLabelForHeader = url;
+      /** @type {string} */
+      this.url = url;
+      /** @type {string} */
       this.propertyName = propertyName;
+      /** @type {boolean} */
       this.displayAlways = displayAlways;
+      /** @type {string} */
       this.tooltip = tooltip;
     }
   }
 
   /**
+   * Tracks and aggregates responses from the C++ autocomplete controller.
+   * Typically, the C++ controller returns 3 sets of results per query, unless
+   * a new query is submitted before all 3 responses. OutputController also
+   * triggers appending to and clearing of OmniboxOutput when appropriate (e.g.,
+   * upon receiving a new response or a change in display inputs).
+   */
+  class OutputController {
+    constructor() {
+      /** @private {!Array<mojom.OmniboxResult>} */
+      this.outputResultsGroups = [];
+    }
+
+    clear() {
+      this.outputResultsGroups = [];
+      omniboxOutput.clearOutput();
+    }
+
+    /*
+     * Adds a new response to the page. If we're not displaying incomplete
+     * results, we clear the page and display only the new result. If we are
+     * displaying incomplete results, then this is more efficient than refresh,
+     * as there's no need to clear and re-add previous results.
+     */
+    /** @param {!mojom.OmniboxResult} response A response from C++ autocomplete controller */
+    add(response) {
+      this.outputResultsGroups.push(response);
+      if (!omniboxInputs.$$('show-incomplete-results').checked)
+        omniboxOutput.clearOutput();
+      addResultToOutput(this.outputResultsGroups[this.outputResultsGroups.length - 1]);
+    }
+
+    /*
+     * Refreshes all results. We only display the last (most recent) entry
+     * unless incomplete results is enabled.
+     */
+    refresh() {
+      omniboxOutput.clearOutput();
+      if (omniboxInputs.$$('show-incomplete-results').checked) {
+        this.outputResultsGroups.forEach(addResultToOutput);
+      } else if (this.outputResultsGroups.length) {
+        addResultToOutput(
+            this.outputResultsGroups[this.outputResultsGroups.length - 1]);
+      }
+    }
+  }
+
+  /**
    * A constant that's used to decide what autocomplete result
    * properties to output in what order.  This is an array of
    * PresentationInfoRecord() objects; for details see that
@@ -137,7 +189,7 @@
     // batch of results.
     if (omniboxInputs.$$('show-details').checked
         || omniboxInputs.$$('show-incomplete-results').checked) {
-      addParagraph(`cursor position = ${cursorPositionUsed}`);
+      addParagraph(`cursor position = ${cursorPosition}`);
       addParagraph(`inferred input type = ${result.type}`);
       addParagraph(`elapsed time = ${result.timeSinceOmniboxStartedMs}ms`);
       addParagraph(`all providers done = ${result.done}`);
@@ -252,10 +304,10 @@
     PROPERTY_OUTPUT_ORDER.forEach(property => {
       if (inDetailedMode || property.displayAlways) {
         let headerCell = document.createElement('th');
-        if (property.urlLabelForHeader !== '') {
+        if (property.url !== '') {
           // Wrap header text in URL.
           let linkNode = document.createElement('a');
-          linkNode.href = property.urlLabelForHeader;
+          linkNode.href = property.url;
           linkNode.textContent = property.header;
           headerCell.appendChild(linkNode);
         } else {
@@ -342,38 +394,6 @@
     omniboxOutput.addOutput(p);
   }
 
-  /* Repaints the page based on the contents of the array
-   * progressiveAutocompleteResults, which represents consecutive
-   * autocomplete results.  We only display the last (most recent)
-   * entry unless we're asked to display incomplete results.  For an
-   * example of the output, play with chrome://omnibox/
-   */
-  function refreshAllResults() {
-    omniboxOutput.clearOutput();
-    if (omniboxInputs.$$('show-incomplete-results').checked)
-      browserProxy.progressiveAutocompleteResults.forEach(addResultToOutput);
-    else if (browserProxy.progressiveAutocompleteResults.length)
-      addResultToOutput(
-          browserProxy.progressiveAutocompleteResults
-              [browserProxy.progressiveAutocompleteResults.length - 1]);
-  }
-
-  /*
-   * Adds the last result, based on the contents of the array
-   * progressiveAutocompleteResults, to the page. If we're not displaying
-   * incomplete results, we clear the page and add the last result, similar to
-   * refreshAllResults. If we are displaying incomplete results, then this is
-   * more efficient than refreshAllResults, as there's no need to clear and
-   * re-add previous results.
-   */
-  function refreshNewResult() {
-    if (!omniboxInputs.$$('show-incomplete-results').checked)
-      omniboxOutput.clearOutput();
-    addResultToOutput(
-        browserProxy.progressiveAutocompleteResults
-            [browserProxy.progressiveAutocompleteResults.length - 1]);
-  }
-
   class BrowserProxy {
     constructor() {
       /** @private {!mojom.OmniboxPageHandlerPtr} */
@@ -389,14 +409,6 @@
       this.binding_ =
           new mojo.Binding(mojom.OmniboxPage, this, mojo.makeRequest(client));
       this.pagehandlePtr_.setClientPage(client);
-
-      /**
-       * @type {!Array<mojom.OmniboxResult>} an array of all autocomplete
-       *     results we've seen for this query.  We append to this list once for
-       *     every call to handleNewAutocompleteResult.  See omnibox.mojom for
-       *     details.
-       */
-      this.progressiveAutocompleteResults = [];
     }
 
     /**
@@ -405,12 +417,11 @@
      * call handleNewAutocompleteResult as results come in.
      */
     makeRequest(inputString,
-                cursorPositionUsed,
+                cursorPosition,
                 preventInlineAutocomplete,
                 preferKeyword,
                 pageClassification) {
-      omniboxOutput.clearOutput();
-      this.progressiveAutocompleteResults = [];
+      outputController.clear();
       // Then, call chrome with a five-element list:
       // - first element: the value in the text box
       // - second element: the location of the cursor in the text box
@@ -419,15 +430,14 @@
       // - fifth element: the value of page-classification
       this.pagehandlePtr_.startOmniboxQuery(
           inputString,
-          cursorPositionUsed,
+          cursorPosition,
           preventInlineAutocomplete,
           preferKeyword,
           pageClassification);
     }
 
-    handleNewAutocompleteResult(result) {
-      this.progressiveAutocompleteResults.push(result);
-      refreshNewResult();
+    handleNewAutocompleteResult(response) {
+      outputController.add(response);
     }
   }
 
@@ -437,6 +447,8 @@
   let omniboxInputs;
   /** @type {OmniboxOutput} */
   let omniboxOutput;
+  /** @type {OutputController} */
+  let outputController = new OutputController();
 
   document.addEventListener('DOMContentLoaded', () => {
     browserProxy = new BrowserProxy();
@@ -450,6 +462,7 @@
             event.detail.preferKeyword,
             event.detail.pageClassification
         ));
-    omniboxInputs.addEventListener('display-inputs-changed', refreshAllResults);
+    omniboxInputs.addEventListener('display-inputs-changed',
+        outputController.refresh.bind(outputController));
   });
 })();
diff --git a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html
index 2b93303..1b5fc56 100644
--- a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html
+++ b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html
@@ -9,14 +9,16 @@
     <link rel="import" href="signin_shared_css.html">
     <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
     <link rel="stylesheet" href="sync_confirmation.css"></link>
-    <style is="custom-style" include="signin-dialog-shared paper-button-style">
+    <custom-style>
+      <style is="custom-style" include="signin-dialog-shared paper-button-style">
 <if expr="is_macosx or is_linux">
-      #undoButton {
-        margin-inline-end: 8px;
-        margin-inline-start: 0;
-      }
+        #undoButton {
+          margin-inline-end: 8px;
+          margin-inline-start: 0;
+        }
 </if>
-    </style>
+      </style>
+    </custom-style>
   </head>
   <body>
     <!--
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html b/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html
index 4652da4..26311cc 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html
@@ -6,16 +6,6 @@
 <dom-module id="nux-email">
   <template>
     <style>
-      :host-context(#viewManager):host([slot='view']) {
-        /* Unsets cr-view-manager's styling to make all views full-page, and
-           allows the content to be centered horizontally/vertically on the
-           page. */
-        bottom: initial;
-        left: initial;
-        right: initial;
-        top: initial;
-      }
-
       .email-ask {
         text-align: center;
       }
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.html b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.html
index 43f6569..530c9c5 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.html
@@ -10,16 +10,6 @@
 <dom-module id="nux-google-apps">
   <template>
     <style include="paper-button-style">
-      :host-context(#viewManager):host([slot='view']) {
-        /* Unsets cr-view-manager's styling to make all views full-page, and
-           allows the content to be centered horizontally/vertically on the
-           page. */
-        bottom: initial;
-        left: initial;
-        right: initial;
-        top: initial;
-      }
-
       .apps-ask {
         margin-left: auto;
         margin-right: auto;
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
index 60125a1..ce2222ca 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
@@ -11,16 +11,6 @@
 <dom-module id="nux-set-as-default">
   <template>
     <style include="paper-button-style">
-      :host-context(#viewManager):host([slot='view']) {
-        /* Unsets cr-view-manager's styling to make all views full-page, and
-           allows the content to be centered horizontally/vertically on the
-           page. */
-        bottom: initial;
-        left: initial;
-        right: initial;
-        top: initial;
-      }
-
       .container {
         text-align: center;
         width: 800px;
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.html b/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.html
index 2b7f48c8..36cdaf95 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.html
@@ -20,6 +20,15 @@
         margin: 0;
         min-height: 100vh;
       }
+
+      #viewManager :-webkit-any(nux-email,
+          nux-google-apps, nux-set-as-default) {
+        /* Override cr-view-manager's default styling for view. */
+        bottom: initial;
+        left: initial;
+        right: initial;
+        top: initial;
+      }
     </style>
     <cr-view-manager id="viewManager">
       <landing-view id="step-landing" slot="view" class="active"></landing-view>
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
index 9783bcd..31012c5 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -44,6 +44,7 @@
 
 // The number of user gestures we trace back for download attribution.
 const int kDownloadAttributionUserGestureLimit = 2;
+const int kDownloadAttributionUserGestureLimitForExtendedReporting = 5;
 
 void AddEventUrlToReferrerChain(const download::DownloadItem& item,
                                 ReferrerChain* out_referrer_chain) {
@@ -74,6 +75,26 @@
   return false;
 }
 
+int GetDownloadAttributionUserGestureLimit(const download::DownloadItem& item) {
+  content::WebContents* web_contents =
+      content::DownloadItemUtils::GetWebContents(
+          const_cast<download::DownloadItem*>(&item));
+  if (!web_contents)
+    return kDownloadAttributionUserGestureLimit;
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  if (!profile)
+    return kDownloadAttributionUserGestureLimit;
+
+  const PrefService* prefs = profile->GetPrefs();
+  if (!prefs)
+    return kDownloadAttributionUserGestureLimit;
+  if (!IsExtendedReportingEnabled(*prefs))
+    return kDownloadAttributionUserGestureLimit;
+  return kDownloadAttributionUserGestureLimitForExtendedReporting;
+}
+
 }  // namespace
 
 const void* const DownloadProtectionService::kDownloadPingTokenKey =
@@ -426,8 +447,8 @@
   // We look for the referrer chain that leads to the download url first.
   SafeBrowsingNavigationObserverManager::AttributionResult result =
       navigation_observer_manager_->IdentifyReferrerChainByEventURL(
-          item.GetURL(), download_tab_id, kDownloadAttributionUserGestureLimit,
-          referrer_chain.get());
+          item.GetURL(), download_tab_id,
+          GetDownloadAttributionUserGestureLimit(item), referrer_chain.get());
 
   // If no navigation event is found, this download is not triggered by regular
   // navigation (e.g. html5 file apis, etc). We look for the referrer chain
@@ -437,7 +458,7 @@
       web_contents && web_contents->GetLastCommittedURL().is_valid()) {
     AddEventUrlToReferrerChain(item, referrer_chain.get());
     result = navigation_observer_manager_->IdentifyReferrerChainByWebContents(
-        web_contents, kDownloadAttributionUserGestureLimit,
+        web_contents, GetDownloadAttributionUserGestureLimit(item),
         referrer_chain.get());
   }
 
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.h b/chrome/browser/safe_browsing/download_protection/download_protection_service.h
index dffff24..061445c 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.h
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.h
@@ -194,12 +194,14 @@
                            PPAPIDownloadRequest_InvalidResponse);
   FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
                            PPAPIDownloadRequest_Timeout);
-  FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
-                           VerifyReferrerChainWithEmptyNavigationHistory);
   FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceFlagTest,
                            CheckClientDownloadOverridenByFlag);
   FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
                            VerifyMaybeSendDangerousDownloadOpenedReport);
+  FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
+                           VerifyReferrerChainWithEmptyNavigationHistory);
+  FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
+                           VerifyReferrerChainLengthForExtendedReporting);
 
   static const void* const kDownloadPingTokenKey;
 
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
index 2556e5e..36e9a2c 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -37,6 +37,7 @@
 #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
 #include "chrome/browser/safe_browsing/download_protection/ppapi_download_request.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/test_extension_event_observer.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
@@ -45,6 +46,7 @@
 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
 #include "chrome/common/safe_browsing/file_type_policies_test_util.h"
 #include "chrome/common/safe_browsing/mock_binary_feature_extractor.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/download/public/common/download_danger_type.h"
@@ -61,6 +63,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/download_item_utils.h"
 #include "content/public/browser/page_navigator.h"
+#include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "content/public/test/web_contents_tester.h"
@@ -78,6 +81,9 @@
 #include "third_party/zlib/google/zip.h"
 #include "url/gurl.h"
 
+using base::RunLoop;
+using content::BrowserThread;
+using ::testing::_;
 using ::testing::Assign;
 using ::testing::ContainerEq;
 using ::testing::DoAll;
@@ -89,10 +95,8 @@
 using ::testing::Return;
 using ::testing::ReturnRef;
 using ::testing::SaveArg;
+using ::testing::SizeIs;
 using ::testing::StrictMock;
-using ::testing::_;
-using base::RunLoop;
-using content::BrowserThread;
 
 namespace OnDangerousDownloadOpened =
     extensions::api::safe_browsing_private::OnDangerousDownloadOpened;
@@ -205,22 +209,26 @@
           base::Unretained(arg1), arg0, threat_type));
 }
 
-class DownloadProtectionServiceTest : public testing::Test {
+class DownloadProtectionServiceTest : public ChromeRenderViewHostTestHarness {
  protected:
-  DownloadProtectionServiceTest()
-      : test_browser_thread_bundle_(
-            content::TestBrowserThreadBundle::IO_MAINLOOP) {}
+  DownloadProtectionServiceTest() {}
   void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+
     system_request_context_getter_ =
         base::MakeRefCounted<net::TestURLRequestContextGetter>(
             base::CreateSingleThreadTaskRunnerWithTraits(
                 {content::BrowserThread::IO}));
     TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(
         system_request_context_getter_.get());
+    in_process_utility_thread_helper_ =
+        std::make_unique<content::InProcessUtilityThreadHelper>();
     // Start real threads for the IO and File threads so that the DCHECKs
     // to test that we're on the correct thread work.
     sb_service_ = new StrictMock<FakeSafeBrowsingService>();
     sb_service_->Initialize();
+    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(
+        sb_service_.get());
     binary_feature_extractor_ = new StrictMock<MockBinaryFeatureExtractor>();
     ON_CALL(*binary_feature_extractor_, ExtractImageFeatures(_, _, _, _))
         .WillByDefault(Return(true));
@@ -246,11 +254,8 @@
                          .AppendASCII("safe_browsing")
                          .AppendASCII("download_protection");
 
-    // Setup a profile
-    ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
-    profile_.reset(new TestingProfile(profile_dir_.GetPath()));
-    ASSERT_TRUE(profile_->CreateHistoryService(true /* delete_file */,
-                                               false /* no_db */));
+    ASSERT_TRUE(profile()->CreateHistoryService(true /* delete_file */,
+                                                false /* no_db */));
 
     // Setup a directory to place test files in.
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -259,12 +264,9 @@
     SetBinarySamplingProbability(0.0);
 
     // |test_event_router_| is owned by KeyedServiceFactory.
-    test_event_router_ =
-        extensions::CreateAndUseTestEventRouter(profile_.get());
+    test_event_router_ = extensions::CreateAndUseTestEventRouter(profile());
     extensions::SafeBrowsingPrivateEventRouterFactory::GetInstance()
-        ->SetTestingFactory(
-            profile_.get(),
-            base::BindRepeating(&BuildSafeBrowsingPrivateEventRouter));
+        ->SetTestingFactory(profile(), BuildSafeBrowsingPrivateEventRouter);
   }
 
   void TearDown() override {
@@ -276,7 +278,11 @@
     FlushThreadMessageLoops();
     sb_service_ = NULL;
     TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(nullptr);
+    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(nullptr);
     system_request_context_getter_ = nullptr;
+    in_process_utility_thread_helper_ = nullptr;
+
+    ChromeRenderViewHostTestHarness::TearDown();
   }
 
   void SetWhitelistedDownloadSampleRate(double target_rate) {
@@ -436,11 +442,28 @@
   }
 
   void AddDomainToEnterpriseWhitelist(const std::string& domain) {
-    ListPrefUpdate update(profile_->GetPrefs(),
+    ListPrefUpdate update(profile()->GetPrefs(),
                           prefs::kSafeBrowsingWhitelistDomains);
     update.Get()->AppendString(domain);
   }
 
+  // Helper function to simulate a user gesture, then a link click.
+  // The usual NavigateAndCommit is unsuitable because it creates
+  // browser-initiated navigations, causing us to drop the referrer.
+  // TODO(drubery): This function could be eliminated if we dropped referrer
+  // depending on PageTransition. This could help eliminate edge cases in
+  // browser/renderer navigations.
+  void SimulateLinkClick(const GURL& url) {
+    content::WebContentsTester::For(web_contents())
+        ->TestDidReceiveInputEvent(blink::WebInputEvent::kMouseDown);
+    std::unique_ptr<content::NavigationSimulator> navigation =
+        content::NavigationSimulator::CreateRendererInitiated(
+            url, web_contents()->GetMainFrame());
+
+    navigation->SetTransition(ui::PAGE_TRANSITION_LINK);
+    navigation->Commit();
+  }
+
  private:
   // Helper functions for FlushThreadMessageLoops.
   void RunAllPendingAndQuitUI(const base::Closure& quit_closure) {
@@ -507,7 +530,7 @@
   }
 
   void SetExtendedReportingPreference(bool is_extended_reporting) {
-    SetExtendedReportingPref(profile_->GetPrefs(), is_extended_reporting);
+    SetExtendedReportingPref(profile()->GetPrefs(), is_extended_reporting);
   }
 
   // Verify that corrupted ZIP/DMGs do send a ping.
@@ -523,14 +546,12 @@
   DownloadProtectionService* download_service_;
   DownloadCheckResult result_;
   bool has_result_;
-  content::TestBrowserThreadBundle test_browser_thread_bundle_;
-  content::InProcessUtilityThreadHelper in_process_utility_thread_helper_;
+  std::unique_ptr<content::InProcessUtilityThreadHelper>
+      in_process_utility_thread_helper_;
   base::FilePath testdata_path_;
   ClientDownloadRequestSubscription client_download_request_subscription_;
   PPAPIDownloadRequestSubscription ppapi_download_request_subscription_;
   std::unique_ptr<ClientDownloadRequest> last_client_download_request_;
-  base::ScopedTempDir profile_dir_;
-  std::unique_ptr<TestingProfile> profile_;
   // The following 5 fields are used by PrepareBasicDownloadItem() function to
   // store attributes of the last download item. They can be modified
   // afterwards and the *item will return the new values.
@@ -767,7 +788,7 @@
     //           ClientDownloadRequest should NOT be sent.
     SetExtendedReportingPreference(true);
     content::DownloadItemUtils::AttachInfo(
-        &item, profile_->GetOffTheRecordProfile(), nullptr);
+        &item, profile()->GetOffTheRecordProfile(), nullptr);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -781,7 +802,7 @@
     //           ClientDownloadRequest should NOT be sent.
     SetExtendedReportingPreference(false);
     content::DownloadItemUtils::AttachInfo(
-        &item, profile_->GetOffTheRecordProfile(), nullptr);
+        &item, profile()->GetOffTheRecordProfile(), nullptr);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -793,7 +814,7 @@
   {
     // Case (3): !is_extended_reporting && !is_incognito.
     //           ClientDownloadRequest should NOT be sent.
-    content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+    content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -807,7 +828,7 @@
     //           Download matches URL whitelist.
     //           ClientDownloadRequest should be sent.
     SetExtendedReportingPreference(true);
-    content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+    content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -836,7 +857,7 @@
     // Case (5): is_extended_reporting && !is_incognito &&
     //           Download matches certificate whitelist.
     //           ClientDownloadRequest should be sent.
-    content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+    content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
     EXPECT_CALL(
         *sb_service_->mock_database_manager(),
         MatchDownloadWhitelistUrl(GURL("http://www.whitelist.com/a.exe")))
@@ -856,7 +877,7 @@
     // Case (6): is_extended_reporting && !is_incognito &&
     //           Download matches both URL and certificate whitelists.
     //           ClientDownloadRequest should be sent.
-    content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+    content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
     EXPECT_CALL(
         *sb_service_->mock_database_manager(),
         MatchDownloadWhitelistUrl(GURL("http://www.whitelist.com/a.exe")))
@@ -906,7 +927,7 @@
     //           ClientDownloadRequest should NOT be sent.
     SetExtendedReportingPreference(true);
     content::DownloadItemUtils::AttachInfo(
-        &item, profile_->GetOffTheRecordProfile(), nullptr);
+        &item, profile()->GetOffTheRecordProfile(), nullptr);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -918,7 +939,7 @@
   {
     // Case (2): is_extended_reporting && !is_incognito.
     //           A "light" ClientDownloadRequest should be sent.
-    content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+    content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -944,7 +965,7 @@
     //           ClientDownloadRequest should NOT be sent.
     SetExtendedReportingPreference(false);
     content::DownloadItemUtils::AttachInfo(
-        &item, profile_->GetOffTheRecordProfile(), nullptr);
+        &item, profile()->GetOffTheRecordProfile(), nullptr);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -956,7 +977,7 @@
   {
     // Case (4): !is_extended_reporting && !is_incognito.
     //           ClientDownloadRequest should NOT be sent.
-    content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+    content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -1849,7 +1870,7 @@
   EXPECT_CALL(item, GetTabReferrerUrl())
       .WillRepeatedly(ReturnRef(tab_referrer));
   EXPECT_CALL(item, GetRemoteAddress()).WillRepeatedly(Return(remote_address));
-  content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+  content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
   EXPECT_CALL(*sb_service_->mock_database_manager(),
               MatchDownloadWhitelistUrl(_))
       .WillRepeatedly(Return(false));
@@ -1935,7 +1956,7 @@
     redirects.push_back(GURL("http://tab.com/ref1"));
     redirects.push_back(GURL("http://tab.com/ref2"));
     redirects.push_back(tab_url);
-    HistoryServiceFactory::GetForProfile(profile_.get(),
+    HistoryServiceFactory::GetForProfile(profile(),
                                          ServiceAccessType::EXPLICIT_ACCESS)
         ->AddPage(tab_url, base::Time::Now(),
                   reinterpret_cast<history::ContextID>(1), 0, GURL(), redirects,
@@ -2066,10 +2087,8 @@
       FILE_PATH_LITERAL("a.tmp"),   // tmp_path
       FILE_PATH_LITERAL("a.exe"));  // final_path
   std::unique_ptr<content::WebContents> web_contents(
-      content::WebContentsTester::CreateTestWebContents(profile_.get(),
-                                                        nullptr));
-  content::DownloadItemUtils::AttachInfo(&item, profile_.get(),
-                                         web_contents.get());
+      content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
+  content::DownloadItemUtils::AttachInfo(&item, profile(), web_contents.get());
   EXPECT_CALL(*sb_service_->mock_database_manager(), CheckDownloadUrl(_, _))
       .Times(0);
   RunLoop run_loop;
@@ -2088,8 +2107,7 @@
       "http://referrer.com",        // referrer
       FILE_PATH_LITERAL("a.tmp"),   // tmp_path
       FILE_PATH_LITERAL("a.exe"));  // final_path
-  content::DownloadItemUtils::AttachInfo(&item2, profile_.get(),
-                                         web_contents.get());
+  content::DownloadItemUtils::AttachInfo(&item2, profile(), web_contents.get());
   EXPECT_CALL(*sb_service_->mock_database_manager(), CheckDownloadUrl(_, _))
       .Times(0);
   RunLoop run_loop2;
@@ -2332,7 +2350,7 @@
       FILE_PATH_LITERAL(".tmp"), FILE_PATH_LITERAL(".asdfasdf")};
   download_service_->CheckPPAPIDownloadRequest(
       GURL("http://example.com/foo"), GURL(), nullptr, default_file_path,
-      alternate_extensions, profile_.get(),
+      alternate_extensions, profile(),
       base::Bind(&DownloadProtectionServiceTest::SyncCheckDoneCallback,
                  base::Unretained(this)));
   ASSERT_TRUE(IsResult(DownloadCheckResult::SAFE));
@@ -2366,7 +2384,7 @@
     RunLoop run_loop;
     download_service_->CheckPPAPIDownloadRequest(
         GURL("http://example.com/foo"), GURL(), nullptr, default_file_path,
-        alternate_extensions, profile_.get(),
+        alternate_extensions, profile(),
         base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                    base::Unretained(this), run_loop.QuitClosure()));
     run_loop.Run();
@@ -2389,7 +2407,7 @@
   RunLoop run_loop;
   download_service_->CheckPPAPIDownloadRequest(
       GURL("http://example.com/foo"), GURL(), nullptr, default_file_path,
-      alternate_extensions, profile_.get(),
+      alternate_extensions, profile(),
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this), run_loop.QuitClosure()));
   run_loop.Run();
@@ -2409,7 +2427,7 @@
   RunLoop run_loop;
   download_service_->CheckPPAPIDownloadRequest(
       GURL("http://example.com/foo"), GURL(), nullptr, default_file_path,
-      alternate_extensions, profile_.get(),
+      alternate_extensions, profile(),
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this), run_loop.QuitClosure()));
   run_loop.Run();
@@ -2428,7 +2446,7 @@
   RunLoop run_loop;
   download_service_->CheckPPAPIDownloadRequest(
       GURL("http://example.com/foo"), GURL(), nullptr, default_file_path,
-      alternate_extensions, profile_.get(),
+      alternate_extensions, profile(),
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this), run_loop.QuitClosure()));
   run_loop.Run();
@@ -2447,7 +2465,7 @@
   RunLoop run_loop;
   download_service_->CheckPPAPIDownloadRequest(
       GURL("http://example.com/foo"), GURL(), nullptr, default_file_path,
-      alternate_extensions, profile_.get(),
+      alternate_extensions, profile(),
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this), run_loop.QuitClosure()));
   run_loop.Run();
@@ -2467,7 +2485,7 @@
   RunLoop run_loop;
   download_service_->CheckPPAPIDownloadRequest(
       GURL("http://example.com/foo"), GURL(), nullptr, default_file_path,
-      alternate_extensions, profile_.get(),
+      alternate_extensions, profile(),
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this), run_loop.QuitClosure()));
   run_loop.Run();
@@ -2497,7 +2515,7 @@
   RunLoop run_loop;
   download_service_->CheckPPAPIDownloadRequest(
       kRequestorUrl, GURL(), nullptr, default_file_path, alternate_extensions,
-      profile_.get(),
+      profile(),
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this), run_loop.QuitClosure()));
   run_loop.Run();
@@ -2520,15 +2538,14 @@
        PPAPIDownloadRequest_WhitelistedByPolicy) {
   AddDomainToEnterpriseWhitelist("example.com");
   std::unique_ptr<content::WebContents> web_contents(
-      content::WebContentsTester::CreateTestWebContents(profile_.get(),
-                                                        nullptr));
+      content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
 
   base::FilePath default_file_path(FILE_PATH_LITERAL("/foo/bar/test.txt"));
   std::vector<base::FilePath::StringType> alternate_extensions{
       FILE_PATH_LITERAL(".tmp"), FILE_PATH_LITERAL(".asdfasdf")};
   download_service_->CheckPPAPIDownloadRequest(
       GURL("http://example.com/foo"), GURL(), web_contents.get(),
-      default_file_path, alternate_extensions, profile_.get(),
+      default_file_path, alternate_extensions, profile(),
       base::BindRepeating(&DownloadProtectionServiceTest::SyncCheckDoneCallback,
                           base::Unretained(this)));
   ASSERT_TRUE(IsResult(DownloadCheckResult::WHITELISTED_BY_POLICY));
@@ -2542,7 +2559,7 @@
                            "http://www.google.com/",     // referrer
                            FILE_PATH_LITERAL("a.tmp"),   // tmp_path
                            FILE_PATH_LITERAL("a.exe"));  // final_path
-  content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+  content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
   ASSERT_EQ(0, sb_service_->download_report_count());
 
   // No report sent if download item without token field.
@@ -2552,12 +2569,12 @@
   // No report sent if user is in incognito mode.
   DownloadProtectionService::SetDownloadPingToken(&item, "token");
   content::DownloadItemUtils::AttachInfo(
-      &item, profile_->GetOffTheRecordProfile(), nullptr);
+      &item, profile()->GetOffTheRecordProfile(), nullptr);
   download_service_->MaybeSendDangerousDownloadOpenedReport(&item, false);
   EXPECT_EQ(0, sb_service_->download_report_count());
 
   // No report sent if user is not in extended reporting group.
-  content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+  content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
   SetExtendedReportingPreference(false);
   download_service_->MaybeSendDangerousDownloadOpenedReport(&item, false);
   EXPECT_EQ(0, sb_service_->download_report_count());
@@ -2585,7 +2602,7 @@
   EXPECT_CALL(item, GetTargetFilePath()).WillRepeatedly(ReturnRef(target_path));
 
   TestExtensionEventObserver event_observer(test_event_router_);
-  content::DownloadItemUtils::AttachInfo(&item, profile_.get(), nullptr);
+  content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
   download_service_->MaybeSendDangerousDownloadOpenedReport(&item, false);
   ASSERT_EQ(1, test_event_router_->GetEventCount(
                    OnDangerousDownloadOpened::kEventName));
@@ -2599,43 +2616,12 @@
 
   // No event is triggered if in incognito mode..
   content::DownloadItemUtils::AttachInfo(
-      &item, profile_->GetOffTheRecordProfile(), nullptr);
+      &item, profile()->GetOffTheRecordProfile(), nullptr);
   download_service_->MaybeSendDangerousDownloadOpenedReport(&item, false);
   EXPECT_EQ(1, test_event_router_->GetEventCount(
                    OnDangerousDownloadOpened::kEventName));
 }
 
-TEST_F(DownloadProtectionServiceTest,
-       VerifyReferrerChainWithEmptyNavigationHistory) {
-  // Setup a web_contents with "http://example.com" as its last committed url.
-  std::unique_ptr<content::WebContents> web_contents(
-      content::WebContentsTester::CreateTestWebContents(profile_.get(),
-                                                        nullptr));
-  content::WebContentsTester* web_contents_tester =
-      content::WebContentsTester::For(web_contents.get());
-  web_contents_tester->SetLastCommittedURL(GURL("http://example.com"));
-
-  NiceMockDownloadItem item;
-  PrepareBasicDownloadItem(
-      &item, {"http://referrer.com", "http://www.evil.com/a.exe"},  // url_chain
-      "http://example.com/",                                        // referrer
-      FILE_PATH_LITERAL("a.tmp"),                                   // tmp_path
-      FILE_PATH_LITERAL("a.exe"));  // final_path
-  content::DownloadItemUtils::AttachInfo(&item, nullptr, web_contents.get());
-  std::unique_ptr<ReferrerChainData> referrer_chain_data =
-      download_service_->IdentifyReferrerChain(item);
-  ReferrerChain* referrer_chain = referrer_chain_data->GetReferrerChain();
-
-  ASSERT_EQ(1u, referrer_chain_data->referrer_chain_length());
-  EXPECT_EQ(item.GetUrlChain().back(), referrer_chain->Get(0).url());
-  EXPECT_EQ(web_contents->GetLastCommittedURL().spec(),
-            referrer_chain->Get(0).referrer_url());
-  EXPECT_EQ(ReferrerChainEntry::EVENT_URL, referrer_chain->Get(0).type());
-  EXPECT_EQ(static_cast<int>(item.GetUrlChain().size()),
-            referrer_chain->Get(0).server_redirect_chain_size());
-  EXPECT_FALSE(referrer_chain->Get(0).is_retargeting());
-}
-
 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadWhitelistedByPolicy) {
   NiceMockDownloadItem item;
   PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"},  // url_chain
@@ -2669,7 +2655,7 @@
 TEST_F(DownloadProtectionServiceTest, CheckOffTheRecordDoesNotSendFeedback) {
   NiceMockDownloadItem item;
   EXPECT_FALSE(download_service_->MaybeBeginFeedbackForDownload(
-      profile_->GetOffTheRecordProfile(), &item, DownloadCommands::KEEP));
+      profile()->GetOffTheRecordProfile(), &item, DownloadCommands::KEEP));
 }
 
 TEST_F(DownloadProtectionServiceTest,
@@ -2678,7 +2664,7 @@
 
   NiceMockDownloadItem item;
   EXPECT_FALSE(download_service_->MaybeBeginFeedbackForDownload(
-      profile_.get(), &item, DownloadCommands::KEEP));
+      profile(), &item, DownloadCommands::KEEP));
 }
 
 // ------------ class DownloadProtectionServiceFlagTest ----------------
@@ -2763,4 +2749,61 @@
   EXPECT_TRUE(IsResult(DownloadCheckResult::DANGEROUS));
 }
 
+TEST_F(DownloadProtectionServiceTest,
+       VerifyReferrerChainWithEmptyNavigationHistory) {
+  // Setup a web_contents with "http://example.com" as its last committed url.
+  NavigateAndCommit(GURL("http://example.com"));
+
+  NiceMockDownloadItem item;
+  std::vector<GURL> url_chain = {GURL("http://example.com/referrer"),
+                                 GURL("http://example.com/evil.exe")};
+  EXPECT_CALL(item, GetURL()).WillRepeatedly(ReturnRef(url_chain.back()));
+  EXPECT_CALL(item, GetUrlChain()).WillRepeatedly(ReturnRef(url_chain));
+  content::DownloadItemUtils::AttachInfo(&item, nullptr, web_contents());
+  std::unique_ptr<ReferrerChainData> referrer_chain_data =
+      download_service_->IdentifyReferrerChain(item);
+  ReferrerChain* referrer_chain = referrer_chain_data->GetReferrerChain();
+
+  ASSERT_EQ(1u, referrer_chain_data->referrer_chain_length());
+  EXPECT_EQ(item.GetUrlChain().back(), referrer_chain->Get(0).url());
+  EXPECT_EQ(web_contents()->GetLastCommittedURL().spec(),
+            referrer_chain->Get(0).referrer_url());
+  EXPECT_EQ(ReferrerChainEntry::EVENT_URL, referrer_chain->Get(0).type());
+  EXPECT_EQ(static_cast<int>(item.GetUrlChain().size()),
+            referrer_chain->Get(0).server_redirect_chain_size());
+  EXPECT_FALSE(referrer_chain->Get(0).is_retargeting());
+}
+
+TEST_F(DownloadProtectionServiceTest,
+       VerifyReferrerChainLengthForExtendedReporting) {
+  SafeBrowsingNavigationObserver::MaybeCreateForWebContents(web_contents());
+
+  // Simulate 6 user interactions
+  SimulateLinkClick(GURL("http://example.com/0"));
+  SimulateLinkClick(GURL("http://example.com/1"));
+  SimulateLinkClick(GURL("http://example.com/2"));
+  SimulateLinkClick(GURL("http://example.com/3"));
+  SimulateLinkClick(GURL("http://example.com/4"));
+  SimulateLinkClick(GURL("http://example.com/5"));
+  SimulateLinkClick(GURL("http://example.com/evil.exe"));
+
+  NiceMockDownloadItem item;
+  std::vector<GURL> url_chain = {GURL("http://example.com/evil.exe")};
+  EXPECT_CALL(item, GetURL()).WillRepeatedly(ReturnRef(url_chain.back()));
+  EXPECT_CALL(item, GetUrlChain()).WillRepeatedly(ReturnRef(url_chain));
+
+  content::DownloadItemUtils::AttachInfo(&item, nullptr, web_contents());
+
+  SetExtendedReportingPref(profile()->GetPrefs(), true);
+  std::unique_ptr<ReferrerChainData> referrer_chain_data =
+      download_service_->IdentifyReferrerChain(item);
+  // 6 entries means 5 interactions between entries.
+  EXPECT_EQ(referrer_chain_data->referrer_chain_length(), 6u);
+
+  SetExtendedReportingPref(profile()->GetPrefs(), false);
+  referrer_chain_data = download_service_->IdentifyReferrerChain(item);
+  // 3 entries means 2 interactions between entries.
+  EXPECT_EQ(referrer_chain_data->referrer_chain_length(), 3u);
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
index a46cd161..0d5b802 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
@@ -49,7 +49,7 @@
 // Helper function to determine if the URL type should be LANDING_REFERRER or
 // LANDING_PAGE, and modify AttributionResult accordingly.
 ReferrerChainEntry::URLType GetURLTypeAndAdjustAttributionResult(
-    bool at_user_gesture_limit,
+    size_t user_gesture_count,
     SafeBrowsingNavigationObserverManager::AttributionResult* out_result) {
   // Landing page refers to the page user directly interacts with to trigger
   // this event (e.g. clicking on download button). Landing referrer page is the
@@ -57,13 +57,19 @@
   // Since we are tracing navigations backwards, if we've reached
   // user gesture limit before this navigation event, this is a navigation
   // leading to the landing referrer page, otherwise it leads to landing page.
-  if (at_user_gesture_limit) {
+  if (user_gesture_count == 0) {
+    *out_result = SafeBrowsingNavigationObserverManager::SUCCESS;
+    return ReferrerChainEntry::EVENT_URL;
+  } else if (user_gesture_count == 2) {
     *out_result =
         SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_REFERRER;
     return ReferrerChainEntry::LANDING_REFERRER;
-  } else {
+  } else if (user_gesture_count == 1) {
     *out_result = SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_PAGE;
     return ReferrerChainEntry::LANDING_PAGE;
+  } else {
+    *out_result = SafeBrowsingNavigationObserverManager::SUCCESS_REFERRER;
+    return ReferrerChainEntry::REFERRER;
   }
 }
 
@@ -424,8 +430,7 @@
     user_gesture_count = 1;
     AddToReferrerChain(
         out_referrer_chain, nav_event, initiating_main_frame_url,
-        GetURLTypeAndAdjustAttributionResult(
-            user_gesture_count == user_gesture_count_limit, &result));
+        GetURLTypeAndAdjustAttributionResult(user_gesture_count, &result));
   } else {
     AddToReferrerChain(out_referrer_chain, nav_event, initiating_main_frame_url,
                        ReferrerChainEntry::CLIENT_REDIRECT);
@@ -667,11 +672,10 @@
     if (!last_nav_event_traced)
       return;
 
-    AddToReferrerChain(
-        out_referrer_chain, last_nav_event_traced, last_main_frame_url_traced,
-        GetURLTypeAndAdjustAttributionResult(
-            current_user_gesture_count == user_gesture_count_limit,
-            out_result));
+    AddToReferrerChain(out_referrer_chain, last_nav_event_traced,
+                       last_main_frame_url_traced,
+                       GetURLTypeAndAdjustAttributionResult(
+                           current_user_gesture_count, out_result));
     // Stop searching if the size of out_referrer_chain already reached its
     // limit.
     if (out_referrer_chain->size() == kReferrerChainMaxLength)
diff --git a/chrome/browser/ui/ash/DEPS b/chrome/browser/ui/ash/DEPS
index 9086047..1c7d932 100644
--- a/chrome/browser/ui/ash/DEPS
+++ b/chrome/browser/ui/ash/DEPS
@@ -49,6 +49,7 @@
     # https://crbug.com/665064
     "+ash/shell_delegate.h",
   ],
+  # Only used in !mash
   "screen_orientation_delegate_chromeos.cc": [
     "+ash/display/screen_orientation_controller.h",
     "+ash/shell.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 979cc8651..70fc4a2 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
@@ -206,12 +206,8 @@
   if (features::IsUsingWindowService())
     immersive_context_ = std::make_unique<ImmersiveContextMus>();
 
-  // TODO(estade): implement ScreenOrientationDelegateChromeos for Mash and
-  // remove this condition.
-  if (!features::IsUsingWindowService()) {
-    screen_orientation_delegate_ =
-        std::make_unique<ScreenOrientationDelegateChromeos>();
-  }
+  screen_orientation_delegate_ =
+      std::make_unique<ScreenOrientationDelegateChromeos>();
 
   app_list_client_ = std::make_unique<AppListClientImpl>();
 
diff --git a/chrome/browser/ui/ash/login_screen_client.cc b/chrome/browser/ui/ash/login_screen_client.cc
index d2fb0862..c4f7990 100644
--- a/chrome/browser/ui/ash/login_screen_client.cc
+++ b/chrome/browser/ui/ash/login_screen_client.cc
@@ -91,15 +91,24 @@
 void LoginScreenClient::AuthenticateUserWithExternalBinary(
     const AccountId& account_id,
     AuthenticateUserWithExternalBinaryCallback callback) {
-  if (delegate_) {
-    delegate_->HandleAuthenticateUserWithExternalBinary(account_id,
-                                                        std::move(callback));
-    // TODO(jdufault): Record auth method attempt here
-    NOTIMPLEMENTED() << "Missing UMA recording for external binary auth";
-  } else {
-    LOG(ERROR) << "Failed AuthenticateUserWithExternalBinary; no delegate";
-    std::move(callback).Run(false);
-  }
+  if (!delegate_)
+    LOG(FATAL) << "Failed AuthenticateUserWithExternalBinary; no delegate";
+
+  delegate_->HandleAuthenticateUserWithExternalBinary(account_id,
+                                                      std::move(callback));
+  // TODO: Record auth method attempt here
+  NOTIMPLEMENTED() << "Missing UMA recording for external binary auth";
+}
+
+void LoginScreenClient::EnrollUserWithExternalBinary(
+    EnrollUserWithExternalBinaryCallback callback) {
+  if (!delegate_)
+    LOG(FATAL) << "Failed EnrollUserWithExternalBinary; no delegate";
+
+  delegate_->HandleEnrollUserWithExternalBinary(std::move(callback));
+
+  // TODO: Record enrollment attempt here
+  NOTIMPLEMENTED() << "Missing UMA recording for external binary enrollment";
 }
 
 void LoginScreenClient::AuthenticateUserWithEasyUnlock(
diff --git a/chrome/browser/ui/ash/login_screen_client.h b/chrome/browser/ui/ash/login_screen_client.h
index df22aa0a..195ec050 100644
--- a/chrome/browser/ui/ash/login_screen_client.h
+++ b/chrome/browser/ui/ash/login_screen_client.h
@@ -14,6 +14,8 @@
     ash::mojom::LoginScreenClient::AuthenticateUserWithPasswordOrPinCallback;
 using AuthenticateUserWithExternalBinaryCallback =
     ash::mojom::LoginScreenClient::AuthenticateUserWithExternalBinaryCallback;
+using EnrollUserWithExternalBinaryCallback =
+    ash::mojom::LoginScreenClient::EnrollUserWithExternalBinaryCallback;
 
 namespace chromeos {
 class LoginAuthRecorder;
@@ -36,6 +38,8 @@
     virtual void HandleAuthenticateUserWithExternalBinary(
         const AccountId& account_id,
         AuthenticateUserWithExternalBinaryCallback callback) = 0;
+    virtual void HandleEnrollUserWithExternalBinary(
+        EnrollUserWithExternalBinaryCallback) = 0;
     virtual void HandleAuthenticateUserWithEasyUnlock(
         const AccountId& account_id) = 0;
     virtual void HandleHardlockPod(const AccountId& account_id) = 0;
@@ -78,6 +82,8 @@
   void AuthenticateUserWithExternalBinary(
       const AccountId& account_id,
       AuthenticateUserWithExternalBinaryCallback callback) override;
+  void EnrollUserWithExternalBinary(
+      EnrollUserWithExternalBinaryCallback callback) override;
   void AuthenticateUserWithEasyUnlock(const AccountId& account_id) override;
   void HardlockPod(const AccountId& account_id) override;
   void RecordClickOnLockIcon(const AccountId& account_id) override;
diff --git a/chrome/browser/ui/ash/screen_orientation_delegate_chromeos.cc b/chrome/browser/ui/ash/screen_orientation_delegate_chromeos.cc
index 716400b..24ffdd3 100644
--- a/chrome/browser/ui/ash/screen_orientation_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/screen_orientation_delegate_chromeos.cc
@@ -4,40 +4,55 @@
 
 #include "chrome/browser/ui/ash/screen_orientation_delegate_chromeos.h"
 
-#include "ash/display/screen_orientation_controller.h"  // mash-ok
-#include "ash/shell.h"                                  // mash-ok
+#include "ash/display/screen_orientation_controller.h"
+#include "ash/public/interfaces/constants.mojom.h"
+#include "ash/shell.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "ui/aura/mus/window_mus.h"
+#include "ui/aura/mus/window_tree_client.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/views/mus/desktop_window_tree_host_mus.h"
+#include "ui/views/mus/mus_client.h"
 
 namespace {
 
-ash::OrientationLockType ToAshOrientationLockType(
+ash::mojom::OrientationLockType ToAshOrientationLockType(
     blink::WebScreenOrientationLockType blink_orientation_lock) {
   switch (blink_orientation_lock) {
     case blink::kWebScreenOrientationLockDefault:
     case blink::kWebScreenOrientationLockAny:
-      return ash::OrientationLockType::kAny;
+      return ash::mojom::OrientationLockType::kAny;
     case blink::kWebScreenOrientationLockPortrait:
-      return ash::OrientationLockType::kPortrait;
+      return ash::mojom::OrientationLockType::kPortrait;
     case blink::kWebScreenOrientationLockPortraitPrimary:
-      return ash::OrientationLockType::kPortraitPrimary;
+      return ash::mojom::OrientationLockType::kPortraitPrimary;
     case blink::kWebScreenOrientationLockPortraitSecondary:
-      return ash::OrientationLockType::kPortraitSecondary;
+      return ash::mojom::OrientationLockType::kPortraitSecondary;
     case blink::kWebScreenOrientationLockLandscape:
-      return ash::OrientationLockType::kLandscape;
+      return ash::mojom::OrientationLockType::kLandscape;
     case blink::kWebScreenOrientationLockLandscapePrimary:
-      return ash::OrientationLockType::kLandscapePrimary;
+      return ash::mojom::OrientationLockType::kLandscapePrimary;
     case blink::kWebScreenOrientationLockLandscapeSecondary:
-      return ash::OrientationLockType::kLandscapeSecondary;
+      return ash::mojom::OrientationLockType::kLandscapeSecondary;
     case blink::kWebScreenOrientationLockNatural:
-      return ash::OrientationLockType::kNatural;
+      return ash::mojom::OrientationLockType::kNatural;
   }
-  return ash::OrientationLockType::kAny;
+  return ash::mojom::OrientationLockType::kAny;
 }
 
 }  // namespace
 
 ScreenOrientationDelegateChromeos::ScreenOrientationDelegateChromeos() {
+  if (features::IsUsingWindowService()) {
+    ash_window_manager_ =
+        views::MusClient::Get()
+            ->window_tree_client()
+            ->BindWindowManagerInterface<ash::mojom::AshWindowManager>();
+  }
+
   content::WebContents::SetScreenOrientationDelegate(this);
 }
 
@@ -53,9 +68,16 @@
 void ScreenOrientationDelegateChromeos::Lock(
     content::WebContents* web_contents,
     blink::WebScreenOrientationLockType orientation_lock) {
-  ash::Shell::Get()->screen_orientation_controller()->LockOrientationForWindow(
-      web_contents->GetNativeView(),
-      ToAshOrientationLockType(orientation_lock));
+  if (features::IsUsingWindowService()) {
+    ash_window_manager_->LockOrientation(
+        aura::WindowMus::Get(web_contents->GetNativeView())->server_id(),
+        ToAshOrientationLockType(orientation_lock));
+  } else {
+    ash::Shell::Get()
+        ->screen_orientation_controller()
+        ->LockOrientationForWindow(web_contents->GetNativeView(),
+                                   ToAshOrientationLockType(orientation_lock));
+  }
 }
 
 bool ScreenOrientationDelegateChromeos::ScreenOrientationProviderSupported() {
@@ -65,7 +87,12 @@
 
 void ScreenOrientationDelegateChromeos::Unlock(
     content::WebContents* web_contents) {
-  ash::Shell::Get()
-      ->screen_orientation_controller()
-      ->UnlockOrientationForWindow(web_contents->GetNativeView());
+  if (features::IsUsingWindowService()) {
+    ash_window_manager_->UnlockOrientation(
+        aura::WindowMus::Get(web_contents->GetNativeView())->server_id());
+  } else {
+    ash::Shell::Get()
+        ->screen_orientation_controller()
+        ->UnlockOrientationForWindow(web_contents->GetNativeView());
+  }
 }
diff --git a/chrome/browser/ui/ash/screen_orientation_delegate_chromeos.h b/chrome/browser/ui/ash/screen_orientation_delegate_chromeos.h
index 5bba1789e..61ee5ac1 100644
--- a/chrome/browser/ui/ash/screen_orientation_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/screen_orientation_delegate_chromeos.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_UI_ASH_SCREEN_ORIENTATION_DELEGATE_CHROMEOS_H_
 #define CHROME_BROWSER_UI_ASH_SCREEN_ORIENTATION_DELEGATE_CHROMEOS_H_
 
+#include "ash/public/interfaces/ash_window_manager.mojom.h"
 #include "content/public/browser/screen_orientation_delegate.h"
 
-// Chrome OS implementation for screen orientation JS api. TODO(estade):
-// implement for Mash.
+// Chrome OS implementation for screen orientation JS api.
 class ScreenOrientationDelegateChromeos
     : public content::ScreenOrientationDelegate {
  public:
@@ -23,6 +23,8 @@
   bool ScreenOrientationProviderSupported() override;
   void Unlock(content::WebContents* web_contents) override;
 
+  ash::mojom::AshWindowManagerAssociatedPtr ash_window_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(ScreenOrientationDelegateChromeos);
 };
 
diff --git a/chrome/browser/ui/ash/screen_orientation_delegate_chromeos_browsertest.cc b/chrome/browser/ui/ash/screen_orientation_delegate_chromeos_browsertest.cc
new file mode 100644
index 0000000..6b0d382
--- /dev/null
+++ b/chrome/browser/ui/ash/screen_orientation_delegate_chromeos_browsertest.cc
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "ui/base/ui_base_features.h"
+
+using ScreenOrientationDelegateChromeosTest = InProcessBrowserTest;
+
+// Tests that an orientation delegate is created and set. Regression test for
+// https://crbug.com/889981
+IN_PROC_BROWSER_TEST_F(ScreenOrientationDelegateChromeosTest, Basic) {
+  EXPECT_NE(nullptr, content::GetScreenOrientationDelegate());
+}
diff --git a/chrome/browser/ui/cocoa/main_menu_builder.mm b/chrome/browser/ui/cocoa/main_menu_builder.mm
index 5e129e8..5fb085a 100644
--- a/chrome/browser/ui/cocoa/main_menu_builder.mm
+++ b/chrome/browser/ui/cocoa/main_menu_builder.mm
@@ -55,10 +55,10 @@
                     .action(@selector(hide:)),
                 Item(IDS_HIDE_OTHERS_MAC)
                     .action(@selector(hideOtherApplications:))
-                    .remove_if(is_pwa),
+                    .key_equivalent(@"h", NSEventModifierFlagCommand |
+                                              NSEventModifierFlagOption),
                 Item(IDS_SHOW_ALL_MAC)
-                    .action(@selector(unhideAllApplications:))
-                    .remove_if(is_pwa),
+                    .action(@selector(unhideAllApplications:)),
                 Item().is_separator(),
                 Item(IDS_CONFIRM_TO_QUIT_OPTION)
                     .target(app_delegate)
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
index 7e025e2..371aa6d 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
@@ -65,6 +65,9 @@
     } else if (GetParam() == FeatureTestState::kEnabledWithUI) {
       feature_list_.InitAndEnableFeature(
           features::kLookalikeUrlNavigationSuggestions);
+    } else {
+      feature_list_.InitAndDisableFeature(
+          features::kLookalikeUrlNavigationSuggestions);
     }
     InProcessBrowserTest::SetUp();
   }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 832d331..ec4cff68 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1086,19 +1086,9 @@
     return;
 #endif
 
-  // Temporarily reveal the top-of-window views (if not already revealed) so
-  // that the location bar view is visible and is considered focusable. If the
-  // location bar view gains focus, |immersive_mode_controller_| will keep the
-  // top-of-window views revealed.
-  std::unique_ptr<ImmersiveRevealedLock> focus_reveal_lock(
-      immersive_mode_controller_->GetRevealedLock(
-          ImmersiveModeController::ANIMATE_REVEAL_YES));
-
   LocationBarView* location_bar = GetLocationBarView();
-  if (location_bar->omnibox_view()->IsFocusable()) {
-    // Location bar got focus.
-    location_bar->FocusLocation(select_all);
-  } else {
+  location_bar->FocusLocation(select_all);
+  if (!location_bar->omnibox_view()->HasFocus()) {
     // If none of location bar got focus, then clear focus.
     views::FocusManager* focus_manager = GetFocusManager();
     DCHECK(focus_manager);
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 6587a7f..9460e0258 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -1003,7 +1003,9 @@
 OmniboxTint LocationBarView::GetTint() {
   ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile());
   if (theme_service->UsingDefaultTheme()) {
-    return profile()->GetProfileType() == Profile::INCOGNITO_PROFILE
+    bool is_dark_mode = GetNativeTheme()->SystemDarkModeEnabled();
+    return profile()->GetProfileType() == Profile::INCOGNITO_PROFILE ||
+                   is_dark_mode
                ? OmniboxTint::DARK
                : OmniboxTint::LIGHT;
   }
@@ -1149,11 +1151,18 @@
 }
 
 void LocationBarView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  RefreshBackground();
+  RefreshFocusRing();
+}
+
+bool LocationBarView::GetNeedsNotificationWhenVisibleBoundsChange() const {
+  return true;
+}
+
+void LocationBarView::OnVisibleBoundsChanged() {
   OmniboxPopupView* popup = GetOmniboxPopupView();
   if (popup->IsOpen())
     popup->UpdatePopupAppearance();
-  RefreshBackground();
-  RefreshFocusRing();
 }
 
 void LocationBarView::OnFocus() {
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index ff727b4..ee22dbb 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -262,6 +262,8 @@
   // |is_hovering| should be true when mouse is in omnibox; false when exited.
   void OnOmniboxHovered(bool is_hovering);
 
+  Browser* browser() { return browser_; }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(SecurityIndicatorTest, CheckIndicatorText);
   FRIEND_TEST_ALL_PREFIXES(TouchLocationBarViewBrowserTest,
@@ -357,6 +359,8 @@
   // views::View:
   const char* GetClassName() const override;
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+  bool GetNeedsNotificationWhenVisibleBoundsChange() const override;
+  void OnVisibleBoundsChanged() override;
   void OnFocus() override;
   void OnPaintBorder(gfx::Canvas* canvas) override;
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index f79491b..3ffaa3b 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/ui/omnibox/omnibox_theme.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
 #include "chrome/grit/generated_resources.h"
@@ -314,6 +315,15 @@
 }
 
 void OmniboxViewViews::SetFocus() {
+  // Temporarily reveal the top-of-window views (if not already revealed) so
+  // that the location bar view is visible and is considered focusable. When it
+  // actually receives focus, ImmersiveFocusWatcher will add another lock to
+  // keep it revealed.
+  std::unique_ptr<ImmersiveRevealedLock> focus_reveal_lock(
+      BrowserView::GetBrowserViewForBrowser(location_bar_view_->browser())
+          ->immersive_mode_controller()
+          ->GetRevealedLock(ImmersiveModeController::ANIMATE_REVEAL_YES));
+
   RequestFocus();
   // Restore caret visibility if focus is explicitly requested. This is
   // necessary because if we already have invisible focus, the RequestFocus()
diff --git a/chrome/browser/vr/PRESUBMIT.py b/chrome/browser/vr/PRESUBMIT.py
index c0b455f1..69da4ae1 100644
--- a/chrome/browser/vr/PRESUBMIT.py
+++ b/chrome/browser/vr/PRESUBMIT.py
@@ -39,28 +39,3 @@
   results = []
   results.extend(_CheckChangeLintsClean(input_api, output_api))
   return results
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, the WebGL 2.0 conformance tests) in addition
-  to the regular CQ try bots. This test suite is too large to run
-  against all Chromium commits, but should be run against changes
-  likely to affect these tests.
-
-  Also, it compiles the Linux VR tryserver to compile the UI testapp.
-
-  When adding/removing tests here, ensure that both gpu/PRESUBMIT.py and
-  ui/gl/PRESUBMIT.py are updated.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_optional_gpu_tests_rel',
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win_optional_gpu_tests_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-      'luci.chromium.try:linux_vr',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 4c6571c..a2af922 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -660,7 +660,7 @@
 // Enable showing a tab-modal dialog while a Web Authentication API request is
 // pending, to help guide the user through the flow of using their security key.
 const base::Feature kWebAuthenticationUI{"WebAuthenticationUI",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
+                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
 #if !defined(OS_ANDROID)
 // Allow capturing of WebRTC event logs, and uploading of those logs to Crash.
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 6f1ab72..a5816f4 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -523,10 +523,6 @@
     "dependencies": ["permission:idltest"],
     "contexts": ["blessed_extension"]
   },
-  "inlineInstallPrivate": {
-    "dependencies": ["permission:inlineInstallPrivate"],
-    "contexts": ["blessed_extension"]
-  },
   "input.ime": {
     "dependencies": ["permission:input"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index fcb1742..013ccbd 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -651,15 +651,6 @@
       "0136FCB13DB29FD5CD442F56E59E53B61F1DF96F"   // http://crbug.com/642141
     ]
   },
-  "inlineInstallPrivate": {
-    "channel": "dev",
-    "extension_types": ["platform_app"],
-    "whitelist": [
-      "8076E9E4DA0DF53B33BFAF0454D3C3B898F93273", // Test Extension
-      "3A78E13285C1949EF84AA85E3BF65D1E83A3D9AB", // Test Extension
-      "4477F0B4FE934D0A8C88922C0986DA7B25D881E1"  // API Test
-    ]
-  },
   "resourcesPrivate": {
     "channel": "stable",
     "extension_types": [
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index a10fa68d..4c035694 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -44,7 +44,6 @@
   "identity.idl",
   "identity_private.idl",
   "image_writer_private.idl",
-  "inline_install_private.idl",
   "instance_id.json",
   "language_settings_private.idl",
   "manifest_types.json",
diff --git a/chrome/common/extensions/api/inline_install_private.idl b/chrome/common/extensions/api/inline_install_private.idl
deleted file mode 100644
index 70af8c0..0000000
--- a/chrome/common/extensions/api/inline_install_private.idl
+++ /dev/null
@@ -1,18 +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.
-
-// Private API to initiate inline install flow of other apps.
-namespace inlineInstallPrivate {
-
-  // This returns a developer-readable error message in error and
-  // a string error code in errorCode (see $ref:webstore.ErrorCode)
-  callback ResultCallback = void (DOMString error,
-                                  DOMString errorCode);
-
-  interface Functions {
-    // This can currently only be used to install apps, but not extensions.
-    static void install(DOMString id,
-                        optional ResultCallback callback);
-  };
-};
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 1b00341..69ecf6fe 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -162,7 +162,6 @@
      APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermission::kFirstRunPrivate, "firstRunPrivate",
      APIPermissionInfo::kFlagCannotBeOptional},
-    {APIPermission::kInlineInstallPrivate, "inlineInstallPrivate"},
     {APIPermission::kSettingsPrivate, "settingsPrivate",
      APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermission::kAutofillPrivate, "autofillPrivate",
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 9f24265..f47cc77 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -764,7 +764,6 @@
   skip.insert(APIPermission::kGcm);
   skip.insert(APIPermission::kIdle);
   skip.insert(APIPermission::kImeWindowEnabled);
-  skip.insert(APIPermission::kInlineInstallPrivate);
   skip.insert(APIPermission::kIdltest);
   skip.insert(APIPermission::kOverrideEscFullscreen);
   skip.insert(APIPermission::kPointerLock);
diff --git a/chrome/installer/mac/BUILD.gn b/chrome/installer/mac/BUILD.gn
index da4b09d2..106fddd 100644
--- a/chrome/installer/mac/BUILD.gn
+++ b/chrome/installer/mac/BUILD.gn
@@ -13,10 +13,6 @@
     ":make_signers",
     "app:mac_installer_app",
   ]
-
-  if (is_chrome_branded) {
-    public_deps += [ ":keychain_reauthorizers" ]
-  }
 }
 
 _packaging_dir = "$root_out_dir/$chrome_product_full_name Packaging"
@@ -118,18 +114,3 @@
     "$_packaging_dir/{{source_file_part}}",
   ]
 }
-
-if (is_chrome_branded) {
-  copy("keychain_reauthorizers") {
-    visibility = [ ":mac" ]
-
-    sources = [
-      "internal/keychain_reauthorizers/com.google.Chrome",
-      "internal/keychain_reauthorizers/com.google.Chrome.canary",
-    ]
-
-    outputs = [
-      "$_packaging_dir/keychain_reauthorizers/{{source_file_part}}",
-    ]
-  }
-}
diff --git a/chrome/installer/mac/dmgdiffer.sh b/chrome/installer/mac/dmgdiffer.sh
index 257f49c..dbdeb9b 100755
--- a/chrome/installer/mac/dmgdiffer.sh
+++ b/chrome/installer/mac/dmgdiffer.sh
@@ -243,18 +243,6 @@
     exit 13
   fi
 
-  local patch_keychain_reauthorize_dir="${patch_fs}/.keychain_reauthorize"
-  if ! mkdir "${patch_keychain_reauthorize_dir}"; then
-    err "could not mkdir patch_keychain_reauthorize_dir"
-    exit 13
-  fi
-
-  if ! cp -p "${SCRIPT_DIR}/keychain_reauthorizers/${old_app_bundleid}" \
-             "${patch_keychain_reauthorize_dir}/${old_app_bundleid}"; then
-    err "could not copy keychain_reauthorize"
-    exit 13
-  fi
-
   local patch_dotpatch_dir="${patch_fs}/.patch"
   if ! mkdir "${patch_dotpatch_dir}"; then
     err "could not mkdir patch_dotpatch_dir"
diff --git a/chrome/installer/mac/sign_app.sh.in b/chrome/installer/mac/sign_app.sh.in
index 4383c82..bfe841d 100644
--- a/chrome/installer/mac/sign_app.sh.in
+++ b/chrome/installer/mac/sign_app.sh.in
@@ -24,21 +24,24 @@
 ME="$(basename "${0}")"
 readonly ME
 
-if [[ ${#} -ne 5 && ${#} -ne 6 ]]; then
+if [[ ${#} -eq 4 || ${#} -eq 6 ]]; then
+  app_path="${1}"
+  codesign_keychain="${2}"
+  codesign_id="${3}"
+  if [[ "${4}" == "--development" || "${6}" == "--development" ]]; then
+    is_development=1
+  fi
+elif [[ ${#} -ne 5 ]]; then
   echo "usage: ${ME} app_path codesign_keychain codesign_id \
-provisioning_profile entitlements_plist [--development]" >& 2
+provisioning_profile entitlements_plist" >& 2
   exit 1
-fi
-
-app_path="${1}"
-codesign_keychain="${2}"
-codesign_id="${3}"
-provisioning_profile="${4}"
-entitlements_plist="${5}"
-is_development=
-
-if [[ ${#} == 6 && "${6}" == "--development" ]]; then
-  is_development=1
+else
+  app_path="${1}"
+  codesign_keychain="${2}"
+  codesign_id="${3}"
+  provisioning_profile="${4}"
+  entitlements_plist="${5}"
+  is_development=0
 fi
 
 script_dir="$(dirname "${0}")"
@@ -59,7 +62,9 @@
 app_mode_loader="${app_mode_loader_app}/Contents/MacOS/app_mode_loader"
 
 # Embed the supplied provisioning profile.
-cp "${provisioning_profile}" "${contents_dir}/embedded.provisionprofile"
+if [[ -z "${is_development}" ]]; then
+  cp "${provisioning_profile}" "${contents_dir}/embedded.provisionprofile"
+fi
 
 requirement="\
 designated => \
@@ -75,9 +80,9 @@
   "${browser_app}"
   --options "${enforcement_flags_app}"
   --resource-rules "${browser_app_rules}"
-  --entitlements "${entitlements_plist}"
 )
 if [[ -z "${is_development}" ]]; then
+  codesign_cmd+=(--entitlements="${entitlements_plist}")
   codesign_cmd+=( -r="${requirement}" )
 fi
 "${codesign_cmd[@]}"
diff --git a/chrome/installer/mac/variables.sh b/chrome/installer/mac/variables.sh
index 3cb206fd..cb07976 100644
--- a/chrome/installer/mac/variables.sh
+++ b/chrome/installer/mac/variables.sh
@@ -19,6 +19,5 @@
 # contains the hash of the certificate used to sign Chrome. When transitioning
 # signing certs, this may include the hash of both the old and new certificate.
 requirement_suffix="\
-and (certificate leaf = H\"85cee8254216185620ddc8851c7a9fc4dfe120ef\" or \
-certificate leaf = H\"c9a99324ca3fcb23dbcc36bd5fd4f9753305130a\") \
+and certificate leaf = H\"c9a99324ca3fcb23dbcc36bd5fd4f9753305130a\" \
 "
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 943056d..13962d2 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1266,7 +1266,6 @@
         "../browser/extensions/api/image_writer_private/image_writer_private_apitest.cc",
         "../browser/extensions/api/image_writer_private/test_utils.cc",
         "../browser/extensions/api/image_writer_private/test_utils.h",
-        "../browser/extensions/api/inline_install_private/inline_install_private_apitest.cc",
         "../browser/extensions/api/input_ime/input_ime_apitest_chromeos.cc",
         "../browser/extensions/api/instance_id/instance_id_apitest.cc",
         "../browser/extensions/api/management/management_api_browsertest.cc",
@@ -1792,6 +1791,7 @@
         "../browser/ui/ash/multi_user/test_multi_user_window_manager.cc",
         "../browser/ui/ash/multi_user/test_multi_user_window_manager.h",
         "../browser/ui/ash/network/networking_config_chromeos_browsertest.cc",
+        "../browser/ui/ash/screen_orientation_delegate_chromeos_browsertest.cc",
         "../browser/ui/ash/shelf_browsertest.cc",
         "../browser/ui/ash/system_tray_client_browsertest.cc",
         "../browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc",
@@ -2572,6 +2572,7 @@
     "../browser/policy/browser_dm_token_storage_mac_unittest.cc",
     "../browser/policy/browser_dm_token_storage_unittest.cc",
     "../browser/policy/browser_dm_token_storage_win_unittest.cc",
+    "../browser/policy/chrome_browser_policy_connector_unittest.cc",
     "../browser/policy/cloud/cloud_policy_invalidator_unittest.cc",
     "../browser/policy/cloud/cloud_policy_test_utils.cc",
     "../browser/policy/cloud/cloud_policy_test_utils.h",
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 7a4d767b..be24024 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -59,6 +59,10 @@
 
 const char kWindowHandlePrefix[] = "CDwindow-";
 
+std::string WebViewIdToWindowHandle(const std::string& web_view_id) {
+  return kWindowHandlePrefix + web_view_id;
+}
+
 bool WindowHandleToWebViewId(const std::string& window_handle,
                              std::string* web_view_id) {
   if (!base::StartsWith(window_handle, kWindowHandlePrefix,
@@ -83,10 +87,6 @@
 
 }  // namespace
 
-std::string WebViewIdToWindowHandle(const std::string& web_view_id) {
-  return kWindowHandlePrefix + web_view_id;
-}
-
 InitSessionParams::InitSessionParams(
     scoped_refptr<URLRequestContextGetter> context_getter,
     const SyncWebSocketFactory& socket_factory,
@@ -467,6 +467,18 @@
   return Status(kOk);
 }
 
+Status ExecuteGetCurrentWindowHandle(Session* session,
+                                     const base::DictionaryValue& params,
+                                     std::unique_ptr<base::Value>* value) {
+  WebView* web_view = NULL;
+  Status status = session->GetTargetWindow(&web_view);
+  if (status.IsError())
+    return status;
+
+  value->reset(new base::Value(WebViewIdToWindowHandle(web_view->GetId())));
+  return Status(kOk);
+}
+
 Status ExecuteLaunchApp(Session* session,
                         const base::DictionaryValue& params,
                         std::unique_ptr<base::Value>* value) {
diff --git a/chrome/test/chromedriver/session_commands.h b/chrome/test/chromedriver/session_commands.h
index 3527937..cae67ad 100644
--- a/chrome/test/chromedriver/session_commands.h
+++ b/chrome/test/chromedriver/session_commands.h
@@ -43,8 +43,6 @@
 Status ProcessCapabilities(const base::DictionaryValue& params,
                            base::DictionaryValue* result_capabilities);
 
-std::string WebViewIdToWindowHandle(const std::string& web_view_id);
-
 // Initializes a session.
 Status ExecuteInitSession(const InitSessionParams& bound_params,
                           Session* session,
@@ -62,6 +60,11 @@
                                      const base::DictionaryValue& params,
                                      std::unique_ptr<base::Value>* value);
 
+// Retrieve the handle of the target window.
+Status ExecuteGetCurrentWindowHandle(Session* session,
+                                     const base::DictionaryValue& params,
+                                     std::unique_ptr<base::Value>* value);
+
 // Close the target window.
 Status ExecuteClose(Session* session,
                     const base::DictionaryValue& params,
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index a858f4b..f7360859 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "chrome/test/chromedriver/window_commands.h"
-#include "chrome/test/chromedriver/session_commands.h"
 
 #include <stddef.h>
 
@@ -1581,12 +1580,3 @@
                                Timeout* timeout) {
   return web_view->TakeHeapSnapshot(value);
 }
-
-Status ExecuteGetCurrentWindowHandle(Session* session,
-                                     WebView* web_view,
-                                     const base::DictionaryValue& params,
-                                     std::unique_ptr<base::Value>* value,
-                                     Timeout* timeout) {
-  value->reset(new base::Value(WebViewIdToWindowHandle(web_view->GetId())));
-  return Status(kOk);
-}
diff --git a/chrome/test/chromedriver/window_commands.h b/chrome/test/chromedriver/window_commands.h
index e61a183..5e18353 100644
--- a/chrome/test/chromedriver/window_commands.h
+++ b/chrome/test/chromedriver/window_commands.h
@@ -365,12 +365,4 @@
 Status ProcessInputActionSequence(Session* session,
                                   const base::DictionaryValue* action_sequence,
                                   std::unique_ptr<base::ListValue>* result);
-
-// Retrieve the handle of the target window.
-Status ExecuteGetCurrentWindowHandle(Session* session,
-                                     WebView* web_view,
-                                     const base::DictionaryValue& params,
-                                     std::unique_ptr<base::Value>* value,
-                                     Timeout* timeout);
-
 #endif  // CHROME_TEST_CHROMEDRIVER_WINDOW_COMMANDS_H_
diff --git a/chrome/test/data/ad_tagging/ad_script.js b/chrome/test/data/ad_tagging/ad_script.js
index bf1e403..ba570e5b 100644
--- a/chrome/test/data/ad_tagging/ad_script.js
+++ b/chrome/test/data/ad_tagging/ad_script.js
@@ -7,6 +7,7 @@
 function createAdFrame(url, name) {
   let frame = document.createElement('iframe');
   frame.name = name;
+  frame.id = name;
   frame.src = url;
   document.body.appendChild(frame);
 }
diff --git a/chrome/test/data/ad_tagging/ad_script_2.js b/chrome/test/data/ad_tagging/ad_script_2.js
new file mode 100644
index 0000000..bed9221
--- /dev/null
+++ b/chrome/test/data/ad_tagging/ad_script_2.js
@@ -0,0 +1,5 @@
+// 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.
+
+'use strict';
diff --git a/chrome/test/data/ad_tagging/allow.zip b/chrome/test/data/ad_tagging/allow.zip
new file mode 100644
index 0000000..d6874d6
--- /dev/null
+++ b/chrome/test/data/ad_tagging/allow.zip
Binary files differ
diff --git a/chrome/test/data/ad_tagging/disallow.zip b/chrome/test/data/ad_tagging/disallow.zip
new file mode 100644
index 0000000..d6874d6
--- /dev/null
+++ b/chrome/test/data/ad_tagging/disallow.zip
Binary files differ
diff --git a/chrome/test/data/ad_tagging/download.html b/chrome/test/data/ad_tagging/download.html
new file mode 100644
index 0000000..5c4b0f8
--- /dev/null
+++ b/chrome/test/data/ad_tagging/download.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<a id="anchor_download_id" href="allow.zip" download>anchor_download</a>
+<a id="nav_download_id" href="allow.zip">nav_download</a>
+<a id="blocked_nav_download_id" href="disallow.zip">disallow_download</a>
\ No newline at end of file
diff --git a/chrome/test/data/ad_tagging/frame_factory.html b/chrome/test/data/ad_tagging/frame_factory.html
index 3679c988..a6ffee0 100644
--- a/chrome/test/data/ad_tagging/frame_factory.html
+++ b/chrome/test/data/ad_tagging/frame_factory.html
@@ -1,3 +1,4 @@
 <!DOCTYPE HTML>
 <script src="create_frame.js"></script>
-<script src="ad_script.js"></script>
\ No newline at end of file
+<script src="ad_script.js"></script>
+<script src="ad_script_2.js"></script>
\ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app.crx b/chrome/test/data/extensions/api_test/inline_install_private/app.crx
deleted file mode 100644
index bae6b40..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/app.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app.pem b/chrome/test/data/extensions/api_test/inline_install_private/app.pem
deleted file mode 100644
index e752e59..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/app.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDofAfBjmMBM1Kh
-LXPpLaSX6vrKUm4STddnZJHiHb+liaLngIqgoCtZ4Gmx4HADoZovBOt+3o4itayr
-sdzYE/FLsaAmt49JoXxri89SoYvEuagjAw+0SgUB7q6ofvNXEVCSMT2UQ6fEEm5U
-38Wn65UGsZcsx3IfXpRg7yhL17inhKxR+w3G4gjqUdmqeXNewFINXDzYNNQfae8x
-uHp4NgTBSxp8MPVZfjiJSg2TivJj3Nx901qlTIH+Es9tSxJHQsA+f/YB8DIKF8+W
-tiXbQ7i7oV3rg6NeWy5xkHLasJzxj7QzR8XJTtzIxfvVR+gmquClwxbjiSnOKUGE
-fcFbVlpLAgMBAAECggEARuFRyAxuWPZZ0fQ2q7gTv5GPxtGc542+B7Lc23Cwdnrh
-JO3G1jQfI3bNIsNHw4Ooq383gWW/Ngvnyi0fJO3nmmlcZ5F9aTiH444rtoi0QVVN
-UudjCVer8SvhKlQSQtBvnTLQEH0UEC6CXvQeohSsSe8pJSjlvXSrjmY8BeuOS9wN
-nmeXNT80pm0Y/3ojvCsvWe7Crp98XnKHiBedPnhKVX4adtkNpL9azeANnYc5h/hB
-LmubA3CIUeSGUsTqlfYFHOgXiUJPZq3h3JTBUsNkEwMQGHuyQpPHig8dYXhs63Fn
-LfsAQ9p8Xet4lVMmyGzWUgmmqZ4Eagd0FB4vKo6zEQKBgQD1nyuNzOeyCk+FYwB3
-v4DJUe73Kuvw/Lb0d3a3sdSiDCCEa9kI0vhGMUj+3WDimaW+q7mT7Fbdh4DNr3pt
-w+RDimEaN1Q52/tZEUpTZNIVFJGJ97Yjy8oKox5n2wToNYczaAJ5FpQF7DphEXAN
-XCE6WSLaZCCNwTiz1q/blhMwaQKBgQDyTsHzGI4kUqsfx8WcGna/dteEANFjYuBp
-YNoHeQOAIJCv2vlgagQjtMQd0o7hQOw9fx51v741Dk6Pjj2HWq7Eagz+IumnbNYA
-fVDkZKA2rg42VHxtG0+NiNdk+JnT+OZTN1oT6p6mUuS4NcJ0+m84qsu2PEouJas5
-s1yE3NNekwKBgGzFBeaPnPMM+dYZ13UwCvocHHS8PyvC3co4tQv35i+0qxm5IK11
-r5h17tteca8nV2yuY0oMWRNVFEcBtHezTfxS5VlUsynELvRsYbu4ZAgNyb2NQs1r
-S5eWULqxFOU3/x1Wq/Gve/F7gQbHUBW6fMR4AKUxvfDIZjHNmqblOK4xAoGBAIil
-r60HWQnU8RpwD9oT9onNXIbd6zewSDxFWU/DiBzWwKHbzKz5vLHiPINQ/jC76z5X
-FPd0lbDYC6fboIlXs52i7QbY64n2z8zg3yCeOtf7Wpp7FNx2/WslE8umgyHOiR2+
-5na65pOHxeK4tpw/qz962n1ADNlvdtuIchGfczgvAoGBAMmCbiygMmaddQDUNouw
-KaOTvMPuXwX9cbySZ872jcEY/JGqYVmvFh7NQqyMLkGj9EOFhrmHXty1Mp43Ng3M
-npscGFJ5mMj3gzstfaNBaLpsgEUVRmxFcxKlQ+0c+A3R+ZwMO3dlqa6aOZ3lj5wT
-cvm4Aiatv1fbC96IHwgNMScn
------END PRIVATE KEY-----
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app/background.js b/chrome/test/data/extensions/api_test/inline_install_private/app/background.js
deleted file mode 100644
index b9d5430..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/app/background.js
+++ /dev/null
@@ -1,7 +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.
-
-chrome.app.runtime.onLaunched.addListener(function() {
-  chrome.app.window.create("page.html");
-});
\ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app/icon.png b/chrome/test/data/extensions/api_test/inline_install_private/app/icon.png
deleted file mode 100644
index 85325d6..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/app/icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app/manifest.json b/chrome/test/data/extensions/api_test/inline_install_private/app/manifest.json
deleted file mode 100644
index 29c7f05..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/app/manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "name": "Test App",
-  "version": "0.5",
-  "manifest_version": 2,
-  "icons": {
-    "48": "icon.png"
-  },
-  "app": {
-    "background": {
-      "scripts": ["background.js"]
-    }
-  }
-}
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app/page.html b/chrome/test/data/extensions/api_test/inline_install_private/app/page.html
deleted file mode 100644
index 3b18e51..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/app/page.html
+++ /dev/null
@@ -1 +0,0 @@
-hello world
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/inlineinstall/detail/adjpiofaikamijlfbhehkldllbdcbmeb b/chrome/test/data/extensions/api_test/inline_install_private/inlineinstall/detail/adjpiofaikamijlfbhehkldllbdcbmeb
deleted file mode 100644
index 665a0159..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/inlineinstall/detail/adjpiofaikamijlfbhehkldllbdcbmeb
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "icon_url": "inline_install_private/app/icon.png",
-  "users": "17",
-  "average_rating": 3.14,
-  "rating_count": 15,
-  "manifest": "{ \"name\": \"Test App\", \"version\": \"0.5\", \"manifest_version\": 2, \"icons\": { \"48\": \"icon.png\" }, \"app\": { \"background\": { \"scripts\": [\"background.js\"] } } }"
-}
\ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/background.js b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/background.js
deleted file mode 100644
index b844294..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/background.js
+++ /dev/null
@@ -1,25 +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.
-
-function backgroundInstall() {
-  chrome.inlineInstallPrivate.install("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-                                      function(error, errorCode) {
-    if (error  == "Must be called from a foreground page")
-      chrome.test.sendMessage("success");
-    else
-      console.error("Did not receive expected error; got '" + error + "'");
-  });
-}
-
-// This gets set to the name of the test we want to run, either locally in this
-// background page or in a window we open up.
-var testName;
-
-chrome.test.sendMessage("ready", function (response) {
-  testName = response;
-  if (testName == "backgroundInstall")
-    backgroundInstall();
-  else
-    chrome.app.window.create("page.html");
-});
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/manifest.json b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/manifest.json
deleted file mode 100644
index 66d81dd0..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "name": "Inline Install API Test Driver",
-   "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn9n2RdEa0AKFzPUaurKoxlwIeji3uvJ4gvZNN0TPXiTcPp81RKVloexPdvOnmpx84tTtU/CyQbDEte0eN93s6geRjXEKggTpn20GAA/CjUuZJGdXBIH0QI90skmDZLih1aqOcthsZXffUnjns27Y99s/WNm3d7roBWJYEJTq5B32YM8tIkwab3sKUagZAEDY4aA5sbbYALFa+0DscSVwquEOlYFlmcRalSkPZ9pj0xfqoCPUmpp7QK0OxW2RYcr8H1t+EJ9B1UUag4jkbShu3kBOLfycck3jRg4KsOQECqO/hXv4KImLz1UAEVfIGCMeoIgIdWelXROV1tsK4iLMtwIDAQAB",
-  "version": "0.5",
-  "manifest_version": 2,
-  "permissions": ["inlineInstallPrivate"],
-  "app": {
-    "background": {
-      "scripts": ["background.js"]
-    }
-  }
-}
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.html b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.html
deleted file mode 100644
index 11066fe..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.html
+++ /dev/null
@@ -1,2 +0,0 @@
-
-<script src="page.js"></script>
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.js b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.js
deleted file mode 100644
index 6706774..0000000
--- a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.js
+++ /dev/null
@@ -1,42 +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.
-
-var app_id = "adjpiofaikamijlfbhehkldllbdcbmeb";
-var extension_id = "ecglahbcnmdpdciemllbhojghbkagdje";
-
-function successfulInstall() {
-  chrome.inlineInstallPrivate.install(app_id,
-                                      function(err, errorCode) {
-    if (err.length == 0 && errorCode == "success") {
-      chrome.test.sendMessage("success");
-    } else {
-      console.error("unexpected result, error:" + err + " errorCode:" +
-                    errorCode);
-    }
-  });
-}
-
-function expectError(id, expectedErrorCode, expectedError) {
-  chrome.inlineInstallPrivate.install(id, function(err, errorCode) {
-    if (errorCode == expectedErrorCode &&
-        (typeof(expectedError) == "undefined" || expectedError == err)) {
-        chrome.test.sendMessage("success");
-    } else {
-      console.error("unexpected result, error:" + err + ", errorCode:" +
-                    errorCode);
-    }
-  });
-}
-
-chrome.runtime.getBackgroundPage(function(bg) {
-  console.error("testName is " + bg.testName);
-
-  if (bg.testName == "successfulInstall") {
-    successfulInstall();
-  } else if (bg.testName == "noGesture") {
-    expectError(app_id, "notPermitted", "Must be called with a user gesture");
-  } else if (bg.testName == "onlyApps") {
-    expectError(extension_id, "notPermitted");
-  }
-});
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
index b548437f..9c7e56b2 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -124,7 +124,7 @@
 };
 
 // This test is flaky on ChromeOS. See https://crbug.com/895832.
-GEN('#if defined(CHROME_OS)');
+GEN('#if defined(OS_CHROMEOS)');
 GEN('#define MAYBE_All DISABLED_All');
 GEN('#else');
 GEN('#define MAYBE_All All');
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn
index 35c73b5..d3733d8 100644
--- a/chromecast/media/cma/backend/BUILD.gn
+++ b/chromecast/media/cma/backend/BUILD.gn
@@ -259,6 +259,8 @@
     "filter_group_unittest.cc",
     "mock_mixer_source.cc",
     "mock_mixer_source.h",
+    "mock_post_processor_factory.cc",
+    "mock_post_processor_factory.h",
     "mock_redirected_audio_output.cc",
     "mock_redirected_audio_output.h",
     "stream_mixer_external_audio_pipeline_unittest.cc",
diff --git a/chromecast/media/cma/backend/mock_post_processor_factory.cc b/chromecast/media/cma/backend/mock_post_processor_factory.cc
new file mode 100644
index 0000000..6f488d32
--- /dev/null
+++ b/chromecast/media/cma/backend/mock_post_processor_factory.cc
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
+
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace chromecast {
+namespace media {
+
+using testing::_;
+using testing::NiceMock;
+
+MockPostProcessor::MockPostProcessor(
+    MockPostProcessorFactory* factory,
+    const std::string& name,
+    const base::ListValue* filter_description_list,
+    int channels)
+    : factory_(factory), name_(name), num_output_channels_(channels) {
+  DCHECK(factory_);
+  CHECK(factory_->instances.insert({name_, this}).second);
+
+  ON_CALL(*this, ProcessFrames(_, _, _, _))
+      .WillByDefault(
+          testing::Invoke(this, &MockPostProcessor::DoProcessFrames));
+
+  if (!filter_description_list) {
+    // This happens for PostProcessingPipeline with no post-processors.
+    return;
+  }
+
+  // Parse |filter_description_list| for parameters.
+  for (size_t i = 0; i < filter_description_list->GetSize(); ++i) {
+    const base::DictionaryValue* description_dict;
+    CHECK(filter_description_list->GetDictionary(i, &description_dict));
+    std::string solib;
+    CHECK(description_dict->GetString("processor", &solib));
+    // This will initially be called with the actual pipeline on creation.
+    // Ignore and wait for the call to ResetPostProcessorsForTest.
+    const std::string kDelayModuleSolib = "delay.so";
+    if (solib == kDelayModuleSolib) {
+      const base::DictionaryValue* processor_config_dict;
+      CHECK(description_dict->GetDictionary("config", &processor_config_dict));
+      int module_delay;
+      CHECK(processor_config_dict->GetInteger("delay", &module_delay));
+      rendering_delay_ += module_delay;
+      processor_config_dict->GetBoolean("ringing", &ringing_);
+      processor_config_dict->GetInteger("output_channels",
+                                        &num_output_channels_);
+    }
+  }
+}
+
+MockPostProcessor::~MockPostProcessor() {
+  factory_->instances.erase(name_);
+}
+
+std::unique_ptr<PostProcessingPipeline>
+MockPostProcessorFactory::CreatePipeline(
+    const std::string& name,
+    const base::ListValue* filter_description_list,
+    int channels) {
+  return std::make_unique<testing::NiceMock<MockPostProcessor>>(
+      this, name, filter_description_list, channels);
+}
+
+MockPostProcessorFactory::MockPostProcessorFactory() = default;
+MockPostProcessorFactory::~MockPostProcessorFactory() = default;
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/mock_post_processor_factory.h b/chromecast/media/cma/backend/mock_post_processor_factory.h
new file mode 100644
index 0000000..20ba1e3
--- /dev/null
+++ b/chromecast/media/cma/backend/mock_post_processor_factory.h
@@ -0,0 +1,76 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "base/macros.h"
+#include "chromecast/media/cma/backend/post_processing_pipeline.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromecast {
+namespace media {
+
+class MockPostProcessorFactory;
+class MockPostProcessor : public PostProcessingPipeline {
+ public:
+  MockPostProcessor(MockPostProcessorFactory* factory,
+                    const std::string& name,
+                    const base::ListValue* filter_description_list,
+                    int channels);
+  ~MockPostProcessor() override;
+  MOCK_METHOD4(
+      ProcessFrames,
+      int(float* data, int num_frames, float current_volume, bool is_silence));
+  MOCK_METHOD1(SetContentType, void(AudioContentType));
+  bool SetSampleRate(int sample_rate) override { return true; }
+  bool IsRinging() override { return ringing_; }
+  int delay() { return rendering_delay_; }
+  std::string name() const { return name_; }
+  float* GetOutputBuffer() override { return output_buffer_; }
+  int NumOutputChannels() override { return num_output_channels_; }
+
+  MOCK_METHOD2(SetPostProcessorConfig,
+               void(const std::string& name, const std::string& config));
+  MOCK_METHOD1(UpdatePlayoutChannel, void(int));
+
+ private:
+  int DoProcessFrames(float* data,
+                      int num_frames,
+                      float current_volume,
+                      bool is_silence) {
+    output_buffer_ = data;
+    return rendering_delay_;
+  }
+
+  MockPostProcessorFactory* const factory_;
+  const std::string name_;
+  int rendering_delay_ = 0;
+  bool ringing_ = false;
+  float* output_buffer_ = nullptr;
+  int num_output_channels_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockPostProcessor);
+};
+
+class MockPostProcessorFactory : public PostProcessingPipelineFactory {
+ public:
+  MockPostProcessorFactory();
+  ~MockPostProcessorFactory() override;
+  std::unique_ptr<PostProcessingPipeline> CreatePipeline(
+      const std::string& name,
+      const base::ListValue* filter_description_list,
+      int channels) override;
+
+  std::unordered_map<std::string, MockPostProcessor*> instances;
+};
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
diff --git a/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc b/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc
index be47160..313a14f 100644
--- a/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc
+++ b/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromecast/media/audio/fake_external_audio_pipeline_support.h"
 #include "chromecast/media/cma/backend/mock_mixer_source.h"
+#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
 #include "chromecast/media/cma/backend/stream_mixer.h"
 #include "chromecast/public/media/external_audio_pipeline_shlib.h"
 #include "chromecast/public/media/mixer_output_stream.h"
@@ -162,6 +163,10 @@
   // Set Volume to 1, because we'd like the input to be w/o changes.
   mixer_->SetVolume(AudioContentType::kMedia, 1);
 
+  // Add fake postprocessor to override test configuration running on device.
+  mixer_->ResetPostProcessorsForTest(
+      std::make_unique<MockPostProcessorFactory>(), "{}");
+
   // CastMediaShlib::LoopbackAudioObserver mock observer.
   MockLoopbackAudioObserver mock_loopback_observer;
   EXPECT_CALL(mock_loopback_observer, OnLoopbackAudio(_, _, _, _, _, _))
diff --git a/chromecast/media/cma/backend/stream_mixer_unittest.cc b/chromecast/media/cma/backend/stream_mixer_unittest.cc
index e3ed597e..501c586 100644
--- a/chromecast/media/cma/backend/stream_mixer_unittest.cc
+++ b/chromecast/media/cma/backend/stream_mixer_unittest.cc
@@ -8,7 +8,6 @@
 #include <cmath>
 #include <limits>
 #include <memory>
-#include <unordered_map>
 #include <utility>
 
 #include "base/memory/ptr_util.h"
@@ -20,8 +19,8 @@
 #include "chromecast/media/cma/backend/audio_output_redirector.h"
 #include "chromecast/media/cma/backend/mixer_input.h"
 #include "chromecast/media/cma/backend/mock_mixer_source.h"
+#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
 #include "chromecast/media/cma/backend/mock_redirected_audio_output.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline.h"
 #include "chromecast/public/media/mixer_output_stream.h"
 #include "chromecast/public/volume_control.h"
 #include "media/audio/audio_device_description.h"
@@ -204,63 +203,6 @@
   std::vector<float> data_;
 };
 
-class MockPostProcessorFactory;
-class MockPostProcessor : public PostProcessingPipeline {
- public:
-  MockPostProcessor(MockPostProcessorFactory* factory,
-                    const std::string& name,
-                    const base::ListValue* filter_description_list,
-                    int channels);
-  ~MockPostProcessor() override;
-  MOCK_METHOD4(
-      ProcessFrames,
-      int(float* data, int num_frames, float current_volume, bool is_silence));
-  MOCK_METHOD1(SetContentType, void(AudioContentType));
-  bool SetSampleRate(int sample_rate) override { return true; }
-  bool IsRinging() override { return ringing_; }
-  int delay() { return rendering_delay_; }
-  std::string name() const { return name_; }
-  float* GetOutputBuffer() override { return output_buffer_; }
-  int NumOutputChannels() override { return num_output_channels_; }
-
-  MOCK_METHOD2(SetPostProcessorConfig,
-               void(const std::string& name, const std::string& config));
-  MOCK_METHOD1(UpdatePlayoutChannel, void(int));
-
- private:
-  int DoProcessFrames(float* data,
-                      int num_frames,
-                      float current_volume,
-                      bool is_silence) {
-    output_buffer_ = data;
-    return rendering_delay_;
-  }
-
-  MockPostProcessorFactory* const factory_;
-  const std::string name_;
-  int rendering_delay_ = 0;
-  bool ringing_ = false;
-  float* output_buffer_ = nullptr;
-  int num_output_channels_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockPostProcessor);
-};
-
-class MockPostProcessorFactory : public PostProcessingPipelineFactory {
- public:
-  MockPostProcessorFactory() = default;
-  ~MockPostProcessorFactory() override = default;
-  std::unique_ptr<PostProcessingPipeline> CreatePipeline(
-      const std::string& name,
-      const base::ListValue* filter_description_list,
-      int channels) override {
-    return std::make_unique<testing::NiceMock<MockPostProcessor>>(
-        this, name, filter_description_list, channels);
-  }
-
-  std::unordered_map<std::string, MockPostProcessor*> instances;
-};
-
 #define EXPECT_CALL_ALL_POSTPROCESSORS(factory, call_sig) \
   do {                                                    \
     for (auto& itr : factory->instances) {                \
@@ -274,49 +216,6 @@
   }
 }
 
-MockPostProcessor::MockPostProcessor(
-    MockPostProcessorFactory* factory,
-    const std::string& name,
-    const base::ListValue* filter_description_list,
-    int channels)
-    : factory_(factory), name_(name), num_output_channels_(channels) {
-  DCHECK(factory_);
-  CHECK(factory_->instances.insert({name_, this}).second);
-
-  ON_CALL(*this, ProcessFrames(_, _, _, _))
-      .WillByDefault(
-          testing::Invoke(this, &MockPostProcessor::DoProcessFrames));
-
-  if (!filter_description_list) {
-    // This happens for PostProcessingPipeline with no post-processors.
-    return;
-  }
-
-  // Parse |filter_description_list| for parameters.
-  for (size_t i = 0; i < filter_description_list->GetSize(); ++i) {
-    const base::DictionaryValue* description_dict;
-    CHECK(filter_description_list->GetDictionary(i, &description_dict));
-    std::string solib;
-    CHECK(description_dict->GetString("processor", &solib));
-    // This will initially be called with the actual pipeline on creation.
-    // Ignore and wait for the call to ResetPostProcessorsForTest.
-    if (solib == kDelayModuleSolib) {
-      const base::DictionaryValue* processor_config_dict;
-      CHECK(description_dict->GetDictionary("config", &processor_config_dict));
-      int module_delay;
-      CHECK(processor_config_dict->GetInteger("delay", &module_delay));
-      rendering_delay_ += module_delay;
-      processor_config_dict->GetBoolean("ringing", &ringing_);
-      processor_config_dict->GetInteger("output_channels",
-                                        &num_output_channels_);
-    }
-  }
-}
-
-MockPostProcessor::~MockPostProcessor() {
-  factory_->instances.erase(name_);
-}
-
 class MockLoopbackAudioObserver : public CastMediaShlib::LoopbackAudioObserver {
  public:
   MockLoopbackAudioObserver() = default;
diff --git a/chromeos/dbus/power_policy_controller.cc b/chromeos/dbus/power_policy_controller.cc
index 94e59d88..9bdf6ae5 100644
--- a/chromeos/dbus/power_policy_controller.cc
+++ b/chromeos/dbus/power_policy_controller.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "chromeos/chromeos_features.h"
+#include "chromeos/dbus/power_manager/backlight.pb.h"
 
 // Avoid some ugly line-wrapping later.
 using base::StringAppendF;
@@ -234,11 +235,14 @@
   prefs_policy_.set_lid_closed_action(GetProtoAction(values.lid_closed_action));
   prefs_policy_.set_use_audio_activity(values.use_audio_activity);
   prefs_policy_.set_use_video_activity(values.use_video_activity);
-  if (values.ac_brightness_percent >= 0.0)
-    prefs_policy_.set_ac_brightness_percent(values.ac_brightness_percent);
-  if (values.battery_brightness_percent >= 0.0) {
-    prefs_policy_.set_battery_brightness_percent(
-        values.battery_brightness_percent);
+
+  if (!per_session_brightness_override_) {
+    if (values.ac_brightness_percent >= 0.0)
+      prefs_policy_.set_ac_brightness_percent(values.ac_brightness_percent);
+    if (values.battery_brightness_percent >= 0.0) {
+      prefs_policy_.set_battery_brightness_percent(
+          values.battery_brightness_percent);
+    }
   }
 
   // Screen-dim deferral in response to user activity predictions can
@@ -295,6 +299,17 @@
   SendCurrentPolicy();
 }
 
+void PowerPolicyController::ScreenBrightnessChanged(
+    const power_manager::BacklightBrightnessChange& change) {
+  if (prefs_were_set_ &&
+      (prefs_policy_.has_ac_brightness_percent() ||
+       prefs_policy_.has_battery_brightness_percent()) &&
+      change.cause() ==
+          power_manager::BacklightBrightnessChange_Cause_USER_REQUEST) {
+    per_session_brightness_override_ = true;
+  }
+}
+
 void PowerPolicyController::NotifyChromeIsExiting() {
   if (chrome_is_exiting_)
     return;
@@ -311,13 +326,7 @@
 }
 
 PowerPolicyController::PowerPolicyController(PowerManagerClient* client)
-    : client_(client),
-      prefs_were_set_(false),
-      honor_wake_locks_(true),
-      honor_screen_wake_locks_(true),
-      next_wake_lock_id_(1),
-      chrome_is_exiting_(false),
-      encryption_migration_active_(false) {
+    : client_(client) {
   DCHECK(client_);
   client_->AddObserver(this);
 }
diff --git a/chromeos/dbus/power_policy_controller.h b/chromeos/dbus/power_policy_controller.h
index 7c486b9..3d34d1c9 100644
--- a/chromeos/dbus/power_policy_controller.h
+++ b/chromeos/dbus/power_policy_controller.h
@@ -129,6 +129,8 @@
 
   // PowerManagerClient::Observer implementation:
   void PowerManagerRestarted() override;
+  void ScreenBrightnessChanged(
+      const power_manager::BacklightBrightnessChange& change) override;
 
  private:
   explicit PowerPolicyController(PowerManagerClient* client);
@@ -172,7 +174,7 @@
   power_manager::PowerManagementPolicy prefs_policy_;
 
   // Was ApplyPrefs() called?
-  bool prefs_were_set_;
+  bool prefs_were_set_ = false;
 
   // Maps from an ID representing a request to prevent the screen from
   // getting dimmed or turned off or to prevent the system from suspending
@@ -180,21 +182,25 @@
   WakeLockMap wake_locks_;
 
   // Should |wake_locks_| be honored?
-  bool honor_wake_locks_;
+  bool honor_wake_locks_ = true;
 
   // If wake locks are honored, should TYPE_SCREEN or TYPE_DIM entries in
   // |wake_locks_| be honored?
   // If false, screen wake locks are just treated as TYPE_SYSTEM instead.
-  bool honor_screen_wake_locks_;
+  bool honor_screen_wake_locks_ = true;
 
   // Next ID to be used by an Add*WakeLock() request.
-  int next_wake_lock_id_;
+  int next_wake_lock_id_ = 1;
 
   // True if Chrome is in the process of exiting.
-  bool chrome_is_exiting_;
+  bool chrome_is_exiting_ = false;
 
   // True if a user homedir is in the process of migrating encryption formats.
-  bool encryption_migration_active_;
+  bool encryption_migration_active_ = false;
+
+  // Whether brightness policy value was overridden by a user adjustment in the
+  // current user session.
+  bool per_session_brightness_override_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(PowerPolicyController);
 };
diff --git a/chromeos/dbus/power_policy_controller_unittest.cc b/chromeos/dbus/power_policy_controller_unittest.cc
index 5a57c25..40bf9bcb 100644
--- a/chromeos/dbus/power_policy_controller_unittest.cc
+++ b/chromeos/dbus/power_policy_controller_unittest.cc
@@ -7,9 +7,11 @@
 #include <memory>
 
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/chromeos_features.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
+#include "chromeos/dbus/power_manager/backlight.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -375,4 +377,51 @@
                 fake_power_client_->policy()));
 }
 
+TEST_F(PowerPolicyControllerTest, PerSessionScreenBrightnessOverride) {
+  const double kAcBrightness = 99.0;
+  const double kBatteryBrightness = 77.0;
+
+  PowerPolicyController::PrefValues prefs;
+  prefs.ac_brightness_percent = kAcBrightness;
+  prefs.battery_brightness_percent = kBatteryBrightness;
+  policy_controller_->ApplyPrefs(prefs);
+
+  EXPECT_EQ(kAcBrightness,
+            fake_power_client_->policy().ac_brightness_percent());
+  EXPECT_EQ(kBatteryBrightness,
+            fake_power_client_->policy().battery_brightness_percent());
+
+  // Simulate model triggered brightness change - shouldn't override the policy.
+  power_manager::SetBacklightBrightnessRequest request;
+  request.set_percent(80.0);
+  request.set_cause(power_manager::SetBacklightBrightnessRequest_Cause_MODEL);
+  fake_power_client_->SetScreenBrightness(request);
+  base::RunLoop().RunUntilIdle();
+  policy_controller_->ApplyPrefs(prefs);
+
+  EXPECT_EQ(kAcBrightness,
+            fake_power_client_->policy().ac_brightness_percent());
+  EXPECT_EQ(kBatteryBrightness,
+            fake_power_client_->policy().battery_brightness_percent());
+
+  // Simulate user triggered brightness change - should override the policy.
+  request.set_percent(80.0);
+  request.set_cause(
+      power_manager::SetBacklightBrightnessRequest_Cause_USER_REQUEST);
+  fake_power_client_->SetScreenBrightness(request);
+  base::RunLoop().RunUntilIdle();
+  policy_controller_->ApplyPrefs(prefs);
+
+  EXPECT_FALSE(fake_power_client_->policy().has_ac_brightness_percent());
+  EXPECT_FALSE(fake_power_client_->policy().has_battery_brightness_percent());
+
+  // Simulate policy values update that should be ignored.
+  prefs.ac_brightness_percent = 98.0;
+  prefs.battery_brightness_percent = 76.0;
+  policy_controller_->ApplyPrefs(prefs);
+
+  EXPECT_FALSE(fake_power_client_->policy().has_ac_brightness_percent());
+  EXPECT_FALSE(fake_power_client_->policy().has_battery_brightness_percent());
+}
+
 }  // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/BUILD.gn b/chromeos/services/multidevice_setup/BUILD.gn
index bc062541..cab1d1d 100644
--- a/chromeos/services/multidevice_setup/BUILD.gn
+++ b/chromeos/services/multidevice_setup/BUILD.gn
@@ -65,6 +65,7 @@
     "//chromeos/services/multidevice_setup/public/cpp:android_sms_app_helper_delegate",
     "//chromeos/services/multidevice_setup/public/cpp:android_sms_pairing_state_tracker",
     "//chromeos/services/multidevice_setup/public/cpp:auth_token_validator",
+    "//chromeos/services/multidevice_setup/public/cpp:oobe_completion_tracker",
     "//chromeos/services/multidevice_setup/public/cpp:prefs",
     "//chromeos/services/multidevice_setup/public/mojom",
     "//chromeos/services/secure_channel/public/cpp/client",
@@ -142,6 +143,7 @@
     "//base",
     "//base/test:test_support",
     "//chromeos/services/device_sync/public/cpp:test_support",
+    "//chromeos/services/multidevice_setup/public/cpp:oobe_completion_tracker",
     "//chromeos/services/multidevice_setup/public/cpp:prefs",
     "//chromeos/services/multidevice_setup/public/cpp:test_support",
     "//chromeos/services/multidevice_setup/public/cpp:unit_tests",
diff --git a/chromeos/services/multidevice_setup/DEPS b/chromeos/services/multidevice_setup/DEPS
index 67cdbb1..a64f9a0 100644
--- a/chromeos/services/multidevice_setup/DEPS
+++ b/chromeos/services/multidevice_setup/DEPS
@@ -2,6 +2,7 @@
   "+chrome/common/url_constants.h",
   "+components/proximity_auth/logging/logging.h",
   "+components/cryptauth",
+  '+components/keyed_service/core',
   "+components/sync_preferences/testing_pref_service_syncable.h",
   "+components/variations",
   "+mojo/public/cpp/bindings",
diff --git a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc
index 7f134e0..a8c5cdc 100644
--- a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc
+++ b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc
@@ -54,10 +54,11 @@
     HostStatusProvider* host_status_provider,
     PrefService* pref_service,
     HostDeviceTimestampManager* host_device_timestamp_manager,
+    OobeCompletionTracker* oobe_completion_tracker,
     base::Clock* clock) {
   return base::WrapUnique(new AccountStatusChangeDelegateNotifierImpl(
       host_status_provider, pref_service, host_device_timestamp_manager,
-      clock));
+      oobe_completion_tracker, clock));
 }
 
 // static
@@ -72,6 +73,9 @@
                               kTimestampNotSet);
   registry->RegisterInt64Pref(kExistingUserChromebookAddedPrefName,
                               kTimestampNotSet);
+
+  registry->RegisterInt64Pref(kOobeSetupFlowTimestampPrefName,
+                              kTimestampNotSet);
   registry->RegisterStringPref(
       kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName, kNoHost);
 }
@@ -79,6 +83,7 @@
 AccountStatusChangeDelegateNotifierImpl::
     ~AccountStatusChangeDelegateNotifierImpl() {
   host_status_provider_->RemoveObserver(this);
+  oobe_completion_tracker_->RemoveObserver(this);
 }
 
 void AccountStatusChangeDelegateNotifierImpl::OnDelegateSet() {
@@ -108,19 +113,30 @@
     kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName[] =
         "multidevice_setup.host_device_id_from_most_recent_sync";
 
+// The timestamps (in milliseconds since UNIX Epoch, aka JavaTime) of the user
+// seeing setup flow in OOBE. If it is 0, the user did not see the setup flow in
+// OOBE.
+// static
+const char
+    AccountStatusChangeDelegateNotifierImpl::kOobeSetupFlowTimestampPrefName[] =
+        "multidevice_setup.oobe_setup_flow_timestamp ";
+
 AccountStatusChangeDelegateNotifierImpl::
     AccountStatusChangeDelegateNotifierImpl(
         HostStatusProvider* host_status_provider,
         PrefService* pref_service,
         HostDeviceTimestampManager* host_device_timestamp_manager,
+        OobeCompletionTracker* oobe_completion_tracker,
         base::Clock* clock)
     : host_status_provider_(host_status_provider),
       pref_service_(pref_service),
       host_device_timestamp_manager_(host_device_timestamp_manager),
+      oobe_completion_tracker_(oobe_completion_tracker),
       clock_(clock) {
   verified_host_device_id_from_most_recent_update_ =
       LoadHostDeviceIdFromEndOfPreviousSession();
   host_status_provider_->AddObserver(this);
+  oobe_completion_tracker_->AddObserver(this);
 }
 
 void AccountStatusChangeDelegateNotifierImpl::OnHostStatusChange(
@@ -128,6 +144,13 @@
   CheckForMultiDeviceEvents(host_status_with_device);
 }
 
+void AccountStatusChangeDelegateNotifierImpl::OnOobeCompleted() {
+  pref_service_->SetInt64(kOobeSetupFlowTimestampPrefName,
+                          clock_->Now().ToJavaTime());
+  if (delegate())
+    delegate()->OnNoLongerNewUser();
+}
+
 void AccountStatusChangeDelegateNotifierImpl::CheckForMultiDeviceEvents(
     const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
   if (!delegate()) {
@@ -174,6 +197,13 @@
     CheckForNewUserPotentialHostExistsEvent(
         const HostStatusProvider::HostStatusWithDevice&
             host_status_with_device) {
+  // We do not notify the user if they already had a chance to go through setup
+  // flow in OOBE.
+  if (pref_service_->GetInt64(kOobeSetupFlowTimestampPrefName) !=
+      kTimestampNotSet) {
+    return;
+  }
+
   // We only check for new user events if there is no enabled host.
   if (verified_host_device_id_from_most_recent_update_)
     return;
diff --git a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h
index 94ddbad2..d4722cb 100644
--- a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h
+++ b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "chromeos/services/multidevice_setup/account_status_change_delegate_notifier.h"
 #include "chromeos/services/multidevice_setup/host_status_provider.h"
+#include "chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 
 class PrefRegistrySimple;
@@ -31,7 +32,8 @@
 // previous notifications.
 class AccountStatusChangeDelegateNotifierImpl
     : public AccountStatusChangeDelegateNotifier,
-      public HostStatusProvider::Observer {
+      public HostStatusProvider::Observer,
+      public OobeCompletionTracker::Observer {
  public:
   class Factory {
    public:
@@ -42,6 +44,7 @@
         HostStatusProvider* host_status_provider,
         PrefService* pref_service,
         HostDeviceTimestampManager* host_device_timestamp_manager,
+        OobeCompletionTracker* oobe_completion_tracker,
         base::Clock* clock);
 
    private:
@@ -62,6 +65,7 @@
   static const char kExistingUserHostSwitchedPrefName[];
   static const char kExistingUserChromebookAddedPrefName[];
 
+  static const char kOobeSetupFlowTimestampPrefName[];
   static const char
       kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName[];
 
@@ -69,6 +73,7 @@
       HostStatusProvider* host_status_provider,
       PrefService* pref_service,
       HostDeviceTimestampManager* host_device_timestamp_manager,
+      OobeCompletionTracker* oobe_completion_tracker,
       base::Clock* clock);
 
   // AccountStatusChangeDelegateNotifier:
@@ -78,6 +83,9 @@
   void OnHostStatusChange(const HostStatusProvider::HostStatusWithDevice&
                               host_status_with_device) override;
 
+  // OobeCompletionTracker::Observer:
+  void OnOobeCompleted() override;
+
   void CheckForMultiDeviceEvents(
       const HostStatusProvider::HostStatusWithDevice& host_status_with_device);
 
@@ -107,6 +115,7 @@
   HostStatusProvider* host_status_provider_;
   PrefService* pref_service_;
   HostDeviceTimestampManager* host_device_timestamp_manager_;
+  OobeCompletionTracker* oobe_completion_tracker_;
   base::Clock* clock_;
 
   DISALLOW_COPY_AND_ASSIGN(AccountStatusChangeDelegateNotifierImpl);
diff --git a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl_unittest.cc b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl_unittest.cc
index d3bb11e..bf64596 100644
--- a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl_unittest.cc
@@ -14,6 +14,7 @@
 #include "chromeos/services/multidevice_setup/fake_account_status_change_delegate.h"
 #include "chromeos/services/multidevice_setup/fake_host_device_timestamp_manager.h"
 #include "chromeos/services/multidevice_setup/fake_host_status_provider.h"
+#include "chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 #include "components/cryptauth/remote_device_ref.h"
 #include "components/cryptauth/remote_device_test_util.h"
@@ -27,14 +28,31 @@
 namespace {
 
 const int64_t kTestTimeMillis = 1500000000000;
-const std::string kFakePhoneKey = "fake-phone-key";
-const std::string kFakePhoneName = "Phony Phone";
+const char kFakePhoneKey[] = "fake-phone-key";
+const char kFakePhoneName[] = "Phony Phone";
+const char kFakePhoneKeyA[] = "fake-phone-key-A";
+const char kFakePhoneNameA[] = "Phony Phone A";
+const char kFakePhoneKeyB[] = "fake-phone-key-B";
+const char kFakePhoneNameB[] = "Phony Phone B";
+
 const cryptauth::RemoteDeviceRef kFakePhone =
     cryptauth::RemoteDeviceRefBuilder()
         .SetPublicKey(kFakePhoneKey)
         .SetName(kFakePhoneName)
         .Build();
 
+// Alternate hosts for multi host tests
+const cryptauth::RemoteDeviceRef kFakePhoneA =
+    cryptauth::RemoteDeviceRefBuilder()
+        .SetPublicKey("fake-phone-key-A")
+        .SetName("Phony Phone A")
+        .Build();
+const cryptauth::RemoteDeviceRef kFakePhoneB =
+    cryptauth::RemoteDeviceRefBuilder()
+        .SetPublicKey("fake-phone-key-B")
+        .SetName("Phony Phone B")
+        .Build();
+
 }  // namespace
 
 class MultiDeviceSetupAccountStatusChangeDelegateNotifierTest
@@ -55,6 +73,7 @@
     test_clock_ = std::make_unique<base::SimpleTestClock>();
     fake_host_device_timestamp_manager_ =
         std::make_unique<FakeHostDeviceTimestampManager>();
+    fake_oobe_completion_tracker_ = std::make_unique<OobeCompletionTracker>();
     test_clock_->SetNow(base::Time::FromJavaTime(kTestTimeMillis));
   }
 
@@ -62,11 +81,18 @@
     delegate_notifier_ =
         AccountStatusChangeDelegateNotifierImpl::Factory::Get()->BuildInstance(
             fake_host_status_provider_.get(), test_pref_service_.get(),
-            fake_host_device_timestamp_manager_.get(), test_clock_.get());
+            fake_host_device_timestamp_manager_.get(),
+            fake_oobe_completion_tracker_.get(), test_clock_.get());
   }
 
-  // Following HostStatusWithDevice contract, this sets the device to null when
-  // there is no set host (or the default kFakePhone otherwise).
+  cryptauth::RemoteDeviceRef BuildFakePhone(std::string public_key,
+                                            std::string name) {
+    return cryptauth::RemoteDeviceRefBuilder()
+        .SetPublicKey(public_key)
+        .SetName(name)
+        .Build();
+  }
+
   void SetHostWithStatus(
       mojom::HostStatus host_status,
       const base::Optional<cryptauth::RemoteDeviceRef>& host_device) {
@@ -122,6 +148,16 @@
     delegate_notifier_->FlushForTesting();
   }
 
+  // Simulates completing setup flow in OOBE.
+  void CompleteOobeSetupFlow() {
+    fake_host_status_provider_->SetHostWithStatus(
+        mojom::HostStatus::kEligibleHostExistsButNoHostSet,
+        base::nullopt /* host_device */);
+    fake_oobe_completion_tracker_->MarkOobeShown();
+    if (fake_delegate_)
+      delegate_notifier_->FlushForTesting();
+  }
+
   int64_t GetNewUserPotentialHostExistsTimestamp() {
     return test_pref_service_->GetInt64(
         AccountStatusChangeDelegateNotifierImpl::
@@ -134,6 +170,12 @@
             kExistingUserChromebookAddedPrefName);
   }
 
+  int64_t GetOobeSetupFlowTimestamp() {
+    return test_pref_service_->GetInt64(
+        AccountStatusChangeDelegateNotifierImpl::
+            kOobeSetupFlowTimestampPrefName);
+  }
+
   std::string GetMostRecentVerifiedHostDeviceIdPref() {
     return test_pref_service_->GetString(
         AccountStatusChangeDelegateNotifierImpl::
@@ -153,6 +195,7 @@
       test_pref_service_;
   std::unique_ptr<FakeHostDeviceTimestampManager>
       fake_host_device_timestamp_manager_;
+  std::unique_ptr<OobeCompletionTracker> fake_oobe_completion_tracker_;
   std::unique_ptr<base::SimpleTestClock> test_clock_;
 
   std::unique_ptr<AccountStatusChangeDelegateNotifier> delegate_notifier_;
@@ -202,15 +245,17 @@
 
   SetHostWithStatus(
       mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation,
-      kFakePhone);
+      BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(0u, fake_delegate()->num_new_user_potential_host_events_handled());
   EXPECT_EQ(0u, GetNewUserPotentialHostExistsTimestamp());
 
-  SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(0u, fake_delegate()->num_new_user_potential_host_events_handled());
   EXPECT_EQ(0u, GetNewUserPotentialHostExistsTimestamp());
 
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(0u, fake_delegate()->num_new_user_potential_host_events_handled());
   EXPECT_EQ(0u, GetNewUserPotentialHostExistsTimestamp());
 }
@@ -282,7 +327,39 @@
   // A potential host was set.
   SetHostWithStatus(
       mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation,
-      kFakePhone);
+      BuildFakePhone(kFakePhoneKey, kFakePhoneName));
+  EXPECT_EQ(1u, fake_delegate()->num_new_user_potential_host_events_handled());
+  EXPECT_EQ(1u, fake_delegate()->num_no_longer_new_user_events_handled());
+}
+
+TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest,
+       CompletingOobeSetupFlowBlocksNewUserEventIfNoDelegateIsSet) {
+  BuildAccountStatusChangeDelegateNotifier();
+
+  // Complete OOBE MultiDevice setup flow before delegate is set.
+  EXPECT_EQ(0u, GetOobeSetupFlowTimestamp());
+  CompleteOobeSetupFlow();
+  EXPECT_EQ(kTestTimeMillis, GetOobeSetupFlowTimestamp());
+
+  // Set delegate, which triggers event check.
+  SetAccountStatusChangeDelegatePtr();
+
+  EXPECT_EQ(0u, fake_delegate()->num_new_user_potential_host_events_handled());
+  EXPECT_EQ(0u, GetNewUserPotentialHostExistsTimestamp());
+}
+
+TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest,
+       CompletingOobeSetupFlowWithDelegateSetTriggersNoLongerNewUserEvent) {
+  BuildAccountStatusChangeDelegateNotifier();
+  SetAccountStatusChangeDelegatePtr();
+  SetHostWithStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet,
+                    base::nullopt /* host_device */);
+
+  // Complete OOBE MultiDevice setup flow before delegate is set.
+  EXPECT_EQ(0u, GetOobeSetupFlowTimestamp());
+  CompleteOobeSetupFlow();
+  EXPECT_EQ(kTestTimeMillis, GetOobeSetupFlowTimestamp());
+
   EXPECT_EQ(1u, fake_delegate()->num_new_user_potential_host_events_handled());
   EXPECT_EQ(1u, fake_delegate()->num_no_longer_new_user_events_handled());
 }
@@ -304,12 +381,15 @@
   // event in the absence of the Chromebook added timestamp.
   SetHostWithStatus(
       mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation,
-      kFakePhone);
+      BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(0u, fake_delegate()->num_no_longer_new_user_events_handled());
 }
 
 TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest,
        NotifiesObserverForHostSwitchEvents) {
+  const cryptauth::RemoteDeviceRef fakePhone =
+      BuildFakePhone(kFakePhoneKey, kFakePhoneName);
+
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
   // Check the delegate initializes to 0.
@@ -317,31 +397,25 @@
             fake_delegate()->num_existing_user_host_switched_events_handled());
 
   // Set initially verified host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, fakePhone);
   // Host was set but has never been switched.
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 
   // Switch to new verified host.
   SetHostWithStatus(mojom::HostStatus::kHostVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey + "A")
-                        .SetName(kFakePhoneName + "A")
-                        .Build());
+                    BuildFakePhone(kFakePhoneKeyA, kFakePhoneNameA));
   EXPECT_EQ(1u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 
   // Switch to a different new verified host.
   SetHostWithStatus(mojom::HostStatus::kHostVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey + "B")
-                        .SetName(kFakePhoneName + "B")
-                        .Build());
+                    BuildFakePhone(kFakePhoneKeyB, kFakePhoneNameB));
   EXPECT_EQ(2u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 
   // Switch back to initial host (verified).
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, fakePhone);
   EXPECT_EQ(3u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 }
@@ -351,13 +425,11 @@
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
   // Set initially verified host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   // Set to host with identical information.
   SetHostWithStatus(mojom::HostStatus::kHostVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey)
-                        .SetName(kFakePhoneName)
-                        .Build());
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 }
@@ -367,25 +439,26 @@
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
   // Set initially verified host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   // Set to verified host with same name but different key.
   SetHostWithStatus(mojom::HostStatus::kHostVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey + "alternate")
-                        .SetName(kFakePhoneName)
-                        .Build());
+                    BuildFakePhone(kFakePhoneKeyA, kFakePhoneName));
   EXPECT_EQ(1u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 }
 
 TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest,
        VerifyingSetHostTriggersNoHostSwtichEvent) {
+  const cryptauth::RemoteDeviceRef fakePhone =
+      BuildFakePhone(kFakePhoneKey, kFakePhoneName);
+
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
   // Set initial host but do not verify.
-  SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, fakePhone);
   // Verify host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, fakePhone);
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 }
@@ -395,17 +468,15 @@
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
   // Set initially verified host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
 
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 
   // Set a new host without verifying.
   SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey + "A")
-                        .SetName(kFakePhoneName + "A")
-                        .Build());
+                    BuildFakePhone(kFakePhoneKeyA, kFakePhoneNameA));
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 
@@ -413,10 +484,7 @@
   // unverified.
   SetHostWithStatus(
       mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation,
-      cryptauth::RemoteDeviceRefBuilder()
-          .SetPublicKey(kFakePhoneKey + "B")
-          .SetName(kFakePhoneName + "B")
-          .Build());
+      BuildFakePhone(kFakePhoneKeyB, kFakePhoneNameB));
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 }
@@ -426,7 +494,8 @@
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
   // Set initially verified host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
 
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
@@ -437,20 +506,20 @@
 
   // Set a new verified host.
   SetHostWithStatus(mojom::HostStatus::kHostVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey + "alternate")
-                        .SetName(kFakePhoneName + "alternate")
-                        .Build());
+                    BuildFakePhone(kFakePhoneKeyA, kFakePhoneNameA));
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 }
 
 TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest,
        HostSwitchedBetweenSessions) {
-  SetHostFromPreviousSession(kFakePhoneKey + "-old");
+  // Host set in some previous session.
+  SetHostFromPreviousSession(
+      BuildFakePhone(kFakePhoneKeyA, kFakePhoneNameA).GetDeviceId());
   BuildAccountStatusChangeDelegateNotifier();
   // Host switched and verified between sessions.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   SetAccountStatusChangeDelegatePtr();
   EXPECT_EQ(1u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
@@ -460,7 +529,7 @@
        NoHostSwitchedEventWithoutExistingHost) {
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
-  SetUpHost(kFakePhone);
+  SetUpHost(BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 }
@@ -469,14 +538,12 @@
        NoHostSwitchedEventWithoutObserverSet) {
   BuildAccountStatusChangeDelegateNotifier();
   // Set initially verified host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   // All conditions for host switched event are satisfied except for setting a
   // delegate.
   SetHostWithStatus(mojom::HostStatus::kHostVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey + "alternate")
-                        .SetName(kFakePhoneName + "alternate")
-                        .Build());
+                    BuildFakePhone(kFakePhoneKeyA, kFakePhoneNameA));
   EXPECT_EQ(0u,
             fake_delegate()->num_existing_user_host_switched_events_handled());
 }
@@ -491,13 +558,17 @@
 
   // Host is set and verified from another Chromebook while this one is logged
   // in.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(
       1u, fake_delegate()->num_existing_user_chromebook_added_events_handled());
 }
 
 TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest,
        OnlyVerifiedHostCausesChromebookAddedEvent) {
+  const cryptauth::RemoteDeviceRef fakePhone =
+      BuildFakePhone(kFakePhoneKey, kFakePhoneName);
+
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
   // Start with potential hosts but none set.
@@ -505,12 +576,12 @@
                     base::nullopt /* host_device */);
 
   // Set a host without verifying.
-  SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, fakePhone);
   EXPECT_EQ(
       0u, fake_delegate()->num_existing_user_chromebook_added_events_handled());
 
   // Verify the new host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, fakePhone);
   EXPECT_EQ(
       1u, fake_delegate()->num_existing_user_chromebook_added_events_handled());
 }
@@ -522,17 +593,11 @@
   // Start with potential hosts but none set.
   // Set initial host but do not verify.
   SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey + "A")
-                        .SetName(kFakePhoneName + "A")
-                        .Build());
+                    BuildFakePhone(kFakePhoneKeyA, kFakePhoneNameA));
 
   // Replace unverified Phone A with verified Phone B.
   SetHostWithStatus(mojom::HostStatus::kHostVerified,
-                    cryptauth::RemoteDeviceRefBuilder()
-                        .SetPublicKey(kFakePhoneKey + "B")
-                        .SetName(kFakePhoneName + "B")
-                        .Build());
+                    BuildFakePhone(kFakePhoneKeyB, kFakePhoneNameB));
   // This causes a 'Chromebook added' event.
   EXPECT_EQ(
       1u, fake_delegate()->num_existing_user_chromebook_added_events_handled());
@@ -545,7 +610,8 @@
        ChromebookAddedBetweenSessionsTriggersEvents) {
   BuildAccountStatusChangeDelegateNotifier();
   // Host is set and verified before this Chromebook is logged in.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
 
   SetAccountStatusChangeDelegatePtr();
   EXPECT_EQ(
@@ -554,10 +620,13 @@
 
 TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest,
        ChromebookAddedEventBlockedIfHostWasSetFromThisChromebook) {
+  const cryptauth::RemoteDeviceRef fakePhone =
+      BuildFakePhone(kFakePhoneKey, kFakePhoneName);
+
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
 
-  SetUpHost(kFakePhone);
+  SetUpHost(fakePhone);
   // The host was set on this Chromebook so it should not trigger the Chromebook
   // added event
   EXPECT_EQ(
@@ -565,7 +634,7 @@
 
   ForgetHost();
   // Set verified host on another Chromebook.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, fakePhone);
   EXPECT_EQ(
       1u, fake_delegate()->num_existing_user_chromebook_added_events_handled());
 }
@@ -581,7 +650,8 @@
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
 
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(
       1u, fake_delegate()->num_existing_user_chromebook_added_events_handled());
   // Timestamp was overwritten by clock.
@@ -593,38 +663,36 @@
   BuildAccountStatusChangeDelegateNotifier();
   // Triggers event check. Note that all conditions for Chromebook added event
   // are satisfied except for setting a delegate.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
+  SetHostWithStatus(mojom::HostStatus::kHostVerified,
+                    BuildFakePhone(kFakePhoneKey, kFakePhoneName));
   EXPECT_EQ(
       0u, fake_delegate()->num_existing_user_chromebook_added_events_handled());
 }
 
 TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest,
        VerifiedHostIdStaysUpToDateInPrefs) {
+  const cryptauth::RemoteDeviceRef fakePhone =
+      BuildFakePhone(kFakePhoneKey, kFakePhoneName);
+  const cryptauth::RemoteDeviceRef fakePhoneA =
+      BuildFakePhone(kFakePhoneKeyA, kFakePhoneNameA);
+
   BuildAccountStatusChangeDelegateNotifier();
   SetAccountStatusChangeDelegatePtr();
   // Check the delegate initializes to empty.
   EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), "");
 
   // Set initially verified host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone);
-  EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), kFakePhone.GetDeviceId());
-
-  const cryptauth::RemoteDeviceRef kFakePhoneAlternate =
-      cryptauth::RemoteDeviceRefBuilder()
-          .SetPublicKey(kFakePhoneKey + "alternate")
-          .SetName(kFakePhoneName + "alternate")
-          .Build();
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, fakePhone);
+  EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), fakePhone.GetDeviceId());
 
   // Switch to an unverified host.
-  SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified,
-                    kFakePhoneAlternate);
+  SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, fakePhoneA);
   // The host is set but not verified so the pref should be set to empty.
   EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), "");
 
   // Verify the new host.
-  SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhoneAlternate);
-  EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(),
-            kFakePhoneAlternate.GetDeviceId());
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, fakePhoneA);
+  EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), fakePhoneA.GetDeviceId());
 
   ForgetHost();
   EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), "");
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
index b4d57f05..07546010 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
@@ -21,6 +21,7 @@
 #include "chromeos/services/multidevice_setup/public/cpp/android_sms_app_helper_delegate.h"
 #include "chromeos/services/multidevice_setup/public/cpp/android_sms_pairing_state_tracker.h"
 #include "chromeos/services/multidevice_setup/public/cpp/auth_token_validator.h"
+#include "chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
 
 namespace chromeos {
 
@@ -56,6 +57,7 @@
     PrefService* pref_service,
     device_sync::DeviceSyncClient* device_sync_client,
     AuthTokenValidator* auth_token_validator,
+    OobeCompletionTracker* oobe_completion_tracker,
     std::unique_ptr<AndroidSmsAppHelperDelegate>
         android_sms_app_helper_delegate,
     std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -63,7 +65,7 @@
     const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider) {
   return base::WrapUnique(new MultiDeviceSetupImpl(
       pref_service, device_sync_client, auth_token_validator,
-      std::move(android_sms_app_helper_delegate),
+      oobe_completion_tracker, std::move(android_sms_app_helper_delegate),
       std::move(android_sms_pairing_state_tracker), gcm_device_info_provider));
 }
 
@@ -71,6 +73,7 @@
     PrefService* pref_service,
     device_sync::DeviceSyncClient* device_sync_client,
     AuthTokenValidator* auth_token_validator,
+    OobeCompletionTracker* oobe_completion_tracker,
     std::unique_ptr<AndroidSmsAppHelperDelegate>
         android_sms_app_helper_delegate,
     std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -115,6 +118,7 @@
               ->BuildInstance(host_status_provider_.get(),
                               pref_service,
                               host_device_timestamp_manager_.get(),
+                              oobe_completion_tracker,
                               base::DefaultClock::GetInstance())),
       device_reenroller_(DeviceReenroller::Factory::Get()->BuildInstance(
           device_sync_client,
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl.h b/chromeos/services/multidevice_setup/multidevice_setup_impl.h
index bf0455d..1da78e1 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_impl.h
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl.h
@@ -42,6 +42,7 @@
 class HostDeviceTimestampManager;
 class HostStatusProvider;
 class HostVerifier;
+class OobeCompletionTracker;
 
 // Concrete MultiDeviceSetup implementation.
 class MultiDeviceSetupImpl : public MultiDeviceSetupBase,
@@ -57,6 +58,7 @@
         PrefService* pref_service,
         device_sync::DeviceSyncClient* device_sync_client,
         AuthTokenValidator* auth_token_validator,
+        OobeCompletionTracker* oobe_completion_tracker,
         std::unique_ptr<AndroidSmsAppHelperDelegate>
             android_sms_app_helper_delegate,
         std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -76,6 +78,7 @@
       PrefService* pref_service,
       device_sync::DeviceSyncClient* device_sync_client,
       AuthTokenValidator* auth_token_validator,
+      OobeCompletionTracker* oobe_completion_tracker,
       std::unique_ptr<AndroidSmsAppHelperDelegate>
           android_sms_app_helper_delegate,
       std::unique_ptr<AndroidSmsPairingStateTracker>
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
index bb1be1f..92e4d62 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
@@ -33,6 +33,7 @@
 #include "chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.h"
 #include "chromeos/services/multidevice_setup/public/cpp/fake_android_sms_pairing_state_tracker.h"
 #include "chromeos/services/multidevice_setup/public/cpp/fake_auth_token_validator.h"
+#include "chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 #include "components/cryptauth/fake_gcm_device_info_provider.h"
 #include "components/cryptauth/remote_device_test_util.h"
@@ -368,11 +369,13 @@
       sync_preferences::TestingPrefServiceSyncable*
           expected_testing_pref_service,
       FakeHostDeviceTimestampManagerFactory*
-          fake_host_device_timestamp_manager_factory)
+          fake_host_device_timestamp_manager_factory,
+      OobeCompletionTracker* expected_oobe_completion_tracker)
       : fake_host_status_provider_factory_(fake_host_status_provider_factory),
         expected_testing_pref_service_(expected_testing_pref_service),
         fake_host_device_timestamp_manager_factory_(
-            fake_host_device_timestamp_manager_factory) {}
+            fake_host_device_timestamp_manager_factory),
+        expected_oobe_completion_tracker_(expected_oobe_completion_tracker) {}
 
   ~FakeAccountStatusChangeDelegateNotifierFactory() override = default;
 
@@ -384,6 +387,7 @@
       HostStatusProvider* host_status_provider,
       PrefService* pref_service,
       HostDeviceTimestampManager* host_device_timestamp_manager,
+      OobeCompletionTracker* oobe_completion_tracker,
       base::Clock* clock) override {
     EXPECT_FALSE(instance_);
     EXPECT_EQ(fake_host_status_provider_factory_->instance(),
@@ -391,6 +395,7 @@
     EXPECT_EQ(expected_testing_pref_service_, pref_service);
     EXPECT_EQ(fake_host_device_timestamp_manager_factory_->instance(),
               host_device_timestamp_manager);
+    EXPECT_EQ(expected_oobe_completion_tracker_, oobe_completion_tracker);
 
     auto instance = std::make_unique<FakeAccountStatusChangeDelegateNotifier>();
     instance_ = instance.get();
@@ -401,6 +406,7 @@
   sync_preferences::TestingPrefServiceSyncable* expected_testing_pref_service_;
   FakeHostDeviceTimestampManagerFactory*
       fake_host_device_timestamp_manager_factory_;
+  OobeCompletionTracker* expected_oobe_completion_tracker_;
 
   FakeAccountStatusChangeDelegateNotifier* instance_ = nullptr;
 
@@ -494,6 +500,8 @@
     fake_auth_token_validator_ = std::make_unique<FakeAuthTokenValidator>();
     fake_auth_token_validator_->set_expected_auth_token(kValidAuthToken);
 
+    fake_oobe_completion_tracker_ = std::make_unique<OobeCompletionTracker>();
+
     auto fake_android_sms_app_helper_delegate =
         std::make_unique<FakeAndroidSmsAppHelperDelegate>();
 
@@ -557,7 +565,8 @@
     fake_account_status_change_delegate_notifier_factory_ =
         std::make_unique<FakeAccountStatusChangeDelegateNotifierFactory>(
             fake_host_status_provider_factory_.get(), test_pref_service_.get(),
-            fake_host_device_timestamp_manager_factory_.get());
+            fake_host_device_timestamp_manager_factory_.get(),
+            fake_oobe_completion_tracker_.get());
     AccountStatusChangeDelegateNotifierImpl::Factory::SetFactoryForTesting(
         fake_account_status_change_delegate_notifier_factory_.get());
 
@@ -578,7 +587,7 @@
 
     multidevice_setup_ = MultiDeviceSetupImpl::Factory::Get()->BuildInstance(
         test_pref_service_.get(), fake_device_sync_client_.get(),
-        fake_auth_token_validator_.get(),
+        fake_auth_token_validator_.get(), fake_oobe_completion_tracker_.get(),
         std::move(fake_android_sms_app_helper_delegate),
         std::move(fake_android_sms_pairing_state_tracker),
         fake_gcm_device_info_provider_.get());
@@ -859,6 +868,7 @@
       test_pref_service_;
   std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
   std::unique_ptr<FakeAuthTokenValidator> fake_auth_token_validator_;
+  std::unique_ptr<OobeCompletionTracker> fake_oobe_completion_tracker_;
   std::unique_ptr<cryptauth::FakeGcmDeviceInfoProvider>
       fake_gcm_device_info_provider_;
 
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_initializer.cc b/chromeos/services/multidevice_setup/multidevice_setup_initializer.cc
index 2203f62..56b4d97 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_initializer.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_initializer.cc
@@ -43,6 +43,7 @@
     PrefService* pref_service,
     device_sync::DeviceSyncClient* device_sync_client,
     AuthTokenValidator* auth_token_validator,
+    OobeCompletionTracker* oobe_completion_tracker,
     std::unique_ptr<AndroidSmsAppHelperDelegate>
         android_sms_app_helper_delegate,
     std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -50,7 +51,7 @@
     const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider) {
   return base::WrapUnique(new MultiDeviceSetupInitializer(
       pref_service, device_sync_client, auth_token_validator,
-      std::move(android_sms_app_helper_delegate),
+      oobe_completion_tracker, std::move(android_sms_app_helper_delegate),
       std::move(android_sms_pairing_state_tracker), gcm_device_info_provider));
 }
 
@@ -73,6 +74,7 @@
     PrefService* pref_service,
     device_sync::DeviceSyncClient* device_sync_client,
     AuthTokenValidator* auth_token_validator,
+    OobeCompletionTracker* oobe_completion_tracker,
     std::unique_ptr<AndroidSmsAppHelperDelegate>
         android_sms_app_helper_delegate,
     std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -81,6 +83,7 @@
     : pref_service_(pref_service),
       device_sync_client_(device_sync_client),
       auth_token_validator_(auth_token_validator),
+      oobe_completion_tracker_(oobe_completion_tracker),
       android_sms_app_helper_delegate_(
           std::move(android_sms_app_helper_delegate)),
       android_sms_pairing_state_tracker_(
@@ -269,7 +272,7 @@
 
   multidevice_setup_impl_ = MultiDeviceSetupImpl::Factory::Get()->BuildInstance(
       pref_service_, device_sync_client_, auth_token_validator_,
-      std::move(android_sms_app_helper_delegate_),
+      oobe_completion_tracker_, std::move(android_sms_app_helper_delegate_),
       std::move(android_sms_pairing_state_tracker_), gcm_device_info_provider_);
 
   if (pending_delegate_) {
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_initializer.h b/chromeos/services/multidevice_setup/multidevice_setup_initializer.h
index 26e720f..20a55a1 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_initializer.h
+++ b/chromeos/services/multidevice_setup/multidevice_setup_initializer.h
@@ -27,6 +27,7 @@
 class AndroidSmsAppHelperDelegate;
 class AndroidSmsPairingStateTracker;
 class AuthTokenValidator;
+class OobeCompletionTracker;
 
 // Initializes the MultiDeviceSetup service. This class is responsible for
 // waiting for asynchronous initialization steps to complete before creating
@@ -44,6 +45,7 @@
         PrefService* pref_service,
         device_sync::DeviceSyncClient* device_sync_client,
         AuthTokenValidator* auth_token_validator,
+        OobeCompletionTracker* oobe_completion_tracker,
         std::unique_ptr<AndroidSmsAppHelperDelegate>
             android_sms_app_helper_delegate,
         std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -81,6 +83,7 @@
       PrefService* pref_service,
       device_sync::DeviceSyncClient* device_sync_client,
       AuthTokenValidator* auth_token_validator,
+      OobeCompletionTracker* oobe_completion_tracker,
       std::unique_ptr<AndroidSmsAppHelperDelegate>
           android_sms_app_helper_delegate,
       std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -123,6 +126,7 @@
   PrefService* pref_service_;
   device_sync::DeviceSyncClient* device_sync_client_;
   AuthTokenValidator* auth_token_validator_;
+  OobeCompletionTracker* oobe_completion_tracker_;
   std::unique_ptr<AndroidSmsAppHelperDelegate> android_sms_app_helper_delegate_;
   std::unique_ptr<AndroidSmsPairingStateTracker>
       android_sms_pairing_state_tracker_;
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_service.cc b/chromeos/services/multidevice_setup/multidevice_setup_service.cc
index 637e006..f2b3e6dd 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_service.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_service.cc
@@ -37,6 +37,7 @@
     PrefService* pref_service,
     device_sync::DeviceSyncClient* device_sync_client,
     AuthTokenValidator* auth_token_validator,
+    OobeCompletionTracker* oobe_completion_tracker,
     std::unique_ptr<AndroidSmsAppHelperDelegate>
         android_sms_app_helper_delegate,
     std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -47,6 +48,7 @@
               pref_service,
               device_sync_client,
               auth_token_validator,
+              oobe_completion_tracker,
               std::move(android_sms_app_helper_delegate),
               std::move(android_sms_pairing_state_tracker),
               gcm_device_info_provider)),
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_service.h b/chromeos/services/multidevice_setup/multidevice_setup_service.h
index 4256b93..1761d168 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_service.h
+++ b/chromeos/services/multidevice_setup/multidevice_setup_service.h
@@ -31,6 +31,7 @@
 class AuthTokenValidator;
 class MultiDeviceSetupBase;
 class PrivilegedHostDeviceSetterBase;
+class OobeCompletionTracker;
 
 // Service which provides an implementation for mojom::MultiDeviceSetup. This
 // service creates one implementation and shares it among all connection
@@ -41,6 +42,7 @@
       PrefService* pref_service,
       device_sync::DeviceSyncClient* device_sync_client,
       AuthTokenValidator* auth_token_validator,
+      OobeCompletionTracker* oobe_completion_tracker,
       std::unique_ptr<AndroidSmsAppHelperDelegate>
           android_sms_app_helper_delegate,
       std::unique_ptr<AndroidSmsPairingStateTracker>
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_service_unittest.cc b/chromeos/services/multidevice_setup/multidevice_setup_service_unittest.cc
index 6e0f4bb..be70e11 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_service_unittest.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_service_unittest.cc
@@ -16,6 +16,7 @@
 #include "chromeos/services/multidevice_setup/public/cpp/fake_android_sms_pairing_state_tracker.h"
 #include "chromeos/services/multidevice_setup/public/cpp/fake_auth_token_validator.h"
 #include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup.h"
+#include "chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
 #include "chromeos/services/multidevice_setup/public/mojom/constants.mojom.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 #include "components/cryptauth/fake_gcm_device_info_provider.h"
@@ -39,6 +40,7 @@
           expected_testing_pref_service,
       device_sync::FakeDeviceSyncClient* expected_device_sync_client,
       FakeAuthTokenValidator* expected_auth_token_validator,
+      OobeCompletionTracker* expected_oobe_completion_tracker,
       FakeAndroidSmsAppHelperDelegate* expected_android_sms_app_helper_delegate,
       FakeAndroidSmsPairingStateTracker*
           expected_android_sms_pairing_state_tracker,
@@ -47,6 +49,7 @@
       : expected_testing_pref_service_(expected_testing_pref_service),
         expected_device_sync_client_(expected_device_sync_client),
         expected_auth_token_validator_(expected_auth_token_validator),
+        expected_oobe_completion_tracker_(expected_oobe_completion_tracker),
         expected_android_sms_app_helper_delegate_(
             expected_android_sms_app_helper_delegate),
         expected_android_sms_pairing_state_tracker_(
@@ -62,6 +65,7 @@
       PrefService* pref_service,
       device_sync::DeviceSyncClient* device_sync_client,
       AuthTokenValidator* auth_token_validator,
+      OobeCompletionTracker* oobe_completion_tracker,
       std::unique_ptr<AndroidSmsAppHelperDelegate>
           android_sms_app_helper_delegate,
       std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -72,6 +76,7 @@
     EXPECT_EQ(expected_testing_pref_service_, pref_service);
     EXPECT_EQ(expected_device_sync_client_, device_sync_client);
     EXPECT_EQ(expected_auth_token_validator_, auth_token_validator);
+    EXPECT_EQ(expected_oobe_completion_tracker_, oobe_completion_tracker);
     EXPECT_EQ(expected_android_sms_app_helper_delegate_,
               android_sms_app_helper_delegate.get());
     EXPECT_EQ(expected_android_sms_pairing_state_tracker_,
@@ -86,6 +91,7 @@
   sync_preferences::TestingPrefServiceSyncable* expected_testing_pref_service_;
   device_sync::FakeDeviceSyncClient* expected_device_sync_client_;
   FakeAuthTokenValidator* expected_auth_token_validator_;
+  OobeCompletionTracker* expected_oobe_completion_tracker_;
   FakeAndroidSmsAppHelperDelegate* expected_android_sms_app_helper_delegate_;
   FakeAndroidSmsPairingStateTracker*
       expected_android_sms_pairing_state_tracker_;
@@ -113,6 +119,7 @@
     fake_device_sync_client_ =
         std::make_unique<device_sync::FakeDeviceSyncClient>();
     fake_auth_token_validator_ = std::make_unique<FakeAuthTokenValidator>();
+    fake_oobe_completion_tracker_ = std::make_unique<OobeCompletionTracker>();
     auto fake_android_sms_app_helper_delegate =
         std::make_unique<FakeAndroidSmsAppHelperDelegate>();
     fake_android_sms_app_helper_delegate_ =
@@ -129,6 +136,7 @@
         std::make_unique<FakeMultiDeviceSetupFactory>(
             test_pref_service_.get(), fake_device_sync_client_.get(),
             fake_auth_token_validator_.get(),
+            fake_oobe_completion_tracker_.get(),
             fake_android_sms_app_helper_delegate_,
             fake_android_sms_pairing_state_tracker_,
             fake_gcm_device_info_provider_.get());
@@ -140,6 +148,7 @@
             std::make_unique<MultiDeviceSetupService>(
                 test_pref_service_.get(), fake_device_sync_client_.get(),
                 fake_auth_token_validator_.get(),
+                fake_oobe_completion_tracker_.get(),
                 std::move(fake_android_sms_app_helper_delegate),
                 std::move(fake_android_sms_pairing_state_tracker),
                 fake_gcm_device_info_provider_.get()));
@@ -206,6 +215,7 @@
       test_pref_service_;
   std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
   std::unique_ptr<FakeAuthTokenValidator> fake_auth_token_validator_;
+  std::unique_ptr<OobeCompletionTracker> fake_oobe_completion_tracker_;
   FakeAndroidSmsAppHelperDelegate* fake_android_sms_app_helper_delegate_;
   FakeAndroidSmsPairingStateTracker* fake_android_sms_pairing_state_tracker_;
   std::unique_ptr<cryptauth::FakeGcmDeviceInfoProvider>
diff --git a/chromeos/services/multidevice_setup/public/cpp/BUILD.gn b/chromeos/services/multidevice_setup/public/cpp/BUILD.gn
index fc21f96..cf22252 100644
--- a/chromeos/services/multidevice_setup/public/cpp/BUILD.gn
+++ b/chromeos/services/multidevice_setup/public/cpp/BUILD.gn
@@ -78,6 +78,18 @@
   ]
 }
 
+source_set("oobe_completion_tracker") {
+  sources = [
+    "oobe_completion_tracker.cc",
+    "oobe_completion_tracker.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/keyed_service/core",
+  ]
+}
+
 source_set("url_provider") {
   sources = [
     "url_provider.cc",
diff --git a/chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client_impl_unittest.cc b/chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client_impl_unittest.cc
index 93e5fdd..259c9a9 100644
--- a/chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client_impl_unittest.cc
@@ -46,6 +46,7 @@
       PrefService* pref_service,
       device_sync::DeviceSyncClient* device_sync_client,
       AuthTokenValidator* auth_token_validator,
+      OobeCompletionTracker* oobe_completion_tracker,
       std::unique_ptr<AndroidSmsAppHelperDelegate>
           android_sms_app_helper_delegate,
       std::unique_ptr<AndroidSmsPairingStateTracker>
@@ -126,6 +127,7 @@
     auto multidevice_setup_service = std::make_unique<MultiDeviceSetupService>(
         nullptr /* pref_service */, nullptr /* device_sync_client */,
         nullptr /* auth_token_validator */,
+        nullptr /* oobe_completion_tracker */,
         nullptr /* android_sms_app_helper_delegate */,
         nullptr /* android_sms_pairing_state_tracker */,
         nullptr /* gcm_device_info_provider */);
diff --git a/chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.cc b/chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.cc
new file mode 100644
index 0000000..260cfe9
--- /dev/null
+++ b/chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
+
+namespace chromeos {
+
+namespace multidevice_setup {
+
+OobeCompletionTracker::OobeCompletionTracker() = default;
+
+OobeCompletionTracker::~OobeCompletionTracker() = default;
+
+void OobeCompletionTracker::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void OobeCompletionTracker::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
+void OobeCompletionTracker::MarkOobeShown() {
+  for (auto& observer : observer_list_)
+    observer.OnOobeCompleted();
+}
+
+}  // namespace multidevice_setup
+
+}  // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h b/chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h
new file mode 100644
index 0000000..616be33
--- /dev/null
+++ b/chromeos/services/multidevice_setup/public/cpp/oobe_completion_tracker.h
@@ -0,0 +1,48 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_SERVICES_MULTIDEVICE_SETUP_PUBLIC_CPP_OOBE_COMPLETION_TRACKER_H_
+#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_PUBLIC_CPP_OOBE_COMPLETION_TRACKER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace chromeos {
+
+namespace multidevice_setup {
+
+// Records if/when the user underwent the OOBE MultiDevice setup flow to prevent
+// spamming the user with multiple notifications to set up MultiDevice features.
+class OobeCompletionTracker : public KeyedService {
+ public:
+  class Observer {
+   public:
+    virtual void OnOobeCompleted() = 0;
+
+   protected:
+    virtual ~Observer() = default;
+  };
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+  OobeCompletionTracker();
+  ~OobeCompletionTracker() override;
+
+  void MarkOobeShown();
+
+ private:
+  base::ObserverList<Observer>::Unchecked observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(OobeCompletionTracker);
+};
+
+}  // namespace multidevice_setup
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_PUBLIC_CPP_OOBE_COMPLETION_TRACKER_H_
diff --git a/components/cronet/PRESUBMIT.py b/components/cronet/PRESUBMIT.py
index b638ed9..0892fdb 100644
--- a/components/cronet/PRESUBMIT.py
+++ b/components/cronet/PRESUBMIT.py
@@ -77,24 +77,6 @@
       input_api, output_api, '.', [ r'^tools_unittest\.py$'])
 
 
-def _ChangeAffectsCronetForAndroid(change):
-  """ Returns |true| if the change may affect Cronet for Android. """
-
-  for path in change.LocalPaths():
-    if not path.startswith(os.path.join('components', 'cronet', 'ios')):
-      return True
-  return False
-
-
-def _ChangeAffectsCronetForIos(change):
-  """ Returns |true| if the change may affect Cronet for iOS. """
-
-  for path in change.LocalPaths():
-    if not path.startswith(os.path.join('components', 'cronet', 'android')):
-      return True
-  return False
-
-
 def _ChangeAffectsCronetTools(change):
   """ Returns |true| if the change may affect Cronet tools. """
 
@@ -115,20 +97,3 @@
 
 def CheckChangeOnCommit(input_api, output_api):
   return _RunToolsUnittests(input_api, output_api)
-
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook adds an extra try bot to the CL description in order to run Cronet
-  tests in addition to CQ try bots.
-  """
-
-  try_bots = []
-  if _ChangeAffectsCronetForAndroid(change):
-    try_bots.append('master.tryserver.chromium.android:android_cronet_tester')
-  if _ChangeAffectsCronetForIos(change):
-    try_bots.append('luci.chromium.try:ios-simulator-cronet')
-
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl, try_bots, 'Automatically added Cronet trybots to run tests on CQ.')
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index ac54aaa..f499a7c 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -76,6 +76,7 @@
 const char kQuicMigrateSessionsEarlyV2[] = "migrate_sessions_early_v2";
 const char kQuicRetryOnAlternateNetworkBeforeHandshake[] =
     "retry_on_alternate_network_before_handshake";
+const char kQuicRaceStaleDNSOnConnection[] = "race_stale_dns_on_connection";
 const char kQuicDisableBidirectionalStreams[] =
     "quic_disable_bidirectional_streams";
 const char kQuicRaceCertVerification[] = "race_cert_verification";
@@ -443,6 +444,13 @@
             quic_retry_on_alternate_network_before_handshake;
       }
 
+      bool quic_race_stale_dns_on_connection = false;
+      if (quic_args->GetBoolean(kQuicRaceStaleDNSOnConnection,
+                                &quic_race_stale_dns_on_connection)) {
+        session_params->quic_race_stale_dns_on_connection =
+            quic_race_stale_dns_on_connection;
+      }
+
       bool quic_disable_bidirectional_streams = false;
       if (quic_args->GetBoolean(kQuicDisableBidirectionalStreams,
                                 &quic_disable_bidirectional_streams)) {
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc
index 53c7de1c..149b9bb 100644
--- a/components/cronet/url_request_context_config_unittest.cc
+++ b/components/cronet/url_request_context_config_unittest.cc
@@ -204,6 +204,7 @@
   EXPECT_FALSE(params->quic_migrate_sessions_on_network_change_v2);
   EXPECT_FALSE(params->quic_migrate_sessions_early_v2);
   EXPECT_FALSE(params->quic_retry_on_alternate_network_before_handshake);
+  EXPECT_FALSE(params->quic_race_stale_dns_on_connection);
 
   // Check race_cert_verification.
   EXPECT_TRUE(params->quic_race_cert_verification);
@@ -581,6 +582,57 @@
       4, params->quic_max_migrations_to_non_default_network_on_path_degrading);
 }
 
+TEST(URLRequestContextConfigTest, SetQuicStaleDNSracing) {
+  base::test::ScopedTaskEnvironment scoped_task_environment_(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
+
+  URLRequestContextConfig config(
+      // Enable QUIC.
+      true,
+      // QUIC User Agent ID.
+      "Default QUIC User Agent ID",
+      // Enable SPDY.
+      true,
+      // Enable Brotli.
+      false,
+      // Type of http cache.
+      URLRequestContextConfig::HttpCacheType::DISK,
+      // Max size of http cache in bytes.
+      1024000,
+      // Disable caching for HTTP responses. Other information may be stored in
+      // the cache.
+      false,
+      // Storage path for http cache and cookie storage.
+      "/data/data/org.chromium.net/app_cronet_test/test_storage",
+      // Accept-Language request header field.
+      "foreign-language",
+      // User-Agent request header field.
+      "fake agent",
+      // JSON encoded experimental options.
+      "{\"QUIC\":{\"race_stale_dns_on_connection\":true}}",
+      // MockCertVerifier to use for testing purposes.
+      std::unique_ptr<net::CertVerifier>(),
+      // Enable network quality estimator.
+      false,
+      // Enable Public Key Pinning bypass for local trust anchors.
+      true,
+      // Optional network thread priority.
+      base::Optional<double>());
+
+  net::URLRequestContextBuilder builder;
+  net::NetLog net_log;
+  config.ConfigureURLRequestContextBuilder(&builder, &net_log);
+  // Set a ProxyConfigService to avoid DCHECK failure when building.
+  builder.set_proxy_config_service(
+      std::make_unique<net::ProxyConfigServiceFixed>(
+          net::ProxyConfigWithAnnotation::CreateDirect()));
+  std::unique_ptr<net::URLRequestContext> context(builder.Build());
+  const net::HttpNetworkSession::Params* params =
+      context->GetNetworkSessionParams();
+
+  EXPECT_TRUE(params->quic_race_stale_dns_on_connection);
+}
+
 TEST(URLRequestContextConfigTest, SetQuicHostWhitelist) {
   base::test::ScopedTaskEnvironment scoped_task_environment_(
       base::test::ScopedTaskEnvironment::MainThreadType::IO);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
index c67bb400..759994515 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
@@ -20,10 +20,12 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
@@ -102,6 +104,7 @@
     test_context_ = DataReductionProxyTestContext::Builder()
                         .SkipSettingsInitialization()
                         .Build();
+    test_context_->DisableWarmupURLFetch();
     // Since some of the tests fetch a webpage from the embedded server running
     // on localhost, the adding of default bypass rules is disabled. This allows
     // Chrome to fetch webpages using data saver proxy.
@@ -625,6 +628,9 @@
 // was indicated. In both the single and double bypass cases, if the request
 // was idempotent, it will be retried over a direct connection.
 TEST_F(DataReductionProxyProtocolTest, BypassLogic) {
+  // The test manually controls the fetch of warmup URL and the response.
+  test_context_->DisableWarmupURLFetchCallback();
+
   const struct {
     const char* method;
     const char* first_response;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
index f5f8dcf..6ca73dc 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
@@ -83,6 +83,7 @@
 
     test_context_ =
         DataReductionProxyTestContext::Builder().WithMockConfig().Build();
+    test_context_->DisableWarmupURLFetch();
     mock_url_request_ = context_.CreateRequest(GURL(), net::IDLE, &delegate_,
                                                TRAFFIC_ANNOTATION_FOR_TESTS);
   }
@@ -147,6 +148,7 @@
                             .WithURLRequestContext(&context_)
                             .WithMockClientSocketFactory(&mock_socket_factory_)
                             .Build();
+    drp_test_context_->DisableWarmupURLFetch();
     drp_test_context_->AttachToURLRequestContext(&context_storage_);
     context_.set_client_socket_factory(&mock_socket_factory_);
     proxy_delegate_ = drp_test_context_->io_data()->CreateProxyDelegate();
@@ -600,9 +602,6 @@
     const char* initial_response_headers;
   };
   const TestCase test_cases[] = {
-    { "DataReductionProxy.BypassedBytes.MissingViaHeaderOther",
-      "HTTP/1.1 200 OK\r\n\r\n",
-    },
     { "DataReductionProxy.BypassedBytes.Malformed407",
       "HTTP/1.1 407 Proxy Authentication Required\r\n\r\n",
     },
@@ -679,44 +678,6 @@
 }
 
 TEST_F(DataReductionProxyBypassStatsEndToEndTest,
-       BypassedBytesMissingViaHeader4xx) {
-  InitializeContext();
-  const char* test_case_response_headers[] = {
-      "HTTP/1.1 414 Request-URI Too Long\r\n\r\n",
-      "HTTP/1.1 404 Not Found\r\n\r\n",
-  };
-  for (const char* test_case : test_case_response_headers) {
-    ClearBadProxies();
-    // The first request should be bypassed for missing Via header.
-    {
-      base::HistogramTester histogram_tester;
-      CreateAndExecuteRequest(GURL("http://foo.com"), net::LOAD_NORMAL, net::OK,
-                              test_case, kErrorBody.c_str(),
-                              "HTTP/1.1 200 OK\r\n\r\n", kBody.c_str());
-
-      histogram_tester.ExpectUniqueSample(
-          "DataReductionProxy.BypassedBytes.MissingViaHeader4xx", kBody.size(),
-          1);
-      ExpectOtherBypassedBytesHistogramsEmpty(
-          histogram_tester,
-          "DataReductionProxy.BypassedBytes.MissingViaHeader4xx");
-    }
-    // The second request should be sent via the proxy.
-    {
-      base::HistogramTester histogram_tester;
-      CreateAndExecuteRequest(GURL("http://bar.com"), net::LOAD_NORMAL, net::OK,
-                              "HTTP/1.1 200 OK\r\n"
-                              "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
-                              kNextBody.c_str(), nullptr, nullptr);
-      histogram_tester.ExpectUniqueSample(
-          "DataReductionProxy.BypassedBytes.NotBypassed", kNextBody.size(), 1);
-      ExpectOtherBypassedBytesHistogramsEmpty(
-          histogram_tester, "DataReductionProxy.BypassedBytes.NotBypassed");
-    }
-  }
-}
-
-TEST_F(DataReductionProxyBypassStatsEndToEndTest,
        ProxyUnreachableThenReachable) {
   net::ProxyServer fallback_proxy_server =
       net::ProxyServer::FromURI("origin.net:80", net::ProxyServer::SCHEME_HTTP);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 839987a..aa6e71f7 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
@@ -239,7 +240,8 @@
 }
 
 TEST_F(DataReductionProxyConfigTest, TestOnConnectionChangePersistedData) {
-  base::FieldTrialList field_trial_list(nullptr);
+  // The test manually controls the fetch of warmup URL and the response.
+  test_context_->DisableWarmupURLFetchCallback();
 
   const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
       "https://secure_origin.net:443", net::ProxyServer::SCHEME_HTTP);
@@ -282,6 +284,9 @@
 }
 
 TEST_F(DataReductionProxyConfigTest, TestOnNetworkChanged) {
+  // The test manually controls the fetch of warmup URL and the response.
+  test_context_->DisableWarmupURLFetchCallback();
+
   RecreateContextWithMockConfig();
   const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
       "https://secure_origin.net:443", net::ProxyServer::SCHEME_HTTP);
@@ -404,7 +409,8 @@
 
     variations::testing::ClearAllVariationParams();
     std::map<std::string, std::string> variation_params;
-    variation_params["warmup_url"] = warmup_url.spec();
+
+    test_context_->DisableWarmupURLFetchCallback();
 
     ASSERT_TRUE(variations::AssociateVariationParams(
         params::GetQuicFieldTrialName(), "Enabled", variation_params));
@@ -454,16 +460,8 @@
       RunUntilIdle();
 
       if (test.data_reduction_proxy_enabled) {
-        histogram_tester.ExpectUniqueSample(
-            "DataReductionProxy.WarmupURL.FetchInitiated", 1, 1);
-        histogram_tester.ExpectTotalCount(
-            "DataReductionProxy.WarmupURL.FetchAttemptEvent", 2);
-        histogram_tester.ExpectBucketCount(
-            "DataReductionProxy.WarmupURL.FetchAttemptEvent",
-            2 /* kProxyNotEnabledByUser */, 1);
-        histogram_tester.ExpectBucketCount(
-            "DataReductionProxy.WarmupURL.FetchAttemptEvent",
-            0 /* kFetchInitiated */, 1);
+        EXPECT_EQ(1, histogram_tester.GetBucketCount(
+                         "DataReductionProxy.WarmupURL.FetchInitiated", 1));
       } else {
         histogram_tester.ExpectTotalCount(
             "DataReductionProxy.WarmupURL.FetchInitiated", 0);
@@ -485,14 +483,9 @@
       if (test.data_reduction_proxy_enabled) {
         histogram_tester.ExpectTotalCount(
             "DataReductionProxy.WarmupURL.FetchInitiated", 0);
-        histogram_tester.ExpectTotalCount(
-            "DataReductionProxy.WarmupURL.FetchAttemptEvent", 2);
-        histogram_tester.ExpectBucketCount(
-            "DataReductionProxy.WarmupURL.FetchAttemptEvent",
-            1 /* kConnectionTypeNone */, 1);
-        histogram_tester.ExpectBucketCount(
-            "DataReductionProxy.WarmupURL.FetchAttemptEvent",
-            2 /* kProxyNotEnabledByUser */, 1);
+        EXPECT_LE(1, histogram_tester.GetBucketCount(
+                         "DataReductionProxy.WarmupURL.FetchAttemptEvent",
+                         1 /* kConnectionTypeNone */));
 
       } else {
         histogram_tester.ExpectTotalCount(
@@ -1059,6 +1052,9 @@
 TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherRetry) {
   constexpr size_t kMaxWarmupURLFetchAttempts = 3;
 
+  // The test manually controls the fetch of warmup URL and the response.
+  test_context_->DisableWarmupURLFetchCallback();
+
   base::HistogramTester histogram_tester;
   const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
       "https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
@@ -1197,6 +1193,9 @@
 
 // Tests the behavior when warmup URL fetcher times out.
 TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherTimeout) {
+  // The test manually controls the fetch of warmup URL and the response.
+  test_context_->DisableWarmupURLFetchCallback();
+
   base::HistogramTester histogram_tester;
   const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
       "https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
@@ -1252,6 +1251,9 @@
 
 TEST_F(DataReductionProxyConfigTest,
        HandleWarmupFetcherRetryWithConnectionChange) {
+  // The test manually controls the fetch of warmup URL and the response.
+  test_context_->DisableWarmupURLFetchCallback();
+
   constexpr size_t kMaxWarmupURLFetchAttempts = 3;
 
   base::HistogramTester histogram_tester;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
index 6e5d41e0..88741b0 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
@@ -513,26 +513,25 @@
 
 TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithBypassAndRetry) {
   MockRead mock_reads_array[][3] = {
-      // First, get a redirect without a via header, which should be retried
+      // First, get a bypass which should be retried
       // using the fallback proxy.
       {
           MockRead("HTTP/1.1 302 Found\r\n"
+                   "Chrome-Proxy: bypass=0\r\n"
                    "Location: http://bar.com/\r\n\r\n"),
-          MockRead(""),
-          MockRead(net::SYNCHRONOUS, net::OK),
+          MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
       },
       // Same as before, but through the fallback proxy. Now both proxies are
       // bypassed, and the request should be retried over direct.
       {
           MockRead("HTTP/1.1 302 Found\r\n"
+                   "Chrome-Proxy: bypass=0\r\n"
                    "Location: http://baz.com/\r\n\r\n"),
-          MockRead(""),
-          MockRead(net::SYNCHRONOUS, net::OK),
+          MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
       },
       // Finally, a successful response is received.
       {
-          MockRead("HTTP/1.1 200 OK\r\n\r\n"),
-          MockRead(kBody.c_str()),
+          MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead(kBody.c_str()),
           MockRead(net::SYNCHRONOUS, net::OK),
       },
   };
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 48f76d4..60528a8c 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -862,6 +862,10 @@
     return &ssl_socket_data_provider_;
   }
 
+  void DisableWarmupURLFetchCallback() {
+    test_context_->DisableWarmupURLFetchCallback();
+  }
+
  private:
   base::MessageLoopForIO message_loop_;
   std::unique_ptr<net::MockClientSocketFactory> mock_socket_factory_;
@@ -1878,6 +1882,9 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, RedirectSharePid) {
+  // The test manually controls the fetch of warmup URL and the response.
+  DisableWarmupURLFetchCallback();
+
   // This is unaffacted by brotil and insecure proxy.
   Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index d49586e1..336986d2 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -702,6 +702,11 @@
       switches::kDisableDataReductionProxyWarmupURLFetch);
 }
 
+void DataReductionProxyTestContext::DisableWarmupURLFetchCallback() {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kDisableDataReductionProxyWarmupURLFetchCallback);
+}
+
 MockDataReductionProxyConfig* DataReductionProxyTestContext::mock_config()
     const {
   DCHECK(test_context_flags_ & USE_MOCK_CONFIG);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index 1495d884..4332e78 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -424,6 +424,11 @@
   // up the network mock sockets.
   void DisableWarmupURLFetch();
 
+  // Disables the warmup URL fetcher to callback into DRP to report the result
+  // of the warmup fetch. The callback can result in DRP proxies getting
+  // disabled. This method is useful for testing.
+  void DisableWarmupURLFetchCallback();
+
   // Returns the underlying |MockDataReductionProxyConfig|. This can only be
   // called if built with WithMockConfig.
   MockDataReductionProxyConfig* mock_config() const;
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
index 32a815e..e80825a 100644
--- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
+++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
@@ -204,9 +204,7 @@
         PROXY_SCHEME_MAX);
   }
 
-  if (!GetFieldTrialParamByFeatureAsBool(
-          features::kDataReductionProxyRobustConnection,
-          params::GetWarmupCallbackParamName(), false)) {
+  if (!params::IsWarmupURLFetchCallbackEnabled()) {
     CleanupAfterFetch();
     return;
   }
@@ -245,7 +243,7 @@
   const base::TimeDelta min_timeout =
       base::TimeDelta::FromSeconds(GetFieldTrialParamByFeatureAsInt(
           features::kDataReductionProxyRobustConnection,
-          "warmup_url_fetch_min_timeout_seconds", 10));
+          "warmup_url_fetch_min_timeout_seconds", 30));
   const base::TimeDelta max_timeout =
       base::TimeDelta::FromSeconds(GetFieldTrialParamByFeatureAsInt(
           features::kDataReductionProxyRobustConnection,
@@ -296,9 +294,7 @@
   base::UmaHistogramSparse("DataReductionProxy.WarmupURL.HttpResponseCode",
                            std::abs(kInvalidResponseCode));
 
-  if (!GetFieldTrialParamByFeatureAsBool(
-          features::kDataReductionProxyRobustConnection,
-          params::GetWarmupCallbackParamName(), false)) {
+  if (!params::IsWarmupURLFetchCallbackEnabled()) {
     // Running the callback is not enabled.
     CleanupAfterFetch();
     return;
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
index 3f5e383..422592e 100644
--- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
@@ -53,18 +53,9 @@
   }
   FetchResult success_response_last() const { return success_response_last_; }
 
-  static void InitExperiment(
-      base::test::ScopedFeatureList* scoped_feature_list) {
-    std::map<std::string, std::string> params;
-    params[params::GetWarmupCallbackParamName()] = "true";
-    scoped_feature_list->InitAndEnableFeatureWithParameters(
-        features::kDataReductionProxyRobustConnection, params);
-  }
-
   static void InitExperimentWithTimeout(
       base::test::ScopedFeatureList* scoped_feature_list) {
     std::map<std::string, std::string> params;
-    params["warmup_fetch_callback_enabled"] = "true";
     params["warmup_url_fetch_min_timeout_seconds"] = "10";
     params["warmup_url_fetch_max_timeout_seconds"] = "60";
     params["warmup_url_fetch_init_http_rtt_multiplier"] = "12";
@@ -77,7 +68,6 @@
       base::TimeDelta first_retry,
       base::TimeDelta second_retry) {
     std::map<std::string, std::string> params;
-    params["warmup_fetch_callback_enabled"] = "true";
     params["warmup_url_fetch_wait_timer_first_retry_seconds"] =
         base::IntToString(first_retry.InSeconds());
     params["warmup_url_fetch_wait_timer_second_retry_seconds"] =
@@ -182,9 +172,6 @@
 }
 
 TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLNoViaHeader) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  WarmupURLFetcherTest::InitExperiment(&scoped_feature_list);
-
   base::test::ScopedTaskEnvironment scoped_task_environment;
   network::TestURLLoaderFactory test_url_loader_factory;
   auto test_shared_url_loader_factory =
@@ -235,9 +222,6 @@
 }
 
 TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLWithViaHeader) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  WarmupURLFetcherTest::InitExperiment(&scoped_feature_list);
-
   base::test::ScopedTaskEnvironment scoped_task_environment;
   network::TestURLLoaderFactory test_url_loader_factory;
   auto test_shared_url_loader_factory =
@@ -332,15 +316,12 @@
       util::ConvertNetProxySchemeToProxyScheme(net::ProxyServer::SCHEME_DIRECT),
       1);
 
-  // The callback should not be run.
-  EXPECT_EQ(0u, warmup_url_fetcher.callback_received_count());
+  // The callback should be run.
+  EXPECT_EQ(1u, warmup_url_fetcher.callback_received_count());
   warmup_url_fetcher.VerifyStateCleanedUp();
 }
 
 TEST(WarmupURLFetcherTest, TestConnectionResetFetchWarmupURL) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  WarmupURLFetcherTest::InitExperiment(&scoped_feature_list);
-
   base::test::ScopedTaskEnvironment scoped_task_environment;
   network::TestURLLoaderFactory test_url_loader_factory;
   auto test_shared_url_loader_factory =
@@ -385,9 +366,6 @@
 }
 
 TEST(WarmupURLFetcherTest, TestFetchTimesout) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  WarmupURLFetcherTest::InitExperiment(&scoped_feature_list);
-
   base::test::ScopedTaskEnvironment scoped_task_environment;
   network::TestURLLoaderFactory test_url_loader_factory;
   auto test_shared_url_loader_factory =
@@ -425,9 +403,6 @@
 }
 
 TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLWithDelay) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  WarmupURLFetcherTest::InitExperiment(&scoped_feature_list);
-
   base::test::ScopedTaskEnvironment scoped_task_environment(
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
   network::TestURLLoaderFactory test_url_loader_factory;
@@ -485,7 +460,7 @@
 
 TEST(WarmupURLFetcherTest, TestFetchTimeoutIncreasing) {
   // Must remain in sync with warmup_url_fetcher.cc.
-  constexpr base::TimeDelta kMinTimeout = base::TimeDelta::FromSeconds(10);
+  constexpr base::TimeDelta kMinTimeout = base::TimeDelta::FromSeconds(30);
   constexpr base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(60);
 
   base::HistogramTester histogram_tester;
@@ -503,7 +478,7 @@
 
   base::TimeDelta http_rtt = base::TimeDelta::FromSeconds(2);
   warmup_url_fetcher.SetHttpRttOverride(http_rtt);
-  EXPECT_EQ(http_rtt * 12, warmup_url_fetcher.GetFetchTimeout());
+  EXPECT_EQ(kMinTimeout, warmup_url_fetcher.GetFetchTimeout());
 
   warmup_url_fetcher.FetchWarmupURL(1);
   EXPECT_EQ(http_rtt * 24, warmup_url_fetcher.GetFetchTimeout());
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
index 22fbfa6..0446d92 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -427,12 +427,10 @@
   }
 
   bool disable_bypass_on_missing_via_header =
+      params::IsWarmupURLFetchCallbackEnabled() &&
       GetFieldTrialParamByFeatureAsBool(
           features::kDataReductionProxyRobustConnection,
-          params::GetWarmupCallbackParamName(), false) &&
-      GetFieldTrialParamByFeatureAsBool(
-          features::kDataReductionProxyRobustConnection,
-          params::GetMissingViaBypassParamName(), false);
+          params::GetMissingViaBypassParamName(), true);
 
   if (!has_via_header && !disable_bypass_on_missing_via_header &&
       (headers.response_code() != net::HTTP_NOT_MODIFIED)) {
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
index 287b675..521bab2 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
@@ -603,6 +603,9 @@
 }
 
 TEST(DataReductionProxyHeadersTest, BypassMissingViaIfExperiment) {
+  const char kWarmupFetchCallbackEnabledParam[] =
+      "warmup_fetch_callback_enabled";
+
   const struct {
     const char* headers;
     std::map<std::string, std::string> feature_parameters;
@@ -611,7 +614,7 @@
       {
           "HTTP/1.1 200 OK\n",
           {
-              {params::GetWarmupCallbackParamName(), "true"},
+              {kWarmupFetchCallbackEnabledParam, "true"},
               {params::GetMissingViaBypassParamName(), "true"},
           },
           BYPASS_EVENT_TYPE_MAX,
@@ -619,7 +622,7 @@
       {
           "HTTP/1.1 200 OK\n",
           {
-              {params::GetWarmupCallbackParamName(), "true"},
+              {kWarmupFetchCallbackEnabledParam, "true"},
               {params::GetMissingViaBypassParamName(), "false"},
           },
           BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER,
@@ -627,7 +630,7 @@
       {
           "HTTP/1.1 200 OK\n",
           {
-              {params::GetWarmupCallbackParamName(), "false"},
+              {kWarmupFetchCallbackEnabledParam, "false"},
               {params::GetMissingViaBypassParamName(), "false"},
           },
           BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER,
@@ -656,123 +659,121 @@
   const struct {
      const char* headers;
      DataReductionProxyBypassType expected_result;
-  } tests[] = {
-      {
-          "HTTP/1.1 200 OK\n"
-          "Chrome-Proxy: bypass=0\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_MEDIUM,
-      },
-      {
-          "HTTP/1.1 200 OK\n"
-          "Chrome-Proxy: bypass=1\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_SHORT,
-      },
-      {
-          "HTTP/1.1 200 OK\n"
-          "Chrome-Proxy: bypass=59\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_SHORT,
-      },
-      {
-          "HTTP/1.1 200 OK\n"
-          "Chrome-Proxy: bypass=60\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_MEDIUM,
-      },
-      {
-          "HTTP/1.1 200 OK\n"
-          "Chrome-Proxy: bypass=300\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_MEDIUM,
-      },
-      {
-          "HTTP/1.1 200 OK\n"
-          "Chrome-Proxy: bypass=301\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_LONG,
-      },
-      {
-          "HTTP/1.1 200 OK\n"
-          "Chrome-Proxy: block-once\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_CURRENT,
-      },
-      {
-          "HTTP/1.1 500 Internal Server Error\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR,
-      },
-      {
-          "HTTP/1.1 501 Not Implemented\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_MAX,
-      },
-      {
-          "HTTP/1.1 502 Bad Gateway\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY,
-      },
-      {
-          "HTTP/1.1 503 Service Unavailable\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE,
-      },
-      {
-          "HTTP/1.1 504 Gateway Timeout\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_MAX,
-      },
-      {
-          "HTTP/1.1 505 HTTP Version Not Supported\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_MAX,
-      },
-      {
-          "HTTP/1.1 304 Not Modified\n", BYPASS_EVENT_TYPE_MAX,
-      },
-      {
-          "HTTP/1.1 200 OK\n", BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER,
-      },
-      {
-          "HTTP/1.1 200 OK\n"
-          "Chrome-Proxy: bypass=59\n",
-          BYPASS_EVENT_TYPE_SHORT,
-      },
-      {
-          "HTTP/1.1 502 Bad Gateway\n",
-          BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY,
-      },
-      {
-          "HTTP/1.1 502 Bad Gateway\n"
-          "Chrome-Proxy: bypass=59\n",
-          BYPASS_EVENT_TYPE_SHORT,
-      },
-      {
-          "HTTP/1.1 502 Bad Gateway\n"
-          "Chrome-Proxy: bypass=59\n",
-          BYPASS_EVENT_TYPE_SHORT,
-      },
-      {
-          "HTTP/1.1 414 Request-URI Too Long\n",
-          BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX,
-      },
-      {
-          "HTTP/1.1 414 Request-URI Too Long\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_MAX,
-      },
-      {
-          "HTTP/1.1 407 Proxy Authentication Required\n",
-          BYPASS_EVENT_TYPE_MALFORMED_407,
-      },
-      {
-          "HTTP/1.1 407 Proxy Authentication Required\n"
-          "Proxy-Authenticate: Basic\n"
-          "Via: 1.1 Chrome-Compression-Proxy\n",
-          BYPASS_EVENT_TYPE_MAX,
-      }};
+  } tests[] = {{
+                   "HTTP/1.1 200 OK\n"
+                   "Chrome-Proxy: bypass=0\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_MEDIUM,
+               },
+               {
+                   "HTTP/1.1 200 OK\n"
+                   "Chrome-Proxy: bypass=1\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_SHORT,
+               },
+               {
+                   "HTTP/1.1 200 OK\n"
+                   "Chrome-Proxy: bypass=59\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_SHORT,
+               },
+               {
+                   "HTTP/1.1 200 OK\n"
+                   "Chrome-Proxy: bypass=60\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_MEDIUM,
+               },
+               {
+                   "HTTP/1.1 200 OK\n"
+                   "Chrome-Proxy: bypass=300\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_MEDIUM,
+               },
+               {
+                   "HTTP/1.1 200 OK\n"
+                   "Chrome-Proxy: bypass=301\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_LONG,
+               },
+               {
+                   "HTTP/1.1 200 OK\n"
+                   "Chrome-Proxy: block-once\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_CURRENT,
+               },
+               {
+                   "HTTP/1.1 500 Internal Server Error\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR,
+               },
+               {
+                   "HTTP/1.1 501 Not Implemented\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_MAX,
+               },
+               {
+                   "HTTP/1.1 502 Bad Gateway\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY,
+               },
+               {
+                   "HTTP/1.1 503 Service Unavailable\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE,
+               },
+               {
+                   "HTTP/1.1 504 Gateway Timeout\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_MAX,
+               },
+               {
+                   "HTTP/1.1 505 HTTP Version Not Supported\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_MAX,
+               },
+               {
+                   "HTTP/1.1 304 Not Modified\n", BYPASS_EVENT_TYPE_MAX,
+               },
+               {
+                   "HTTP/1.1 200 OK\n", BYPASS_EVENT_TYPE_MAX,
+               },
+               {
+                   "HTTP/1.1 200 OK\n"
+                   "Chrome-Proxy: bypass=59\n",
+                   BYPASS_EVENT_TYPE_SHORT,
+               },
+               {
+                   "HTTP/1.1 502 Bad Gateway\n",
+                   BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY,
+               },
+               {
+                   "HTTP/1.1 502 Bad Gateway\n"
+                   "Chrome-Proxy: bypass=59\n",
+                   BYPASS_EVENT_TYPE_SHORT,
+               },
+               {
+                   "HTTP/1.1 502 Bad Gateway\n"
+                   "Chrome-Proxy: bypass=59\n",
+                   BYPASS_EVENT_TYPE_SHORT,
+               },
+               {
+                   "HTTP/1.1 414 Request-URI Too Long\n", BYPASS_EVENT_TYPE_MAX,
+               },
+               {
+                   "HTTP/1.1 414 Request-URI Too Long\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_MAX,
+               },
+               {
+                   "HTTP/1.1 407 Proxy Authentication Required\n",
+                   BYPASS_EVENT_TYPE_MALFORMED_407,
+               },
+               {
+                   "HTTP/1.1 407 Proxy Authentication Required\n"
+                   "Proxy-Authenticate: Basic\n"
+                   "Via: 1.1 Chrome-Compression-Proxy\n",
+                   BYPASS_EVENT_TYPE_MAX,
+               }};
   for (size_t i = 0; i < arraysize(tests); ++i) {
     std::string headers(tests[i].headers);
     HeadersToRaw(&headers);
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index b7a75fb..7710743 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -124,10 +124,6 @@
   return kLoFiFlagFieldTrial;
 }
 
-const char* GetWarmupCallbackParamName() {
-  return kWarmupFetchCallbackEnabledParam;
-}
-
 const char* GetMissingViaBypassParamName() {
   return kMissingViaBypassDisabledParam;
 }
@@ -170,6 +166,21 @@
       params, "warmup_url", kDefaultWarmupUrl));
 }
 
+bool IsWarmupURLFetchCallbackEnabled() {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          data_reduction_proxy::switches::
+              kDisableDataReductionProxyWarmupURLFetchCallback)) {
+    return false;
+  }
+
+  if (!GetFieldTrialParamByFeatureAsBool(
+          features::kDataReductionProxyRobustConnection,
+          kWarmupFetchCallbackEnabledParam, true)) {
+    return false;
+  }
+  return true;
+}
+
 bool IsWarmupURL(const GURL& url) {
   GURL warmup_url = params::GetWarmupURL();
   return url.host() == warmup_url.host() && url.path() == warmup_url.path();
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index 6a7ce975..7192406 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -127,6 +127,10 @@
 // Returns the warmup URL.
 GURL GetWarmupURL();
 
+// Returns true if the warmup URL fetcher should callback into DRP to report the
+// result of the warmup fetch.
+bool IsWarmupURLFetchCallbackEnabled();
+
 // Returns true if |url| is the warmup url.
 bool IsWarmupURL(const GURL& url);
 
@@ -136,9 +140,6 @@
 // unsuccessful.
 bool IsWhitelistedHttpResponseCodeForProbes(int http_response_code);
 
-// Returns the experiment parameter name to enable the warmup fetch callback.
-const char* GetWarmupCallbackParamName();
-
 // Returns the experiment parameter name to disable missing via header bypasses.
 const char* GetMissingViaBypassParamName();
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index 970b1e4..0e5e839 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -249,6 +249,7 @@
                 params::GetWarmupURL());
     }
     EXPECT_TRUE(params::FetchWarmupProbeURLEnabled());
+    EXPECT_TRUE(params::IsWarmupURLFetchCallbackEnabled());
   }
 }
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
index 95c65471..4fd1b29 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
@@ -78,6 +78,11 @@
 const char kDisableDataReductionProxyWarmupURLFetch[] =
     "disable-data-reduction-proxy-warmup-url-fetch";
 
+// Disables the warmup URL fetcher to callback into DRP to report the result of
+// the warmup fetch.
+const char kDisableDataReductionProxyWarmupURLFetchCallback[] =
+    "disable-data-reduction-proxy-warmup-url-fetch-callback";
+
 // Uses the encoded ClientConfig instead of fetching one from the config server.
 // This value is always used, regardless of error or expiration. The value
 // should be a base64 encoded binary protobuf.
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
index d06ac70..d19d61e 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
@@ -36,6 +36,7 @@
 extern const char kEnableDataReductionProxyForcePingback[];
 extern const char kEnableDataReductionProxySavingsPromo[];
 extern const char kDisableDataReductionProxyWarmupURLFetch[];
+extern const char kDisableDataReductionProxyWarmupURLFetchCallback[];
 
 }  // namespace switches
 }  // namespace data_reduction_proxy
diff --git a/components/domain_reliability/util.cc b/components/domain_reliability/util.cc
index 9d5f16cb..ece9219 100644
--- a/components/domain_reliability/util.cc
+++ b/components/domain_reliability/util.cc
@@ -133,6 +133,7 @@
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_43:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_44:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_45:
+    case net::HttpResponseInfo::CONNECTION_INFO_QUIC_46:
     case net::HttpResponseInfo::CONNECTION_INFO_QUIC_99:
       return "QUIC";
     case net::HttpResponseInfo::NUM_OF_CONNECTION_INFOS:
diff --git a/components/grpc_support/PRESUBMIT.py b/components/grpc_support/PRESUBMIT.py
deleted file mode 100644
index 73b8ce1..0000000
--- a/components/grpc_support/PRESUBMIT.py
+++ /dev/null
@@ -1,23 +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.
-
-"""Presubmit script for components/grpc_support/.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook adds an extra line to the CL description in order to run Cronet
-  tests in addition to CQ bots.
-  """
-
-  # TODO(https://crbug.com/712733): Remove this once Cronet bots are deployed on CQ.
-  try_bots = ['master.tryserver.chromium.android:android_cronet_tester',
-              'luci.chromium.try:ios-simulator-cronet']
-
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl, try_bots, 'Automatically added Cronet trybots to run tests on CQ.')
diff --git a/components/image_fetcher/core/BUILD.gn b/components/image_fetcher/core/BUILD.gn
index 374aa67..325b199 100644
--- a/components/image_fetcher/core/BUILD.gn
+++ b/components/image_fetcher/core/BUILD.gn
@@ -19,7 +19,7 @@
     "request_metadata.h",
   ]
   deps = [
-    "storage",
+    "cache",
   ]
   public_deps = [
     "//base",
@@ -63,9 +63,9 @@
   deps = [
     ":core",
     ":test_support",
-    "storage",
-    "storage:storage_unit_tests",
-    "storage/proto",
+    "cache",
+    "cache:cache_unit_tests",
+    "cache/proto",
     "//components/leveldb_proto:test_support",
     "//components/prefs:test_support",
     "//net",
diff --git a/components/image_fetcher/core/storage/BUILD.gn b/components/image_fetcher/core/cache/BUILD.gn
similarity index 92%
rename from components/image_fetcher/core/storage/BUILD.gn
rename to components/image_fetcher/core/cache/BUILD.gn
index 458fc99..572ebe5 100644
--- a/components/image_fetcher/core/storage/BUILD.gn
+++ b/components/image_fetcher/core/cache/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-static_library("storage") {
+static_library("cache") {
   sources = [
     "image_cache.cc",
     "image_cache.h",
@@ -26,7 +26,7 @@
   ]
 }
 
-source_set("storage_unit_tests") {
+source_set("cache_unit_tests") {
   testonly = true
   sources = [
     "image_cache_unittest.cc",
@@ -34,7 +34,7 @@
     "image_metadata_store_leveldb_unittest.cc",
   ]
   deps = [
-    ":storage",
+    ":cache",
     "proto",
     "//base",
     "//base/test:test_support",
diff --git a/components/image_fetcher/core/storage/DEPS b/components/image_fetcher/core/cache/DEPS
similarity index 100%
rename from components/image_fetcher/core/storage/DEPS
rename to components/image_fetcher/core/cache/DEPS
diff --git a/components/image_fetcher/core/storage/image_cache.cc b/components/image_fetcher/core/cache/image_cache.cc
similarity index 97%
rename from components/image_fetcher/core/storage/image_cache.cc
rename to components/image_fetcher/core/cache/image_cache.cc
index a650c37..f594837 100644
--- a/components/image_fetcher/core/storage/image_cache.cc
+++ b/components/image_fetcher/core/cache/image_cache.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/image_fetcher/core/storage/image_cache.h"
+#include "components/image_fetcher/core/cache/image_cache.h"
 
 #include <algorithm>
 #include <utility>
@@ -15,8 +15,8 @@
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "components/base32/base32.h"
-#include "components/image_fetcher/core/storage/image_data_store.h"
-#include "components/image_fetcher/core/storage/image_metadata_store.h"
+#include "components/image_fetcher/core/cache/image_data_store.h"
+#include "components/image_fetcher/core/cache/image_metadata_store.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
@@ -129,7 +129,7 @@
   queued_requests_.clear();
 
   // TODO(wylieb): Consider delaying eviction as new requests come in via
-  // seperate weak pointers.
+  // separate weak pointers.
   // TODO(wylieb): Log UMA data about starting GC eviction here, then again
   // when it's finished.
   // Once all the queued requests are taken care of, run eviction.
diff --git a/components/image_fetcher/core/storage/image_cache.h b/components/image_fetcher/core/cache/image_cache.h
similarity index 93%
rename from components/image_fetcher/core/storage/image_cache.h
rename to components/image_fetcher/core/cache/image_cache.h
index d7f5fdd..e9218f3 100644
--- a/components/image_fetcher/core/storage/image_cache.h
+++ b/components/image_fetcher/core/cache/image_cache.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_CACHE_H_
-#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_CACHE_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_CACHE_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_CACHE_H_
 
 #include <memory>
 #include <string>
@@ -11,7 +11,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "components/image_fetcher/core/storage/image_store_types.h"
+#include "components/image_fetcher/core/cache/image_store_types.h"
 
 class PrefRegistrySimple;
 class PrefService;
@@ -111,4 +111,4 @@
 
 }  // namespace image_fetcher
 
-#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_CACHE_H_
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_CACHE_H_
diff --git a/components/image_fetcher/core/storage/image_cache_unittest.cc b/components/image_fetcher/core/cache/image_cache_unittest.cc
similarity index 96%
rename from components/image_fetcher/core/storage/image_cache_unittest.cc
rename to components/image_fetcher/core/cache/image_cache_unittest.cc
index cd8c7c5..15ee7c4 100644
--- a/components/image_fetcher/core/storage/image_cache_unittest.cc
+++ b/components/image_fetcher/core/cache/image_cache_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/image_fetcher/core/storage/image_cache.h"
+#include "components/image_fetcher/core/cache/image_cache.h"
 
 #include <map>
 #include <utility>
@@ -12,9 +12,9 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_clock.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "components/image_fetcher/core/storage/image_data_store_disk.h"
-#include "components/image_fetcher/core/storage/image_metadata_store_leveldb.h"
-#include "components/image_fetcher/core/storage/proto/cached_image_metadata.pb.h"
+#include "components/image_fetcher/core/cache/image_data_store_disk.h"
+#include "components/image_fetcher/core/cache/image_metadata_store_leveldb.h"
+#include "components/image_fetcher/core/cache/proto/cached_image_metadata.pb.h"
 #include "components/leveldb_proto/testing/fake_db.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/image_fetcher/core/storage/image_data_store.h b/components/image_fetcher/core/cache/image_data_store.h
similarity index 84%
rename from components/image_fetcher/core/storage/image_data_store.h
rename to components/image_fetcher/core/cache/image_data_store.h
index 14860a33..9ad58c28 100644
--- a/components/image_fetcher/core/storage/image_data_store.h
+++ b/components/image_fetcher/core/cache/image_data_store.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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_H_
-#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_DATA_STORE_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_DATA_STORE_H_
 
 #include <string>
 
-#include "components/image_fetcher/core/storage/image_store_types.h"
+#include "components/image_fetcher/core/cache/image_store_types.h"
 
 namespace image_fetcher {
 
@@ -42,4 +42,4 @@
 };
 }  // namespace image_fetcher
 
-#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_H_
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_DATA_STORE_H_
diff --git a/components/image_fetcher/core/storage/image_data_store_disk.cc b/components/image_fetcher/core/cache/image_data_store_disk.cc
similarity index 98%
rename from components/image_fetcher/core/storage/image_data_store_disk.cc
rename to components/image_fetcher/core/cache/image_data_store_disk.cc
index 6441618b..04909f0 100644
--- a/components/image_fetcher/core/storage/image_data_store_disk.cc
+++ b/components/image_fetcher/core/cache/image_data_store_disk.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/image_fetcher/core/storage/image_data_store_disk.h"
+#include "components/image_fetcher/core/cache/image_data_store_disk.h"
 
 #include <utility>
 #include <vector>
diff --git a/components/image_fetcher/core/storage/image_data_store_disk.h b/components/image_fetcher/core/cache/image_data_store_disk.h
similarity index 84%
rename from components/image_fetcher/core/storage/image_data_store_disk.h
rename to components/image_fetcher/core/cache/image_data_store_disk.h
index d5c3951..0e6a69e 100644
--- a/components/image_fetcher/core/storage/image_data_store_disk.h
+++ b/components/image_fetcher/core/cache/image_data_store_disk.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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_DISK_H_
-#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_DISK_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_DATA_STORE_DISK_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_DATA_STORE_DISK_H_
 
 #include <string>
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "components/image_fetcher/core/storage/image_data_store.h"
-#include "components/image_fetcher/core/storage/image_store_types.h"
+#include "components/image_fetcher/core/cache/image_data_store.h"
+#include "components/image_fetcher/core/cache/image_store_types.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -57,4 +57,4 @@
 };
 }  // namespace image_fetcher
 
-#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_DATA_STORE_DISK_H_
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_DATA_STORE_DISK_H_
diff --git a/components/image_fetcher/core/storage/image_data_store_disk_unittest.cc b/components/image_fetcher/core/cache/image_data_store_disk_unittest.cc
similarity index 98%
rename from components/image_fetcher/core/storage/image_data_store_disk_unittest.cc
rename to components/image_fetcher/core/cache/image_data_store_disk_unittest.cc
index 58a205f..26b13ce 100644
--- a/components/image_fetcher/core/storage/image_data_store_disk_unittest.cc
+++ b/components/image_fetcher/core/cache/image_data_store_disk_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/image_fetcher/core/storage/image_data_store_disk.h"
+#include "components/image_fetcher/core/cache/image_data_store_disk.h"
 
 #include <memory>
 #include <vector>
diff --git a/components/image_fetcher/core/storage/image_metadata_store.h b/components/image_fetcher/core/cache/image_metadata_store.h
similarity index 88%
rename from components/image_fetcher/core/storage/image_metadata_store.h
rename to components/image_fetcher/core/cache/image_metadata_store.h
index c74fb54..b14d381 100644
--- a/components/image_fetcher/core/storage/image_metadata_store.h
+++ b/components/image_fetcher/core/cache/image_metadata_store.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 COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_H_
-#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_METADATA_STORE_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_METADATA_STORE_H_
 
 #include <string>
 
 #include "base/time/time.h"
-#include "components/image_fetcher/core/storage/image_store_types.h"
+#include "components/image_fetcher/core/cache/image_store_types.h"
 
 namespace image_fetcher {
 
@@ -59,4 +59,4 @@
 };
 }  // namespace image_fetcher
 
-#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_H_
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_METADATA_STORE_H_
diff --git a/components/image_fetcher/core/storage/image_metadata_store_leveldb.cc b/components/image_fetcher/core/cache/image_metadata_store_leveldb.cc
similarity index 98%
rename from components/image_fetcher/core/storage/image_metadata_store_leveldb.cc
rename to components/image_fetcher/core/cache/image_metadata_store_leveldb.cc
index a5603b7..8336ef5 100644
--- a/components/image_fetcher/core/storage/image_metadata_store_leveldb.cc
+++ b/components/image_fetcher/core/cache/image_metadata_store_leveldb.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/image_fetcher/core/storage/image_metadata_store_leveldb.h"
+#include "components/image_fetcher/core/cache/image_metadata_store_leveldb.h"
 
 #include <algorithm>
 #include <utility>
@@ -11,7 +11,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
-#include "components/image_fetcher/core/storage/proto/cached_image_metadata.pb.h"
+#include "components/image_fetcher/core/cache/proto/cached_image_metadata.pb.h"
 #include "components/leveldb_proto/proto_database_impl.h"
 
 using image_fetcher::CachedImageMetadataProto;
diff --git a/components/image_fetcher/core/storage/image_metadata_store_leveldb.h b/components/image_fetcher/core/cache/image_metadata_store_leveldb.h
similarity index 89%
rename from components/image_fetcher/core/storage/image_metadata_store_leveldb.h
rename to components/image_fetcher/core/cache/image_metadata_store_leveldb.h
index 12842930..8ed864f 100644
--- a/components/image_fetcher/core/storage/image_metadata_store_leveldb.h
+++ b/components/image_fetcher/core/cache/image_metadata_store_leveldb.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_LEVELDB_H_
-#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_LEVELDB_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_METADATA_STORE_LEVELDB_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_METADATA_STORE_LEVELDB_H_
 
 #include <memory>
 #include <string>
@@ -11,8 +11,8 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "components/image_fetcher/core/storage/image_metadata_store.h"
-#include "components/image_fetcher/core/storage/image_store_types.h"
+#include "components/image_fetcher/core/cache/image_metadata_store.h"
+#include "components/image_fetcher/core/cache/image_store_types.h"
 #include "components/leveldb_proto/proto_database.h"
 
 namespace base {
@@ -94,4 +94,4 @@
 
 }  // namespace image_fetcher
 
-#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_METADATA_STORE_LEVELDB_H_
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_METADATA_STORE_LEVELDB_H_
diff --git a/components/image_fetcher/core/storage/image_metadata_store_leveldb_unittest.cc b/components/image_fetcher/core/cache/image_metadata_store_leveldb_unittest.cc
similarity index 98%
rename from components/image_fetcher/core/storage/image_metadata_store_leveldb_unittest.cc
rename to components/image_fetcher/core/cache/image_metadata_store_leveldb_unittest.cc
index ca7282d..9c474eb 100644
--- a/components/image_fetcher/core/storage/image_metadata_store_leveldb_unittest.cc
+++ b/components/image_fetcher/core/cache/image_metadata_store_leveldb_unittest.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 "components/image_fetcher/core/storage/image_metadata_store_leveldb.h"
+#include "components/image_fetcher/core/cache/image_metadata_store_leveldb.h"
 
 #include <map>
 #include <utility>
 
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_clock.h"
-#include "components/image_fetcher/core/storage/image_store_types.h"
-#include "components/image_fetcher/core/storage/proto/cached_image_metadata.pb.h"
+#include "components/image_fetcher/core/cache/image_store_types.h"
+#include "components/image_fetcher/core/cache/proto/cached_image_metadata.pb.h"
 #include "components/leveldb_proto/testing/fake_db.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/image_fetcher/core/storage/image_store_types.h b/components/image_fetcher/core/cache/image_store_types.h
similarity index 80%
rename from components/image_fetcher/core/storage/image_store_types.h
rename to components/image_fetcher/core/cache/image_store_types.h
index b90edacc..fa64ae8 100644
--- a/components/image_fetcher/core/storage/image_store_types.h
+++ b/components/image_fetcher/core/cache/image_store_types.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_STORE_TYPES_H_
-#define COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_STORE_TYPES_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_STORE_TYPES_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_STORE_TYPES_H_
 
 #include <string>
 #include <vector>
@@ -31,4 +31,4 @@
 
 }  // namespace image_fetcher
 
-#endif  // COMPONENTS_IMAGE_FETCHER_CORE_STORAGE_IMAGE_STORE_TYPES_H_
+#endif  // COMPONENTS_IMAGE_FETCHER_CORE_CACHE_IMAGE_STORE_TYPES_H_
diff --git a/components/image_fetcher/core/storage/proto/BUILD.gn b/components/image_fetcher/core/cache/proto/BUILD.gn
similarity index 100%
rename from components/image_fetcher/core/storage/proto/BUILD.gn
rename to components/image_fetcher/core/cache/proto/BUILD.gn
diff --git a/components/image_fetcher/core/storage/proto/cached_image_metadata.proto b/components/image_fetcher/core/cache/proto/cached_image_metadata.proto
similarity index 100%
rename from components/image_fetcher/core/storage/proto/cached_image_metadata.proto
rename to components/image_fetcher/core/cache/proto/cached_image_metadata.proto
diff --git a/components/image_fetcher/core/cached_image_fetcher.cc b/components/image_fetcher/core/cached_image_fetcher.cc
index 7bfd3a9..a62f1505 100644
--- a/components/image_fetcher/core/cached_image_fetcher.cc
+++ b/components/image_fetcher/core/cached_image_fetcher.cc
@@ -9,9 +9,9 @@
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/timer/elapsed_timer.h"
+#include "components/image_fetcher/core/cache/image_cache.h"
 #include "components/image_fetcher/core/image_decoder.h"
 #include "components/image_fetcher/core/request_metadata.h"
-#include "components/image_fetcher/core/storage/image_cache.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image.h"
diff --git a/components/image_fetcher/core/cached_image_fetcher_service.cc b/components/image_fetcher/core/cached_image_fetcher_service.cc
index fb26375e2..9979a532 100644
--- a/components/image_fetcher/core/cached_image_fetcher_service.cc
+++ b/components/image_fetcher/core/cached_image_fetcher_service.cc
@@ -7,10 +7,10 @@
 #include <utility>
 
 #include "base/time/clock.h"
+#include "components/image_fetcher/core/cache/image_cache.h"
 #include "components/image_fetcher/core/cached_image_fetcher.h"
 #include "components/image_fetcher/core/image_decoder.h"
 #include "components/image_fetcher/core/image_fetcher_impl.h"
-#include "components/image_fetcher/core/storage/image_cache.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace image_fetcher {
diff --git a/components/image_fetcher/core/cached_image_fetcher_unittest.cc b/components/image_fetcher/core/cached_image_fetcher_unittest.cc
index d183755b..aaf3f73 100644
--- a/components/image_fetcher/core/cached_image_fetcher_unittest.cc
+++ b/components/image_fetcher/core/cached_image_fetcher_unittest.cc
@@ -18,13 +18,13 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_clock.h"
 #include "base/threading/sequenced_task_runner_handle.h"
+#include "components/image_fetcher/core/cache/image_cache.h"
+#include "components/image_fetcher/core/cache/image_data_store_disk.h"
+#include "components/image_fetcher/core/cache/image_metadata_store_leveldb.h"
+#include "components/image_fetcher/core/cache/proto/cached_image_metadata.pb.h"
 #include "components/image_fetcher/core/fake_image_decoder.h"
 #include "components/image_fetcher/core/image_fetcher_impl.h"
 #include "components/image_fetcher/core/image_fetcher_types.h"
-#include "components/image_fetcher/core/storage/image_cache.h"
-#include "components/image_fetcher/core/storage/image_data_store_disk.h"
-#include "components/image_fetcher/core/storage/image_metadata_store_leveldb.h"
-#include "components/image_fetcher/core/storage/proto/cached_image_metadata.pb.h"
 #include "components/leveldb_proto/testing/fake_db.h"
 #include "components/prefs/testing_pref_service.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
diff --git a/components/offline_pages/resources/PRESUBMIT.py b/components/offline_pages/resources/PRESUBMIT.py
deleted file mode 100644
index af7a56f..0000000
--- a/components/offline_pages/resources/PRESUBMIT.py
+++ /dev/null
@@ -1,11 +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.
-
-def PostUploadHook(cl, change, output_api):
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:closure_compilation',
-    ],
-    'Automatically added optional Closure bots to run on CQ.')
diff --git a/components/password_manager/content/common/credential_manager_mojom_traits.cc b/components/password_manager/content/common/credential_manager_mojom_traits.cc
index 21cbdedd..dff9cb42 100644
--- a/components/password_manager/content/common/credential_manager_mojom_traits.cc
+++ b/components/password_manager/content/common/credential_manager_mojom_traits.cc
@@ -95,6 +95,7 @@
     case blink::mojom::CredentialManagerError::CREDENTIAL_NOT_RECOGNIZED:
     case blink::mojom::CredentialManagerError::NOT_IMPLEMENTED:
     case blink::mojom::CredentialManagerError::NOT_FOCUSED:
+    case blink::mojom::CredentialManagerError::RESIDENT_CREDENTIALS_UNSUPPORTED:
     case blink::mojom::CredentialManagerError::UNKNOWN:
       *output = password_manager::CredentialManagerError::UNKNOWN;
       return true;
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc
index 8437c3a..15e8cc6 100644
--- a/components/password_manager/core/browser/new_password_form_manager.cc
+++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -101,10 +101,12 @@
     const base::WeakPtr<PasswordManagerDriver>& driver,
     const FormData& observed_form,
     FormFetcher* form_fetcher,
-    std::unique_ptr<FormSaver> form_saver)
+    std::unique_ptr<FormSaver> form_saver,
+    scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder)
     : client_(client),
       driver_(driver),
       observed_form_(observed_form),
+      metrics_recorder_(metrics_recorder),
       owned_form_fetcher_(
           form_fetcher ? nullptr
                        : std::make_unique<FormFetcherImpl>(
@@ -118,8 +120,10 @@
       // |is_possible_change_password_form| in |votes_uploader_| constructor
       votes_uploader_(client, false /* is_possible_change_password_form */),
       weak_ptr_factory_(this) {
-  metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
-      client_->IsMainFrameSecure(), client_->GetUkmSourceId());
+  if (!metrics_recorder_) {
+    metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
+        client_->IsMainFrameSecure(), client_->GetUkmSourceId());
+  }
   metrics_recorder_->RecordFormSignature(CalculateFormSignature(observed_form));
 
   if (owned_form_fetcher_)
@@ -379,9 +383,7 @@
   // blacklisting entry if needed.
   auto result = std::make_unique<NewPasswordFormManager>(
       client_, base::WeakPtr<PasswordManagerDriver>(), observed_form_,
-      fetcher.get(), form_saver_->Clone());
-
-  result->metrics_recorder_ = metrics_recorder_;
+      fetcher.get(), form_saver_->Clone(), metrics_recorder_);
 
   // The constructor only can take a weak pointer to the fetcher, so moving the
   // owning one needs to happen explicitly.
diff --git a/components/password_manager/core/browser/new_password_form_manager.h b/components/password_manager/core/browser/new_password_form_manager.h
index 622cfe83..e539d68 100644
--- a/components/password_manager/core/browser/new_password_form_manager.h
+++ b/components/password_manager/core/browser/new_password_form_manager.h
@@ -44,12 +44,15 @@
   // |this| creates an instance of it itself (meant for production code). Once
   // the fetcher is shared between PasswordFormManager instances, it will be
   // required that |form_fetcher| is not null. |form_saver| is used to
-  // save/update the form.
-  NewPasswordFormManager(PasswordManagerClient* client,
-                         const base::WeakPtr<PasswordManagerDriver>& driver,
-                         const autofill::FormData& observed_form,
-                         FormFetcher* form_fetcher,
-                         std::unique_ptr<FormSaver> form_saver);
+  // save/update the form. |metrics_recorder| records metrics for |*this|. If
+  // null a new instance will be created.
+  NewPasswordFormManager(
+      PasswordManagerClient* client,
+      const base::WeakPtr<PasswordManagerDriver>& driver,
+      const autofill::FormData& observed_form,
+      FormFetcher* form_fetcher,
+      std::unique_ptr<FormSaver> form_saver,
+      scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder);
 
   ~NewPasswordFormManager() override;
 
diff --git a/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
index db0a589..9e65c9e9 100644
--- a/components/password_manager/core/browser/new_password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -253,7 +253,7 @@
     fetcher_->Fetch();
     form_manager_.reset(new NewPasswordFormManager(
         &client_, driver_.AsWeakPtr(), observed_form, fetcher_.get(),
-        std::make_unique<NiceMock<MockFormSaver>>()));
+        std::make_unique<NiceMock<MockFormSaver>>(), nullptr));
   }
 };
 
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index ee5d4d0..f155279f 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -883,7 +883,7 @@
         client_,
         driver ? driver->AsWeakPtr() : base::WeakPtr<PasswordManagerDriver>(),
         new_form->form_data, nullptr,
-        std::make_unique<FormSaverImpl>(client_->GetPasswordStore())));
+        std::make_unique<FormSaverImpl>(client_->GetPasswordStore()), nullptr));
     form_managers_.back()->set_old_parsing_result(*new_form);
   }
 }
diff --git a/components/policy/core/browser/browser_policy_connector.h b/components/policy/core/browser/browser_policy_connector.h
index 29ec51a..2566bfd 100644
--- a/components/policy/core/browser/browser_policy_connector.h
+++ b/components/policy/core/browser/browser_policy_connector.h
@@ -42,6 +42,9 @@
   // Checks whether this device is under any kind of enterprise management.
   virtual bool IsEnterpriseManaged() const = 0;
 
+  // Checks whether there are any machine-level policies configured.
+  virtual bool HasMachineLevelPolicies() = 0;
+
   // Cleans up the connector before it can be safely deleted.
   void Shutdown() override;
 
diff --git a/components/safe_browsing/browser/referrer_chain_provider.h b/components/safe_browsing/browser/referrer_chain_provider.h
index 1ca8753..dd193d7 100644
--- a/components/safe_browsing/browser/referrer_chain_provider.h
+++ b/components/safe_browsing/browser/referrer_chain_provider.h
@@ -26,6 +26,8 @@
     SUCCESS_LANDING_REFERRER = 3,  // Successfully identified landing referrer.
     INVALID_URL = 4,
     NAVIGATION_EVENT_NOT_FOUND = 5,
+    SUCCESS_REFERRER = 6,  // Successfully identified extra referrers beyond the
+                           // landing referrer.
 
     // Always at the end.
     ATTRIBUTION_FAILURE_TYPE_MAX
diff --git a/components/safe_browsing/proto/csd.proto b/components/safe_browsing/proto/csd.proto
index 025b0c2..fb1e16f 100644
--- a/components/safe_browsing/proto/csd.proto
+++ b/components/safe_browsing/proto/csd.proto
@@ -660,6 +660,11 @@
     // chain is empty or partially missing, we will add/append recent navigation
     // events to this list. RECENT_NAVIGATION type is set for these cases.
     RECENT_NAVIGATION = 6;
+
+    // The REFERRER type is used for entries that recede the LANDING_REFERRER in
+    // the referrer chain, when more than two gestures are included in the
+    // referrer chain.
+    REFERRER = 7;
   }
 
   enum NavigationInitiation {
diff --git a/components/safe_browsing/web_ui/safe_browsing_ui.cc b/components/safe_browsing/web_ui/safe_browsing_ui.cc
index 75a4fd7..684efde6 100644
--- a/components/safe_browsing/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/web_ui/safe_browsing_ui.cc
@@ -376,6 +376,9 @@
     case ReferrerChainEntry::RECENT_NAVIGATION:
       url_type = "RECENT_NAVIGATION";
       break;
+    case ReferrerChainEntry::REFERRER:
+      url_type = "REFERRER";
+      break;
   }
   referrer_dict.SetKey("type", base::Value(url_type));
 
diff --git a/components/sync/model/fake_model_type_sync_bridge.h b/components/sync/model/fake_model_type_sync_bridge.h
index 89e91f83..10a8aac 100644
--- a/components/sync/model/fake_model_type_sync_bridge.h
+++ b/components/sync/model/fake_model_type_sync_bridge.h
@@ -147,7 +147,8 @@
   // Sets storage key which will be ignored by bridge.
   void SetKeyToIgnore(const std::string key);
 
-  const Store& db() { return *db_; }
+  const Store& db() const { return *db_; }
+  Store* mutable_db() { return db_.get(); }
 
  protected:
   // Contains all of the data and metadata state.
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc
index 902e04a..90b3ccd 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -271,13 +271,22 @@
 
 ModelTypeSyncBridge::StopSyncResponse
 ClientTagBasedModelTypeProcessor::ClearMetadataAndResetState() {
-  // Clear metadata.
-  std::unique_ptr<MetadataChangeList> change_list =
-      bridge_->CreateMetadataChangeList();
-  for (const auto& kv : entities_) {
-    change_list->ClearMetadata(kv.second->storage_key());
+  std::unique_ptr<MetadataChangeList> change_list;
+
+  // Clear metadata if MergeSyncData() was called before.
+  if (model_type_state_.initial_sync_done()) {
+    change_list = bridge_->CreateMetadataChangeList();
+    for (const auto& kv : entities_) {
+      change_list->ClearMetadata(kv.second->storage_key());
+    }
+    change_list->ClearModelTypeState();
+  } else {
+    // All changes before the initial sync is done are ignored and in fact they
+    // were never persisted by the bridge (prior to MergeSyncData), so we should
+    // be tracking no entities.
+    DCHECK(entities_.empty());
   }
-  change_list->ClearModelTypeState();
+
   const ModelTypeSyncBridge::StopSyncResponse response =
       bridge_->ApplyStopSyncChanges(std::move(change_list));
 
@@ -436,6 +445,7 @@
   DCHECK(!client_tag_hash.empty());
   DCHECK(!storage_key.empty());
   DCHECK(!bridge_->SupportsGetStorageKey());
+  DCHECK(model_type_state_.initial_sync_done());
 
   ProcessorEntityTracker* entity = GetEntityForTagHash(client_tag_hash);
   DCHECK(entity);
@@ -452,6 +462,7 @@
 void ClientTagBasedModelTypeProcessor::UntrackEntity(
     const EntityData& entity_data) {
   const std::string& client_tag_hash = entity_data.client_tag_hash;
+  DCHECK(model_type_state_.initial_sync_done());
   DCHECK(!client_tag_hash.empty());
   DCHECK(GetEntityForTagHash(client_tag_hash)->storage_key().empty());
   entities_.erase(client_tag_hash);
@@ -459,6 +470,8 @@
 
 void ClientTagBasedModelTypeProcessor::UntrackEntityForStorageKey(
     const std::string& storage_key) {
+  DCHECK(model_type_state_.initial_sync_done());
+
   // Look-up the client tag hash.
   auto iter = storage_key_to_tag_hash_.find(storage_key);
   if (iter == storage_key_to_tag_hash_.end()) {
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
index 1769b9f..ffb48e7 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -1348,6 +1348,26 @@
   worker()->VerifyPendingCommits({{kHash1}, {kHash2}, {kHash3}});
 }
 
+// Test proper handling of disable-sync before initial sync done.
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldNotClearBridgeMetadataPriorToMergeSyncData) {
+  // Populate the bridge's metadata with some non-empty values for us to later
+  // check that it hasn't been cleared.
+  const std::string kTestEncryptionKeyName = "TestEncryptionKey";
+  ModelTypeState model_type_state(db().model_type_state());
+  model_type_state.set_encryption_key_name(kTestEncryptionKeyName);
+  bridge()->mutable_db()->set_model_type_state(model_type_state);
+
+  ModelReadyToSync();
+  OnSyncStarting();
+  ASSERT_FALSE(type_processor()->IsTrackingMetadata());
+
+  type_processor()->OnSyncStopping(CLEAR_METADATA);
+  EXPECT_FALSE(type_processor()->IsTrackingMetadata());
+  EXPECT_EQ(kTestEncryptionKeyName,
+            db().model_type_state().encryption_key_name());
+}
+
 // Test re-encrypt everything when desired encryption key changes.
 TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldReencryptCommitsWithNewKey) {
   InitializeToReadyState();
diff --git a/components/viz/PRESUBMIT.py b/components/viz/PRESUBMIT.py
index c18ec999..c8bef10 100644
--- a/components/viz/PRESUBMIT.py
+++ b/components/viz/PRESUBMIT.py
@@ -14,21 +14,3 @@
   import presubmit_checks as ps
   white_list=(r'^components[\\/]viz[\\/].*\.(cc|h)$',)
   return ps.RunAllChecks(input_api, output_api, white_list)
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, on Android) in addition to the regular CQ try
-  bots. These tests don't yet run by default on
-  android_n5x_swarming_rel, but viz changes need to run them.
-
-  When adding/removing tests here, ensure that both gpu/PRESUBMIT.py and
-  ui/gl/PRESUBMIT.py are updated.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
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 38ebfd9a..00eedc5 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
@@ -189,17 +189,21 @@
 void SkiaOutputSurfaceImplOnGpu::SwapBuffers(OutputSurfaceFrame frame) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(sk_surface_);
+  base::TimeTicks swap_start, swap_end;
   if (!gpu_service_->is_using_vulkan()) {
     if (!gl_context_->MakeCurrent(gl_surface_.get())) {
       LOG(FATAL) << "Failed to make current.";
       // TODO(penghuang): Handle the failure.
     }
+    swap_start = base::TimeTicks::Now();
     OnSwapBuffers();
     gl_surface_->SwapBuffers(frame.need_presentation_feedback
                                  ? buffer_presented_callback_
                                  : base::DoNothing());
+    swap_end = base::TimeTicks::Now();
   } else {
 #if BUILDFLAG(ENABLE_VULKAN)
+    swap_start = base::TimeTicks::Now();
     OnSwapBuffers();
     auto backend = sk_surface_->getBackendRenderTarget(
         SkSurface::kFlushRead_BackendHandleAccess);
@@ -216,10 +220,17 @@
     DidSwapBuffersComplete(params);
 
     CreateSkSurfaceForVulkan();
+    swap_end = base::TimeTicks::Now();
 #else
     NOTREACHED();
 #endif
   }
+  for (auto& latency : frame.latency_info) {
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, swap_start, 1);
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT, swap_end, 1);
+  }
 }
 
 void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
diff --git a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
index 2e2c709d..b5825dd 100644
--- a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
@@ -936,7 +936,7 @@
 // Disabled due to flakiness. See https://crbug.com/894572.
 // Integration test for the deletion of cache entries.
 IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest,
-                       Disabled_CacheIntegrationTest) {
+                       DISABLED_CacheIntegrationTest) {
   GURL url1 = GetURLForHTTPSHost1("/cachetime/foo");
   GURL url2 = GetURLForHTTPSHost1("/cachetime/bar");
   GURL url3 = GetURLForHTTPSHost2("/cachetime/foo");
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index 32d7899b..e549424 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -183,7 +183,7 @@
   if (!AttachSession(session.get(), registry))
     return false;
   renderer_channel_.AttachSession(session.get());
-  sessions_.insert(session.get());
+  sessions_.push_back(session.get());
   session_by_client_[client] = std::move(session);
   if (sessions_.size() == 1)
     NotifyAttached();
@@ -240,7 +240,8 @@
       std::move(session_by_client_[client]);
   // Make sure we dispose session prior to reporting it to the host.
   session->Dispose();
-  sessions_.erase(session.get());
+  sessions_.erase(
+      std::remove(sessions_.begin(), sessions_.end(), session.get()));
   session_by_client_.erase(client);
   DetachSession(session.get());
   DevToolsManager* manager = DevToolsManager::GetInstance();
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 1db75042..a2a4578 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -97,7 +97,7 @@
   DevToolsIOContext* GetIOContext() { return &io_context_; }
   DevToolsRendererChannel* GetRendererChannel() { return &renderer_channel_; }
 
-  base::flat_set<DevToolsSession*>& sessions() { return sessions_; }
+  const std::vector<DevToolsSession*>& sessions() const { return sessions_; }
 
  private:
   friend class DevToolsAgentHost;  // for static methods
@@ -117,7 +117,7 @@
                              TargetRegistry* registry);
 
   const std::string id_;
-  base::flat_set<DevToolsSession*> sessions_;
+  std::vector<DevToolsSession*> sessions_;
   base::flat_map<DevToolsAgentHostClient*, std::unique_ptr<DevToolsSession>>
       session_by_client_;
   DevToolsIOContext io_context_;
diff --git a/content/browser/host_zoom_map_impl_unittest.cc b/content/browser/host_zoom_map_impl_unittest.cc
index 0e0d2fc..665c093c 100644
--- a/content/browser/host_zoom_map_impl_unittest.cc
+++ b/content/browser/host_zoom_map_impl_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_clock.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -19,8 +20,7 @@
 class HostZoomMapTest : public testing::Test {
  public:
   HostZoomMapTest()
-      : ui_thread_(BrowserThread::UI,
-                   task_environment_.GetMainThreadTaskRunner()) {}
+      : ui_thread_(BrowserThread::UI, base::ThreadTaskRunnerHandle::Get()) {}
 
  protected:
   base::test::ScopedTaskEnvironment task_environment_;
diff --git a/content/browser/indexed_db/indexed_db_callbacks.cc b/content/browser/indexed_db/indexed_db_callbacks.cc
index d5369e55..84b21d6 100644
--- a/content/browser/indexed_db/indexed_db_callbacks.cc
+++ b/content/browser/indexed_db/indexed_db_callbacks.cc
@@ -141,6 +141,8 @@
   ~IOThreadHelper();
 
   void SendError(const IndexedDBDatabaseError& error);
+  void SendSuccessNamesAndVersionsList(
+      std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions);
   void SendSuccessStringList(const std::vector<base::string16>& value);
   void SendBlocked(int64_t existing_version);
   void SendUpgradeNeeded(SafeIOThreadConnectionWrapper connection,
@@ -236,6 +238,20 @@
   }
 }
 
+void IndexedDBCallbacks::OnSuccess(
+    std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!complete_);
+  DCHECK(io_helper_);
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(&IOThreadHelper::SendSuccessNamesAndVersionsList,
+                     base::Unretained(io_helper_.get()),
+                     std::move(names_and_versions)));
+  complete_ = true;
+}
+
 void IndexedDBCallbacks::OnSuccess(const std::vector<base::string16>& value) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!complete_);
@@ -526,6 +542,18 @@
   callbacks_->Error(error.code(), error.message());
 }
 
+void IndexedDBCallbacks::IOThreadHelper::SendSuccessNamesAndVersionsList(
+    std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (!callbacks_)
+    return;
+  if (!dispatcher_host_) {
+    OnConnectionError();
+    return;
+  }
+  callbacks_->SuccessNamesAndVersionsList(std::move(names_and_versions));
+}
+
 void IndexedDBCallbacks::IOThreadHelper::SendSuccessStringList(
     const std::vector<base::string16>& value) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/content/browser/indexed_db/indexed_db_callbacks.h b/content/browser/indexed_db/indexed_db_callbacks.h
index daada34..0728d44f 100644
--- a/content/browser/indexed_db/indexed_db_callbacks.h
+++ b/content/browser/indexed_db/indexed_db_callbacks.h
@@ -53,6 +53,10 @@
 
   virtual void OnError(const IndexedDBDatabaseError& error);
 
+  // IndexedDBFactory::databases
+  virtual void OnSuccess(
+      std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions);
+
   // IndexedDBFactory::GetDatabaseNames
   virtual void OnSuccess(const std::vector<base::string16>& string);
 
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index f7c98abe..fbd6d40 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -94,6 +94,9 @@
         indexed_db_context_(std::move(indexed_db_context)) {}
   ~IDBSequenceHelper() {}
 
+  void GetDatabaseInfoOnIDBThread(scoped_refptr<IndexedDBCallbacks> callbacks,
+                                  const url::Origin& origin);
+
   void GetDatabaseNamesOnIDBThread(scoped_refptr<IndexedDBCallbacks> callbacks,
                                    const url::Origin& origin);
   void OpenOnIDBThread(
@@ -165,6 +168,24 @@
           base::Unretained(this)));
 }
 
+void IndexedDBDispatcherHost::GetDatabaseInfo(
+    blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
+    const url::Origin& origin) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (!IsValidOrigin(origin)) {
+    mojo::ReportBadMessage(kInvalidOrigin);
+    return;
+  }
+
+  scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
+      this->AsWeakPtr(), origin, std::move(callbacks_info), IDBTaskRunner()));
+  IDBTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&IDBSequenceHelper::GetDatabaseInfoOnIDBThread,
+                                base::Unretained(idb_helper_),
+                                std::move(callbacks), origin));
+}
+
 void IndexedDBDispatcherHost::GetDatabaseNames(
     blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
     const url::Origin& origin) {
@@ -281,6 +302,16 @@
   return indexed_db_context_->TaskRunner();
 }
 
+void IndexedDBDispatcherHost::IDBSequenceHelper::GetDatabaseInfoOnIDBThread(
+    scoped_refptr<IndexedDBCallbacks> callbacks,
+    const url::Origin& origin) {
+  DCHECK(indexed_db_context_->TaskRunner()->RunsTasksInCurrentSequence());
+
+  base::FilePath indexed_db_path = indexed_db_context_->data_path();
+  indexed_db_context_->GetIDBFactory()->GetDatabaseInfo(callbacks, origin,
+                                                        indexed_db_path);
+}
+
 void IndexedDBDispatcherHost::IDBSequenceHelper::GetDatabaseNamesOnIDBThread(
     scoped_refptr<IndexedDBCallbacks> callbacks,
     const url::Origin& origin) {
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.h b/content/browser/indexed_db/indexed_db_dispatcher_host.h
index a4babe25..af46f84 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.h
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -82,6 +82,9 @@
   ~IndexedDBDispatcherHost() override;
 
   // blink::mojom::IDBFactory implementation:
+  void GetDatabaseInfo(
+      blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
+      const url::Origin& origin) override;
   void GetDatabaseNames(
       blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
       const url::Origin& origin) override;
diff --git a/content/browser/indexed_db/indexed_db_factory.h b/content/browser/indexed_db/indexed_db_factory.h
index 9edf2b3..4ade927 100644
--- a/content/browser/indexed_db/indexed_db_factory.h
+++ b/content/browser/indexed_db/indexed_db_factory.h
@@ -38,7 +38,9 @@
 
   virtual void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
                                bool forced_close) = 0;
-
+  virtual void GetDatabaseInfo(scoped_refptr<IndexedDBCallbacks> callbacks,
+                               const url::Origin& origin,
+                               const base::FilePath& data_directory) = 0;
   virtual void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
                                 const url::Origin& origin,
                                 const base::FilePath& data_directory) = 0;
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.cc b/content/browser/indexed_db/indexed_db_factory_impl.cc
index e625f0e..392ca7d8 100644
--- a/content/browser/indexed_db/indexed_db_factory_impl.cc
+++ b/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -399,6 +399,50 @@
   }
 }
 
+void IndexedDBFactoryImpl::GetDatabaseInfo(
+    scoped_refptr<IndexedDBCallbacks> callbacks,
+    const Origin& origin,
+    const base::FilePath& data_directory) {
+  IDB_TRACE("IndexedDBFactoryImpl::GetDatabaseInfo");
+  // TODO(dmurph): Plumb data_loss back to script eventually?
+  IndexedDBDataLossInfo data_loss_info;
+  bool disk_full;
+  leveldb::Status s;
+  // TODO(dmurph): Handle this error
+  scoped_refptr<IndexedDBBackingStore> backing_store =
+      OpenBackingStore(origin, data_directory, &data_loss_info, &disk_full, &s);
+  if (!backing_store.get()) {
+    IndexedDBDatabaseError error(
+        blink::kWebIDBDatabaseExceptionUnknownError,
+        ASCIIToUTF16("Internal error opening backing store for "
+                     "indexedDB.databases()."));
+    callbacks->OnError(error);
+    if (s.IsCorruption())
+      HandleBackingStoreCorruption(origin, error);
+    return;
+  }
+
+  IndexedDBMetadataCoding metadata_coding;
+  std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions;
+  s = metadata_coding.ReadDatabaseNamesAndVersions(
+      backing_store->db(), backing_store->origin_identifier(),
+      &names_and_versions);
+  if (!s.ok()) {
+    DLOG(ERROR) << "Internal error getting database info";
+    IndexedDBDatabaseError error(blink::kWebIDBDatabaseExceptionUnknownError,
+                                 "Internal error opening backing store for "
+                                 "indexedDB.databases().");
+    callbacks->OnError(error);
+    backing_store = nullptr;
+    if (s.IsCorruption())
+      HandleBackingStoreCorruption(origin, error);
+    return;
+  }
+  callbacks->OnSuccess(std::move(names_and_versions));
+  backing_store = nullptr;
+  ReleaseBackingStore(origin, false /* immediate */);
+}
+
 void IndexedDBFactoryImpl::GetDatabaseNames(
     scoped_refptr<IndexedDBCallbacks> callbacks,
     const Origin& origin,
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.h b/content/browser/indexed_db/indexed_db_factory_impl.h
index 669ba66..5a95564 100644
--- a/content/browser/indexed_db/indexed_db_factory_impl.h
+++ b/content/browser/indexed_db/indexed_db_factory_impl.h
@@ -52,7 +52,9 @@
   // content::IndexedDBFactory overrides:
   void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
                        bool forced_close) override;
-
+  void GetDatabaseInfo(scoped_refptr<IndexedDBCallbacks> callbacks,
+                       const url::Origin& origin,
+                       const base::FilePath& data_directory) override;
   void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
                         const url::Origin& origin,
                         const base::FilePath& data_directory) override;
diff --git a/content/browser/indexed_db/indexed_db_metadata_coding.cc b/content/browser/indexed_db/indexed_db_metadata_coding.cc
index 6ffb4bb..f9d0f7a 100644
--- a/content/browser/indexed_db/indexed_db_metadata_coding.cc
+++ b/content/browser/indexed_db/indexed_db_metadata_coding.cc
@@ -18,6 +18,7 @@
 using blink::IndexedDBDatabaseMetadata;
 using blink::IndexedDBIndexMetadata;
 using blink::IndexedDBKeyPath;
+using blink::mojom::IDBNameAndVersionPtr;
 using blink::IndexedDBObjectStoreMetadata;
 using leveldb::Status;
 
@@ -324,15 +325,16 @@
 }
 
 template <typename DatabaseOrTransaction>
-Status ReadDatabaseNamesInternal(DatabaseOrTransaction* db_or_transaction,
-                                 const std::string& origin_identifier,
-                                 std::vector<base::string16>* names) {
+Status ReadDatabaseNamesAndVersionsInternal(
+    DatabaseOrTransaction* db_or_transaction,
+    const std::string& origin_identifier,
+    std::vector<blink::mojom::IDBNameAndVersionPtr>* names_and_versions) {
   const std::string start_key =
       DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier);
   const std::string stop_key =
       DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier);
 
-  DCHECK(names->empty());
+  DCHECK(names_and_versions->empty());
   std::unique_ptr<LevelDBIterator> it = CreateIterator(db_or_transaction);
   Status s;
   for (s = it->Seek(start_key);
@@ -343,7 +345,7 @@
     DatabaseNameKey database_name_key;
     if (!DatabaseNameKey::Decode(&slice, &database_name_key) ||
         !slice.empty()) {
-      // TODO(dmurph): Change UMA name to ReadDatabaseNames.
+      // TODO(dmurph): Change UMA name to ReadDatabaseNamesAndVersionsInternal.
       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES);
       continue;
     }
@@ -369,10 +371,11 @@
     }
 
     // Ignore stale metadata from failed initial opens.
-    if (database_version != IndexedDBDatabaseMetadata::DEFAULT_VERSION)
-      names->push_back(database_name_key.database_name());
+    if (database_version != IndexedDBDatabaseMetadata::DEFAULT_VERSION) {
+      names_and_versions->push_back(blink::mojom::IDBNameAndVersion::New(
+          database_name_key.database_name(), database_version));
+    }
   }
-
   if (!s.ok())
     INTERNAL_READ_ERROR(GET_DATABASE_NAMES);
 
@@ -453,18 +456,38 @@
 IndexedDBMetadataCoding::IndexedDBMetadataCoding() = default;
 IndexedDBMetadataCoding::~IndexedDBMetadataCoding() = default;
 
+Status IndexedDBMetadataCoding::ReadDatabaseNamesAndVersions(
+    LevelDBDatabase* db,
+    const std::string& origin_identifier,
+    std::vector<blink::mojom::IDBNameAndVersionPtr>* names_and_versions) {
+  return ReadDatabaseNamesAndVersionsInternal(db, origin_identifier,
+                                              names_and_versions);
+}
+
 Status IndexedDBMetadataCoding::ReadDatabaseNames(
     LevelDBDatabase* db,
     const std::string& origin_identifier,
     std::vector<base::string16>* names) {
-  return ReadDatabaseNamesInternal(db, origin_identifier, names);
+  std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions;
+  Status s = ReadDatabaseNamesAndVersionsInternal(db, origin_identifier,
+                                                  &names_and_versions);
+  for (const blink::mojom::IDBNameAndVersionPtr& nav : names_and_versions) {
+    names->push_back(nav->name);
+  }
+  return s;
 }
 
 Status IndexedDBMetadataCoding::ReadDatabaseNames(
     LevelDBTransaction* transaction,
     const std::string& origin_identifier,
     std::vector<base::string16>* names) {
-  return ReadDatabaseNamesInternal(transaction, origin_identifier, names);
+  std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions;
+  Status s = ReadDatabaseNamesAndVersionsInternal(
+      transaction, origin_identifier, &names_and_versions);
+  for (const blink::mojom::IDBNameAndVersionPtr& nav : names_and_versions) {
+    names->push_back(nav->name);
+  }
+  return s;
 }
 
 Status IndexedDBMetadataCoding::ReadMetadataForDatabaseName(
diff --git a/content/browser/indexed_db/indexed_db_metadata_coding.h b/content/browser/indexed_db/indexed_db_metadata_coding.h
index e6b579e..7179df9 100644
--- a/content/browser/indexed_db/indexed_db_metadata_coding.h
+++ b/content/browser/indexed_db/indexed_db_metadata_coding.h
@@ -14,6 +14,7 @@
 #include "base/strings/string16.h"
 #include "content/common/content_export.h"
 #include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
 #include "third_party/leveldatabase/src/include/leveldb/status.h"
 
 namespace blink {
@@ -47,6 +48,12 @@
       const std::string& origin_identifier,
       std::vector<base::string16>* names);
 
+  // Reads in the list of database names and versions for the given origin.
+  virtual leveldb::Status ReadDatabaseNamesAndVersions(
+      LevelDBDatabase* db,
+      const std::string& origin_identifier,
+      std::vector<blink::mojom::IDBNameAndVersionPtr>* names_and_versions);
+
   // Reads in metadata for the database and all object stores & indices.
   // Note: the database name is not populated in |metadata|.
   virtual leveldb::Status ReadMetadataForDatabaseName(
diff --git a/content/browser/indexed_db/mock_indexed_db_factory.h b/content/browser/indexed_db/mock_indexed_db_factory.h
index 2d928950..53274cf 100644
--- a/content/browser/indexed_db/mock_indexed_db_factory.h
+++ b/content/browser/indexed_db/mock_indexed_db_factory.h
@@ -25,6 +25,10 @@
                void(scoped_refptr<IndexedDBCallbacks> callbacks,
                     const url::Origin& origin,
                     const base::FilePath& data_directory));
+  MOCK_METHOD3(GetDatabaseInfo,
+               void(scoped_refptr<IndexedDBCallbacks> callbacks,
+                    const url::Origin& origin,
+                    const base::FilePath& data_directory));
   MOCK_METHOD4(
       OpenProxy,
       void(const base::string16& name,
diff --git a/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h b/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h
index ee92e16..f821627 100644
--- a/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h
+++ b/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h
@@ -29,6 +29,9 @@
 
   MOCK_METHOD2(Error, void(int32_t code, const base::string16& message));
 
+  MOCK_METHOD1(SuccessNamesAndVersionsList,
+               void(std::vector<blink::mojom::IDBNameAndVersionPtr> list));
+
   MOCK_METHOD1(SuccessStringList,
                void(const std::vector<base::string16>& value));
 
diff --git a/content/browser/loader/throttling_resource_handler_unittest.cc b/content/browser/loader/throttling_resource_handler_unittest.cc
index 0e6dbf7e4..f5e538c 100644
--- a/content/browser/loader/throttling_resource_handler_unittest.cc
+++ b/content/browser/loader/throttling_resource_handler_unittest.cc
@@ -176,9 +176,7 @@
 class ThrottlingResourceHandlerTest : public testing::Test {
  public:
   ThrottlingResourceHandlerTest()
-      : task_environment_(
-            base::test::ScopedTaskEnvironment::MainThreadType::IO),
-        never_started_url_request_(
+      : never_started_url_request_(
             request_context_.CreateRequest(GURL(kInitialUrl),
                                            net::DEFAULT_PRIORITY,
                                            &never_started_url_request_delegate_,
@@ -224,7 +222,8 @@
 
  protected:
   // Needs to be first, so it's destroyed last.
-  base::test::ScopedTaskEnvironment task_environment_;
+  base::test::ScopedTaskEnvironment task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::IO};
 
   // Machinery to construct a URLRequest that's just used as an argument to
   // methods that expect one, and is never actually started.
diff --git a/content/browser/media/encrypted_media_browsertest.cc b/content/browser/media/encrypted_media_browsertest.cc
index 02faa50..442db8c 100644
--- a/content/browser/media/encrypted_media_browsertest.cc
+++ b/content/browser/media/encrypted_media_browsertest.cc
@@ -18,6 +18,7 @@
 #include "media/base/test_data_util.h"
 #include "media/media_buildflags.h"
 #include "media/mojo/buildflags.h"
+#include "third_party/libaom/av1_buildflags.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/build_info.h"
@@ -68,6 +69,11 @@
     "video/mp4; codecs=\"vp09.02.10.10.01.02.02.02.00\"";
 #endif  // !defined(OS_ANDROID)
 
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+const char kWebMAv1VideoOnly[] = "video/webm; codecs=\"av01.0.04M.08\"";
+const char kMp4Av1VideoOnly[] = "video/mp4; codecs=\"av01.0.04M.08\"";
+#endif  // BUILDFLAG(ENABLE_AV1_DECODER)
+
 // EME-specific test results and errors.
 const char kEmeKeyError[] = "KEYERROR";
 const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
@@ -281,14 +287,6 @@
   TestSimplePlayback("bear-320x240-opus-av_enc-v.webm", kWebMOpusAudioVp9Video);
 }
 
-// TODO(crbug.com/707127): Decide when it's supported on Android.
-#if !defined(OS_ANDROID)
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VP9Profile2Video_WebM) {
-  TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.webm",
-                     kWebMVp9Profile2VideoOnly);
-}
-#endif
-
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4_FLAC) {
   RunMultipleFileTest(std::string(), std::string(), "bear-flac-cenc.mp4",
                       kMp4FlacAudioOnly, media::kEnded);
@@ -305,6 +303,12 @@
 
 // TODO(crbug.com/707127): Decide when it's supported on Android.
 #if !defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
+                       Playback_VideoOnly_WebM_VP9Profile2) {
+  TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.webm",
+                     kWebMVp9Profile2VideoOnly);
+}
+
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_VP9Profile2) {
   // MP4 without MSE is not support yet, http://crbug.com/170793.
   if (CurrentSourceType() != SrcType::MSE) {
@@ -314,7 +318,22 @@
   TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.mp4",
                      kMp4Vp9Profile2VideoOnly);
 }
-#endif
+#endif  // !defined(OS_ANDROID)
+
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_AV1) {
+  TestSimplePlayback("bear-av1-cenc.webm", kWebMAv1VideoOnly);
+}
+
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_AV1) {
+  // MP4 without MSE is not support yet, http://crbug.com/170793.
+  if (CurrentSourceType() != SrcType::MSE) {
+    DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
+    return;
+  }
+  TestSimplePlayback("bear-av1-cenc.mp4", kMp4Av1VideoOnly);
+}
+#endif  // BUILDFLAG(ENABLE_AV1_DECODER)
 
 // Strictly speaking this is not an "encrypted" media test. Keep it here for
 // completeness.
diff --git a/content/browser/media/midi_host_unittest.cc b/content/browser/media/midi_host_unittest.cc
index 388548b..42e9dcec 100644
--- a/content/browser/media/midi_host_unittest.cc
+++ b/content/browser/media/midi_host_unittest.cc
@@ -13,7 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_task_environment.h"
 #include "content/common/media/midi_messages.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "media/midi/midi_manager.h"
 #include "media/midi/midi_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -117,11 +117,7 @@
 
 class MidiHostTest : public testing::Test {
  public:
-  MidiHostTest()
-      : io_browser_thread_(BrowserThread::IO,
-                           task_environment_.GetMainThreadTaskRunner()),
-        data_(kNoteOn, kNoteOn + arraysize(kNoteOn)),
-        port_id_(0) {
+  MidiHostTest() : data_(kNoteOn, kNoteOn + base::size(kNoteOn)), port_id_(0) {
     std::unique_ptr<FakeMidiManagerFactory> factory =
         std::make_unique<FakeMidiManagerFactory>();
     factory_ = factory->GetWeakPtr();
@@ -174,8 +170,7 @@
   }
 
  private:
-  base::test::ScopedTaskEnvironment task_environment_;
-  TestBrowserThread io_browser_thread_;
+  TestBrowserThreadBundle thread_bundle_;
 
   std::vector<uint8_t> data_;
   int32_t port_id_;
diff --git a/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc b/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
index c2dfa60..8d15382 100644
--- a/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
+++ b/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/run_loop.h"
+#include "build/build_config.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -135,7 +136,13 @@
 // wheel scroll latching is enabled the wheel event will be still sent to the
 // document's scrolling element and the document's scrolling element will
 // continue scrolling.
-IN_PROC_BROWSER_TEST_F(WheelScrollLatchingBrowserTest, WheelEventTarget) {
+// Disabled on Android due to flakiness. See https://crbug.com/894572.
+#if defined(OS_ANDROID)
+#define MAYBE_WheelEventTarget DISABLED_WheelEventTarget
+#else
+#define MAYBE_WheelEventTarget WheelEventTarget
+#endif
+IN_PROC_BROWSER_TEST_F(WheelScrollLatchingBrowserTest, MAYBE_WheelEventTarget) {
   LoadURL(kWheelEventLatchingDataURL);
   EXPECT_EQ(0, ExecuteScriptAndExtractInt("documentWheelEventCounter"));
   EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
diff --git a/content/browser/screen_orientation/screen_orientation_provider.cc b/content/browser/screen_orientation/screen_orientation_provider.cc
index 8f1a0a3..6d2e9140 100644
--- a/content/browser/screen_orientation/screen_orientation_provider.cc
+++ b/content/browser/screen_orientation/screen_orientation_provider.cc
@@ -120,6 +120,10 @@
   delegate_ = delegate;
 }
 
+ScreenOrientationDelegate* ScreenOrientationProvider::GetDelegateForTesting() {
+  return delegate_;
+}
+
 void ScreenOrientationProvider::DidToggleFullscreenModeForTab(
     bool entered_fullscreen,
     bool will_cause_resize) {
diff --git a/content/browser/screen_orientation/screen_orientation_provider.h b/content/browser/screen_orientation/screen_orientation_provider.h
index 9d16e0fe..9e9f963 100644
--- a/content/browser/screen_orientation/screen_orientation_provider.h
+++ b/content/browser/screen_orientation/screen_orientation_provider.h
@@ -42,7 +42,8 @@
 
   // Provide a delegate which creates delegates for platform implementations.
   // The delegate is not owned by ScreenOrientationProvider.
-  static void SetDelegate(ScreenOrientationDelegate* delegate_);
+  static void SetDelegate(ScreenOrientationDelegate* delegate);
+  static ScreenOrientationDelegate* GetDelegateForTesting();
 
   // WebContentsObserver
   void DidToggleFullscreenModeForTab(bool entered_fullscreen,
diff --git a/content/browser/streams/stream_url_request_job_unittest.cc b/content/browser/streams/stream_url_request_job_unittest.cc
index 6d3cd75d..92083246 100644
--- a/content/browser/streams/stream_url_request_job_unittest.cc
+++ b/content/browser/streams/stream_url_request_job_unittest.cc
@@ -55,9 +55,7 @@
     StreamRegistry* registry_;
   };
 
-  StreamURLRequestJobTest()
-      : task_environment_(
-            base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+  StreamURLRequestJobTest() {}
 
   void SetUp() override {
     registry_.reset(new StreamRegistry());
@@ -109,7 +107,8 @@
   }
 
  protected:
-  base::test::ScopedTaskEnvironment task_environment_;
+  base::test::ScopedTaskEnvironment task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::IO};
   std::unique_ptr<StreamRegistry> registry_;
 
   net::URLRequestContext url_request_context_;
diff --git a/content/browser/tracing/background_tracing_config_unittest.cc b/content/browser/tracing/background_tracing_config_unittest.cc
index e75249cd..06265218 100644
--- a/content/browser/tracing/background_tracing_config_unittest.cc
+++ b/content/browser/tracing/background_tracing_config_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "content/browser/tracing/background_tracing_config_impl.h"
 #include "content/browser/tracing/background_tracing_rule.h"
@@ -18,8 +19,7 @@
 class BackgroundTracingConfigTest : public testing::Test {
  public:
   BackgroundTracingConfigTest()
-      : ui_thread_(BrowserThread::UI,
-                   task_environment_.GetMainThreadTaskRunner()) {}
+      : ui_thread_(BrowserThread::UI, base::ThreadTaskRunnerHandle::Get()) {}
 
  protected:
   base::test::ScopedTaskEnvironment task_environment_;
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index a413f86..4b1116ed 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -583,6 +583,16 @@
     return;
   }
 
+  if (options->authenticator_selection &&
+      options->authenticator_selection->require_resident_key) {
+    // Disallow the creation of resident credentials.
+    InvokeCallbackAndCleanup(
+        std::move(callback),
+        blink::mojom::AuthenticatorStatus::RESIDENT_CREDENTIALS_UNSUPPORTED,
+        nullptr, Focus::kDontCheck);
+    return;
+  }
+
   DCHECK(make_credential_response_callback_.is_null());
   make_credential_response_callback_ = std::move(callback);
 
@@ -676,6 +686,15 @@
     return;
   }
 
+  if (options->allow_credentials.empty()) {
+    // Chrome currently does not support any resident keys.
+    InvokeCallbackAndCleanup(
+        std::move(callback),
+        blink::mojom::AuthenticatorStatus::RESIDENT_CREDENTIALS_UNSUPPORTED,
+        nullptr);
+    return;
+  }
+
   if (options->appid) {
     alternative_application_parameter_ =
         ProcessAppIdExtension(*options->appid, caller_origin);
@@ -1096,4 +1115,4 @@
 #endif
 }
 
-}  // namespace content
+}  // namespace content
\ No newline at end of file
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index c0091c5..11bf5db1 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -400,6 +400,11 @@
     scoped_feature_list_->InitAndEnableFeature(feature);
   }
 
+  void DisableFeature(const base::Feature& feature) {
+    scoped_feature_list_.emplace();
+    scoped_feature_list_->InitAndDisableFeature(feature);
+  }
+
  protected:
   std::unique_ptr<AuthenticatorImpl> authenticator_impl_;
   service_manager::mojom::ConnectorRequest request_;
@@ -527,8 +532,8 @@
   EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status());
 }
 
-// Test that MakeCredential request times out with NOT_ALLOWED_ERROR if resident
-// key is requested for U2F devices on create().
+// Test that MakeCredential request returns if resident
+// key is requested on create().
 TEST_F(AuthenticatorImplTest, MakeCredentialResidentKey) {
   SimulateNavigation(GURL(kTestOrigin1));
   device::test::ScopedVirtualFidoDevice scoped_virtual_device;
@@ -547,7 +552,10 @@
   base::RunLoop().RunUntilIdle();
   task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
   callback_receiver.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status());
+  EXPECT_EQ(AuthenticatorStatus::RESIDENT_CREDENTIALS_UNSUPPORTED,
+            callback_receiver.status());
+
+  // TODO add CTAP device
 }
 
 // Test that MakeCredential request times out with NOT_ALLOWED_ERROR if a
@@ -831,22 +839,16 @@
 
 TEST_F(AuthenticatorImplTest, TestCableDiscoveryByDefault) {
   auto authenticator = ConnectToAuthenticator();
-// On Windows caBLE should be disabled by default regardless of version.
-#if defined(OS_WIN)
-  EXPECT_FALSE(SupportsTransportProtocol(
-      device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy));
-// Otherwise, it should be enabled by default if BLE is supported.
-#else
+
+  // caBLE should be enabled by default if BLE is supported.
   EXPECT_EQ(
       device::BluetoothAdapterFactory::Get().IsLowEnergySupported(),
       SupportsTransportProtocol(
           device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy));
-#endif
 }
 
 TEST_F(AuthenticatorImplTest, TestCableDiscoveryDisabledWithFlag) {
-  scoped_feature_list_.emplace();
-  scoped_feature_list_->InitAndDisableFeature(features::kWebAuthCable);
+  DisableFeature(features::kWebAuthCable);
 
   auto authenticator = ConnectToAuthenticator();
   EXPECT_FALSE(SupportsTransportProtocol(
@@ -932,7 +934,7 @@
   base::RunLoop().RunUntilIdle();
   task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
   callback_receiver.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::CREDENTIAL_NOT_RECOGNIZED,
+  EXPECT_EQ(AuthenticatorStatus::RESIDENT_CREDENTIALS_UNSUPPORTED,
             callback_receiver.status());
 }
 
@@ -1707,6 +1709,7 @@
 TEST_F(AuthenticatorContentBrowserClientTest, IsUVPAAFalseIfFeatureFlagOff) {
   if (__builtin_available(macOS 10.12.2, *)) {
     // Touch ID is hardware-supported and embedder-enabled, but the flag is off.
+    DisableFeature(device::kWebAuthTouchId);
     device::fido::mac::ScopedTouchIdTestEnvironment touch_id_test_environment;
     touch_id_test_environment.SetTouchIdAvailable(true);
     test_client_.supports_touch_id = true;
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc
index 49b3267..615c349cb 100644
--- a/content/browser/webauth/webauth_browsertest.cc
+++ b/content/browser/webauth/webauth_browsertest.cc
@@ -67,9 +67,9 @@
     "webauth: NotAllowedError: The operation either timed out or was not "
     "allowed. See: https://w3c.github.io/webauthn/#sec-assertion-privacy.";
 
-constexpr char kInvalidStateErrorMessage[] =
-    "webauth: InvalidStateError: The user attempted to use an authenticator "
-    "that recognized none of the provided credentials.";
+constexpr char kResidentCredentialsErrorMessage[] =
+    "webauth: NotSupportedError: Resident credentials or empty "
+    "'allowCredentials' lists are not supported at this time.";
 
 constexpr char kRelyingPartySecurityErrorMessage[] =
     "webauth: SecurityError: The relying party ID 'localhost' is not a "
@@ -736,7 +736,7 @@
         shell()->web_contents()->GetMainFrame(),
         BuildCreateCallWithParameters(parameters), &result));
 
-    ASSERT_EQ(kTimeoutErrorMessage, result);
+    ASSERT_EQ(kResidentCredentialsErrorMessage, result);
   }
 }
 
@@ -807,7 +807,7 @@
   ASSERT_TRUE(content::ExecuteScriptAndExtractString(
       shell()->web_contents()->GetMainFrame(),
       BuildGetCallWithParameters(parameters), &result));
-  ASSERT_EQ(kInvalidStateErrorMessage, result);
+  ASSERT_EQ(kResidentCredentialsErrorMessage, result);
 }
 
 // WebAuthBrowserBleDisabledTest
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index a8d1973..de790d1 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -500,7 +500,7 @@
 // using pairingless BLE protocol on Windows.
 // https://w3c.github.io/webauthn
 const base::Feature kWebAuthCableWin{"WebAuthenticationCableWin",
-                                     base::FEATURE_DISABLED_BY_DEFAULT};
+                                     base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Controls whether AuthenticatorAttestationResponse contains a getTransports
 // member to return the set of transports supported by an authenticator.
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 6860439..9079f5d 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -48,6 +48,7 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
+#include "content/browser/screen_orientation/screen_orientation_provider.h"
 #include "content/browser/service_manager/service_manager_context.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_contents_view.h"
@@ -1989,6 +1990,10 @@
          frame_connector->GetParentRenderWidgetHostView();
 }
 
+ScreenOrientationDelegate* GetScreenOrientationDelegate() {
+  return ScreenOrientationProvider::GetDelegateForTesting();
+}
+
 std::vector<RenderWidgetHostView*> GetInputEventRouterRenderWidgetHostViews(
     WebContents* web_contents) {
   return static_cast<WebContentsImpl*>(web_contents)
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 4a3005ce..f12fc43f 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -879,6 +879,10 @@
 // WebContents.
 bool IsInnerInterstitialPageConnected(InterstitialPage* interstitial_page);
 
+// Returns the screen orientation provider that's been set via
+// WebContents::SetScreenOrientationDelegate(). May return null.
+ScreenOrientationDelegate* GetScreenOrientationDelegate();
+
 // Returns all the RenderWidgetHostViews inside the |web_contents| that are
 // registered in the RenderWidgetHostInputEventRouter.
 std::vector<RenderWidgetHostView*> GetInputEventRouterRenderWidgetHostViews(
diff --git a/content/renderer/indexed_db/indexed_db_callbacks_impl.cc b/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
index 81d7278..792237fa 100644
--- a/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
+++ b/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
 
 using blink::IndexedDBDatabaseMetadata;
@@ -20,6 +21,7 @@
 using blink::WebIDBCallbacks;
 using blink::WebIDBDatabase;
 using blink::WebIDBMetadata;
+using blink::WebIDBNameAndVersion;
 using blink::WebIDBValue;
 using blink::WebString;
 using blink::WebVector;
@@ -75,6 +77,12 @@
   return web_value;
 }
 
+WebIDBNameAndVersion ConvertNameVersion(
+    const blink::mojom::IDBNameAndVersionPtr& name_and_version) {
+  return WebIDBNameAndVersion(WebString::FromUTF16(name_and_version->name),
+                              name_and_version->version);
+}
+
 }  // namespace
 
 // static
@@ -122,6 +130,17 @@
   callbacks_.reset();
 }
 
+void IndexedDBCallbacksImpl::SuccessNamesAndVersionsList(
+    std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions) {
+  WebVector<WebIDBNameAndVersion> web_names_and_versions;
+  web_names_and_versions.reserve(names_and_versions.size());
+  for (const blink::mojom::IDBNameAndVersionPtr& name_version :
+       names_and_versions)
+    web_names_and_versions.emplace_back(ConvertNameVersion(name_version));
+  callbacks_->OnSuccess(web_names_and_versions);
+  callbacks_.reset();
+}
+
 void IndexedDBCallbacksImpl::SuccessStringList(
     const std::vector<base::string16>& value) {
   WebVector<WebString> web_value(value.size());
diff --git a/content/renderer/indexed_db/indexed_db_callbacks_impl.h b/content/renderer/indexed_db/indexed_db_callbacks_impl.h
index 7fad138c..fd57217 100644
--- a/content/renderer/indexed_db/indexed_db_callbacks_impl.h
+++ b/content/renderer/indexed_db/indexed_db_callbacks_impl.h
@@ -37,6 +37,9 @@
 
   // blink::mojom::IDBCallbacks implementation:
   void Error(int32_t code, const base::string16& message) override;
+  void SuccessNamesAndVersionsList(
+      std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions)
+      override;
   void SuccessStringList(const std::vector<base::string16>& value) override;
   void Blocked(int64_t existing_version) override;
   void UpgradeNeeded(blink::mojom::IDBDatabaseAssociatedPtrInfo database_info,
diff --git a/content/renderer/indexed_db/mock_webidbcallbacks.h b/content/renderer/indexed_db/mock_webidbcallbacks.h
index a52677c..ec337180 100644
--- a/content/renderer/indexed_db/mock_webidbcallbacks.h
+++ b/content/renderer/indexed_db/mock_webidbcallbacks.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_metadata.h"
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
 #include "third_party/blink/public/platform/web_blob_info.h"
 #include "third_party/blink/public/web/web_heap.h"
@@ -30,6 +31,8 @@
                     const blink::WebIDBKey& primaryKey,
                     const blink::WebIDBValue& value));
 
+  MOCK_METHOD1(OnSuccess,
+               void(const blink::WebVector<blink::WebIDBNameAndVersion>&));
   MOCK_METHOD1(OnSuccess, void(const blink::WebVector<blink::WebString>&));
 
   void OnSuccess(blink::WebIDBCursor* cursor,
diff --git a/content/renderer/indexed_db/webidbfactory_impl.cc b/content/renderer/indexed_db/webidbfactory_impl.cc
index fb3fd54..62682a0 100644
--- a/content/renderer/indexed_db/webidbfactory_impl.cc
+++ b/content/renderer/indexed_db/webidbfactory_impl.cc
@@ -29,6 +29,17 @@
 
 WebIDBFactoryImpl::~WebIDBFactoryImpl() = default;
 
+void WebIDBFactoryImpl::GetDatabaseInfo(
+    WebIDBCallbacks* callbacks,
+    const WebSecurityOrigin& origin,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+  auto callbacks_impl = std::make_unique<IndexedDBCallbacksImpl>(
+      base::WrapUnique(callbacks), IndexedDBCallbacksImpl::kNoTransaction,
+      nullptr);
+  factory_->GetDatabaseInfo(GetCallbacksProxy(std::move(callbacks_impl)),
+                            url::Origin(origin));
+}
+
 void WebIDBFactoryImpl::GetDatabaseNames(
     WebIDBCallbacks* callbacks,
     const WebSecurityOrigin& origin,
diff --git a/content/renderer/indexed_db/webidbfactory_impl.h b/content/renderer/indexed_db/webidbfactory_impl.h
index 8aab9cfe..f4a704b 100644
--- a/content/renderer/indexed_db/webidbfactory_impl.h
+++ b/content/renderer/indexed_db/webidbfactory_impl.h
@@ -27,6 +27,10 @@
   ~WebIDBFactoryImpl() override;
 
   // See WebIDBFactory.h for documentation on these functions.
+  void GetDatabaseInfo(
+      blink::WebIDBCallbacks* callbacks,
+      const blink::WebSecurityOrigin& origin,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   void GetDatabaseNames(
       blink::WebIDBCallbacks* callbacks,
       const blink::WebSecurityOrigin& origin,
diff --git a/content/renderer/loader/shared_memory_data_consumer_handle_unittest.cc b/content/renderer/loader/shared_memory_data_consumer_handle_unittest.cc
index 77f7542b..711942c 100644
--- a/content/renderer/loader/shared_memory_data_consumer_handle_unittest.cc
+++ b/content/renderer/loader/shared_memory_data_consumer_handle_unittest.cc
@@ -134,7 +134,7 @@
         scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
         const base::Closure& on_done)
         : handle_(std::move(handle)),
-          main_thread_task_runner_(main_thread_task_runner),
+          main_thread_task_runner_(std::move(main_thread_task_runner)),
           on_done_(on_done) {}
 
     const std::string& result() const { return result_; }
@@ -1044,7 +1044,8 @@
 TEST_F(ThreadedSharedMemoryDataConsumerHandleTest, Read) {
   base::RunLoop run_loop;
   auto operation = std::make_unique<ReadDataOperation>(
-      std::move(handle_), base::ThreadTaskRunnerHandle::Get(),
+      std::move(handle_),
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
       run_loop.QuitClosure());
   scoped_refptr<Logger> logger(new Logger);
 
diff --git a/content/renderer/loader/url_response_body_consumer_unittest.cc b/content/renderer/loader/url_response_body_consumer_unittest.cc
index 36b002b..a2e1a0906 100644
--- a/content/renderer/loader/url_response_body_consumer_unittest.cc
+++ b/content/renderer/loader/url_response_body_consumer_unittest.cc
@@ -154,8 +154,8 @@
         blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
         TRAFFIC_ANNOTATION_FOR_TESTS, false,
         false /* pass_response_pipe_to_peer */,
-        std::make_unique<TestRequestPeer>(context,
-                                          base::ThreadTaskRunnerHandle::Get()),
+        std::make_unique<TestRequestPeer>(
+            context, blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &factory_),
         std::vector<std::unique_ptr<URLLoaderThrottle>>(),
@@ -183,7 +183,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
-      base::ThreadTaskRunnerHandle::Get()));
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
   mojo::ScopedDataPipeProducerHandle writer =
@@ -208,7 +208,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
-      base::ThreadTaskRunnerHandle::Get()));
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
   consumer->OnComplete(network::URLLoaderCompletionStatus());
@@ -243,7 +243,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
-      base::ThreadTaskRunnerHandle::Get()));
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
   consumer->OnComplete(network::URLLoaderCompletionStatus());
@@ -275,7 +275,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
-      base::ThreadTaskRunnerHandle::Get()));
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
   network::URLLoaderCompletionStatus status;
@@ -318,7 +318,7 @@
 
   scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer(
       request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle),
-      base::ThreadTaskRunnerHandle::Get()));
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   consumer->ArmOrNotify();
 
   Run(&context);
diff --git a/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc b/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc
index da0eb4f..980fe64 100644
--- a/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc
+++ b/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc
@@ -67,7 +67,7 @@
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
       const base::Closure& on_done)
       : handle_(new WebDataConsumerHandleImpl(std::move(handle))),
-        main_thread_task_runner_(main_thread_task_runner),
+        main_thread_task_runner_(std::move(main_thread_task_runner)),
         on_done_(on_done) {}
 
   const std::string& result() const { return result_; }
@@ -128,7 +128,7 @@
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
       const base::Closure& on_done)
       : handle_(new WebDataConsumerHandleImpl(std::move(handle))),
-        main_thread_task_runner_(main_thread_task_runner),
+        main_thread_task_runner_(std::move(main_thread_task_runner)),
         on_done_(on_done) {}
 
   const std::string& result() const { return result_; }
@@ -247,7 +247,8 @@
 TEST_F(WebDataConsumerHandleImplTest, ReadData) {
   base::RunLoop run_loop;
   auto operation = std::make_unique<ReadDataOperation>(
-      std::move(consumer_), base::ThreadTaskRunnerHandle::Get(),
+      std::move(consumer_),
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
       run_loop.QuitClosure());
 
   base::Thread t("DataConsumerHandle test thread");
@@ -269,7 +270,8 @@
 TEST_F(WebDataConsumerHandleImplTest, TwoPhaseReadData) {
   base::RunLoop run_loop;
   auto operation = std::make_unique<TwoPhaseReadDataOperation>(
-      std::move(consumer_), base::ThreadTaskRunnerHandle::Get(),
+      std::move(consumer_),
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
       run_loop.QuitClosure());
 
   base::Thread t("DataConsumerHandle test thread");
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index c14b9a4..eed1235 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -129,7 +129,7 @@
 namespace content {
 
 // static
-media::WebMediaPlayerParams::SurfaceLayerMode
+blink::WebMediaPlayer::SurfaceLayerMode
 MediaFactory::GetVideoSurfaceLayerMode() {
   // LayoutTests do not support SurfaceLayer by default at the moment.
   // See https://crbug.com/838128
@@ -137,33 +137,19 @@
       content::RenderThreadImpl::current();
   if (render_thread && render_thread->layout_test_mode() &&
       !render_thread->LayoutTestModeUsesDisplayCompositorPixelDump()) {
-    return media::WebMediaPlayerParams::SurfaceLayerMode::kNever;
+    return blink::WebMediaPlayer::SurfaceLayerMode::kNever;
   }
 
   if (features::IsMultiProcessMash())
-    return media::WebMediaPlayerParams::SurfaceLayerMode::kNever;
+    return blink::WebMediaPlayer::SurfaceLayerMode::kNever;
 
   if (base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo))
-    return media::WebMediaPlayerParams::SurfaceLayerMode::kAlways;
+    return blink::WebMediaPlayer::SurfaceLayerMode::kAlways;
 
   if (base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideoPIP))
-    return media::WebMediaPlayerParams::SurfaceLayerMode::kOnDemand;
+    return blink::WebMediaPlayer::SurfaceLayerMode::kOnDemand;
 
-  return media::WebMediaPlayerParams::SurfaceLayerMode::kNever;
-}
-
-bool MediaFactory::VideoSurfaceLayerEnabledForMS() {
-  // LayoutTests do not support SurfaceLayer by default at the moment.
-  // See https://crbug.com/838128
-  content::RenderThreadImpl* render_thread =
-      content::RenderThreadImpl::current();
-  if (render_thread && render_thread->layout_test_mode() &&
-      !render_thread->LayoutTestModeUsesDisplayCompositorPixelDump()) {
-    return false;
-  }
-
-  return base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideoMS) &&
-         !features::IsMultiProcessMash();
+  return blink::WebMediaPlayer::SurfaceLayerMode::kNever;
 }
 
 MediaFactory::MediaFactory(
@@ -291,11 +277,11 @@
   scoped_refptr<base::SingleThreadTaskRunner>
       video_frame_compositor_task_runner;
   std::unique_ptr<blink::WebVideoFrameSubmitter> submitter;
-  media::WebMediaPlayerParams::SurfaceLayerMode use_surface_layer_for_video =
+  blink::WebMediaPlayer::SurfaceLayerMode use_surface_layer_for_video =
       GetVideoSurfaceLayerMode();
   bool use_sync_primitives = false;
   if (use_surface_layer_for_video ==
-      media::WebMediaPlayerParams::SurfaceLayerMode::kAlways) {
+      blink::WebMediaPlayer::SurfaceLayerMode::kAlways) {
     // Run the compositor / frame submitter on its own thread.
     video_frame_compositor_task_runner =
         render_thread->CreateVideoFrameCompositorTaskRunner();
@@ -313,7 +299,7 @@
   }
 
   if (use_surface_layer_for_video !=
-      media::WebMediaPlayerParams::SurfaceLayerMode::kNever) {
+      blink::WebMediaPlayer::SurfaceLayerMode::kNever) {
     submitter = blink::WebVideoFrameSubmitter::Create(
         base::BindRepeating(
             &PostContextProviderToCallback,
@@ -530,10 +516,34 @@
         render_frame_->GetTaskRunner(blink::TaskType::kInternalMediaRealTime);
 
   scoped_refptr<base::SingleThreadTaskRunner>
-      media_stream_compositor_task_runner =
-          VideoSurfaceLayerEnabledForMS()
-              ? render_thread->CreateVideoFrameCompositorTaskRunner()
-              : compositor_task_runner;
+      video_frame_compositor_task_runner;
+  std::unique_ptr<blink::WebVideoFrameSubmitter> submitter;
+  blink::WebMediaPlayer::SurfaceLayerMode use_surface_layer_for_video =
+      GetVideoSurfaceLayerMode();
+
+  // Currently we do not support kOnDemand for MediaStreams.
+  if (use_surface_layer_for_video ==
+      blink::WebMediaPlayer::SurfaceLayerMode::kOnDemand) {
+    use_surface_layer_for_video =
+        blink::WebMediaPlayer::SurfaceLayerMode::kNever;
+  }
+
+  if (use_surface_layer_for_video ==
+      blink::WebMediaPlayer::SurfaceLayerMode::kAlways) {
+    // Run the compositor / frame submitter on its own thread.
+    video_frame_compositor_task_runner =
+        render_thread->CreateVideoFrameCompositorTaskRunner();
+    // We must use sync primitives on this thread.
+    const bool use_sync_primitives = true;
+
+    submitter = blink::WebVideoFrameSubmitter::Create(
+        base::BindRepeating(
+            &PostContextProviderToCallback,
+            RenderThreadImpl::current()->GetCompositorMainThreadTaskRunner()),
+        settings, use_sync_primitives);
+  } else {
+    video_frame_compositor_task_runner = compositor_task_runner;
+  }
 
   DCHECK(layer_tree_view);
   return new WebMediaPlayerMS(
@@ -542,7 +552,7 @@
           url::Origin(security_origin).GetURL(),
           render_frame_->GetTaskRunner(blink::TaskType::kInternalMedia)),
       CreateMediaStreamRendererFactory(), render_thread->GetIOTaskRunner(),
-      media_stream_compositor_task_runner,
+      video_frame_compositor_task_runner,
       render_thread->GetMediaThreadTaskRunner(),
       render_thread->GetWorkerTaskRunner(), render_thread->GetGpuFactories(),
       sink_id,
@@ -553,7 +563,7 @@
               &PostContextProviderToCallback,
               RenderThreadImpl::current()->GetCompositorMainThreadTaskRunner()),
           settings, true),
-      VideoSurfaceLayerEnabledForMS());
+      use_surface_layer_for_video);
 }
 
 media::RendererWebMediaPlayerDelegate*
diff --git a/content/renderer/media/media_factory.h b/content/renderer/media/media_factory.h
index bc71702..2e5fbd7 100644
--- a/content/renderer/media/media_factory.h
+++ b/content/renderer/media/media_factory.h
@@ -73,8 +73,7 @@
 class MediaFactory {
  public:
   // Helper function returning whether VideoSurfaceLayer should be enabled.
-  static media::WebMediaPlayerParams::SurfaceLayerMode
-  GetVideoSurfaceLayerMode();
+  static blink::WebMediaPlayer::SurfaceLayerMode GetVideoSurfaceLayerMode();
 
   // Helper function returning whether VideoSurfaceLayer should be enabled for
   // MediaStreams.
diff --git a/content/renderer/media/renderer_webaudiodevice_impl_unittest.cc b/content/renderer/media/renderer_webaudiodevice_impl_unittest.cc
index 8cb93d6..26fffe9 100644
--- a/content/renderer/media/renderer_webaudiodevice_impl_unittest.cc
+++ b/content/renderer/media/renderer_webaudiodevice_impl_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "content/renderer/media/audio/audio_device_factory.h"
 #include "media/base/audio_capturer_source.h"
@@ -14,6 +15,7 @@
 #include "media/base/mock_audio_renderer_sink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 using testing::_;
 
@@ -69,7 +71,7 @@
     webaudio_device_.reset(new RendererWebAudioDeviceImplUnderTest(
         media::CHANNEL_LAYOUT_MONO, 1, latencyHint, this, 0));
     webaudio_device_->SetMediaTaskRunnerForTesting(
-        task_environment_.GetMainThreadTaskRunner());
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   }
 
   void SetupDevice(media::ChannelLayout layout, int channels) {
@@ -79,7 +81,7 @@
             blink::WebAudioLatencyHint::kCategoryInteractive),
         this, 0));
     webaudio_device_->SetMediaTaskRunnerForTesting(
-        task_environment_.GetMainThreadTaskRunner());
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   }
 
   MOCK_METHOD2(CreateAudioCapturerSource,
diff --git a/content/renderer/media/stream/webmediaplayer_ms.cc b/content/renderer/media/stream/webmediaplayer_ms.cc
index 78ca5e2..adaa02a 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms.cc
@@ -271,7 +271,7 @@
     CreateSurfaceLayerBridgeCB create_bridge_callback,
     base::RepeatingCallback<std::unique_ptr<blink::WebVideoFrameSubmitter>()>
         create_submitter_callback,
-    bool surface_layer_for_video_enabled)
+    blink::WebMediaPlayer::SurfaceLayerMode surface_layer_mode)
     : frame_(frame),
       network_state_(WebMediaPlayer::kNetworkStateEmpty),
       ready_state_(WebMediaPlayer::kReadyStateHaveNothing),
@@ -294,9 +294,12 @@
       should_play_upon_shown_(false),
       create_bridge_callback_(std::move(create_bridge_callback)),
       create_submitter_callback_(create_submitter_callback),
-      surface_layer_for_video_enabled_(surface_layer_for_video_enabled) {
+      surface_layer_mode_(surface_layer_mode) {
   DVLOG(1) << __func__;
   DCHECK(client);
+  // We currently do not support on demand switching to use surface layer.
+  DCHECK(surface_layer_mode_ !=
+         blink::WebMediaPlayer::SurfaceLayerMode::kOnDemand);
   DCHECK(delegate_);
   delegate_id_ = delegate_->AddObserver(this);
 
@@ -314,7 +317,8 @@
   // Destruct compositor resources in the proper order.
   get_client()->SetCcLayer(nullptr);
   if (video_layer_) {
-    DCHECK(!surface_layer_for_video_enabled_);
+    DCHECK(surface_layer_mode_ !=
+           blink::WebMediaPlayer::SurfaceLayerMode::kAlways);
     video_layer_->StopUsingProvider();
   }
 
@@ -353,8 +357,7 @@
 
   compositor_ = new WebMediaPlayerMSCompositor(
       compositor_task_runner_, io_task_runner_, web_stream_,
-      create_submitter_callback_, surface_layer_for_video_enabled_,
-      AsWeakPtr());
+      create_submitter_callback_, surface_layer_mode_, AsWeakPtr());
 
   SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
   SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
@@ -798,6 +801,11 @@
   return ready_state_;
 }
 
+blink::WebMediaPlayer::SurfaceLayerMode
+WebMediaPlayerMS::GetVideoSurfaceLayerMode() const {
+  return surface_layer_mode_;
+}
+
 blink::WebString WebMediaPlayerMS::GetErrorMessage() const {
   return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
 }
@@ -1098,7 +1106,7 @@
   DVLOG(1) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (surface_layer_for_video_enabled_) {
+  if (surface_layer_mode_ == blink::WebMediaPlayer::SurfaceLayerMode::kAlways) {
     DCHECK(!bridge_);
 
     bridge_ = std::move(create_bridge_callback_)
diff --git a/content/renderer/media/stream/webmediaplayer_ms.h b/content/renderer/media/stream/webmediaplayer_ms.h
index 8c35955..b237beae 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.h
+++ b/content/renderer/media/stream/webmediaplayer_ms.h
@@ -16,6 +16,7 @@
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "media/blink/webmediaplayer_delegate.h"
+#include "media/blink/webmediaplayer_params.h"
 #include "media/blink/webmediaplayer_util.h"
 #include "media/renderers/paint_canvas_video_renderer.h"
 #include "media/video/gpu_video_accelerator_factories.h"
@@ -94,7 +95,7 @@
       CreateSurfaceLayerBridgeCB create_bridge_callback,
       base::RepeatingCallback<std::unique_ptr<blink::WebVideoFrameSubmitter>()>
           create_submitter_callback,
-      bool surface_layer_for_video_enabled_);
+      blink::WebMediaPlayer::SurfaceLayerMode surface_layer_mode);
 
   ~WebMediaPlayerMS() override;
 
@@ -160,6 +161,9 @@
   blink::WebMediaPlayer::NetworkState GetNetworkState() const override;
   blink::WebMediaPlayer::ReadyState GetReadyState() const override;
 
+  blink::WebMediaPlayer::SurfaceLayerMode GetVideoSurfaceLayerMode()
+      const override;
+
   blink::WebString GetErrorMessage() const override;
   bool DidLoadingProgress() override;
 
@@ -349,7 +353,8 @@
       create_submitter_callback_;
 
   // Whether the use of a surface layer instead of a video layer is enabled.
-  bool surface_layer_for_video_enabled_ = false;
+  blink::WebMediaPlayer::SurfaceLayerMode surface_layer_mode_ =
+      blink::WebMediaPlayer::SurfaceLayerMode::kNever;
 
   // Owns the weblayer and obtains/maintains SurfaceIds for
   // kUseSurfaceLayerForVideo feature.
diff --git a/content/renderer/media/stream/webmediaplayer_ms_compositor.cc b/content/renderer/media/stream/webmediaplayer_ms_compositor.cc
index 92b6b60..cdd6166 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_compositor.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms_compositor.cc
@@ -136,7 +136,7 @@
     const blink::WebMediaStream& web_stream,
     base::RepeatingCallback<std::unique_ptr<blink::WebVideoFrameSubmitter>()>
         create_submitter_callback,
-    bool surface_layer_for_video_enabled,
+    blink::WebMediaPlayer::SurfaceLayerMode surface_layer_mode,
     const base::WeakPtr<WebMediaPlayerMS>& player)
     : RefCountedDeleteOnSequence<WebMediaPlayerMSCompositor>(
           video_frame_compositor_task_runner),
@@ -153,7 +153,9 @@
       weak_ptr_factory_(this) {
   main_message_loop_ = base::MessageLoopCurrent::Get();
 
-  if (surface_layer_for_video_enabled) {
+  DCHECK(surface_layer_mode !=
+         blink::WebMediaPlayer::SurfaceLayerMode::kOnDemand);
+  if (surface_layer_mode != blink::WebMediaPlayer::SurfaceLayerMode::kNever) {
     submitter_ = create_submitter_callback.Run();
 
     video_frame_compositor_task_runner_->PostTask(
diff --git a/content/renderer/media/stream/webmediaplayer_ms_compositor.h b/content/renderer/media/stream/webmediaplayer_ms_compositor.h
index 63caa79..a9a2ad7 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_compositor.h
+++ b/content/renderer/media/stream/webmediaplayer_ms_compositor.h
@@ -20,6 +20,7 @@
 #include "cc/layers/video_frame_provider.h"
 #include "content/common/content_export.h"
 #include "media/base/media_log.h"
+#include "media/blink/webmediaplayer_params.h"
 #include "third_party/blink/public/platform/web_video_frame_submitter.h"
 
 namespace base {
@@ -68,7 +69,7 @@
       const blink::WebMediaStream& web_stream,
       base::RepeatingCallback<std::unique_ptr<blink::WebVideoFrameSubmitter>()>
           create_submitter_callback,
-      bool surface_layer_for_video_enabled,
+      blink::WebMediaPlayer::SurfaceLayerMode surface_layer_mode,
       const base::WeakPtr<WebMediaPlayerMS>& player);
 
   // Can be called from any thread.
diff --git a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
index 58e88fc..7931e33 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
@@ -22,6 +22,7 @@
 #include "media/video/mock_gpu_memory_buffer_video_frame_pool.h"
 #include "media/video/mock_gpu_video_accelerator_factories.h"
 #include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_fullscreen_video_status.h"
 #include "third_party/blink/public/platform/web_media_player.h"
 #include "third_party/blink/public/platform/web_media_player_client.h"
@@ -525,9 +526,9 @@
       public cc::VideoFrameProvider::Client {
  public:
   WebMediaPlayerMSTest()
-      : render_factory_(
-            new MockRenderFactory(base::ThreadTaskRunnerHandle::Get(),
-                                  &message_loop_controller_)),
+      : render_factory_(new MockRenderFactory(
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
+            &message_loop_controller_)),
         gpu_factories_(new media::MockGpuVideoAcceleratorFactories(nullptr)),
         surface_layer_bridge_(
             std::make_unique<NiceMock<MockSurfaceLayerBridge>>()),
@@ -677,18 +678,24 @@
 
 void WebMediaPlayerMSTest::InitializeWebMediaPlayerMS() {
   enable_surface_layer_for_video_ = testing::get<0>(GetParam());
+  blink::WebMediaPlayer::SurfaceLayerMode surface_layer_mode =
+      enable_surface_layer_for_video_
+          ? blink::WebMediaPlayer::SurfaceLayerMode::kAlways
+          : blink::WebMediaPlayer::SurfaceLayerMode::kNever;
   player_ = std::make_unique<WebMediaPlayerMS>(
       nullptr, this, &delegate_, std::make_unique<media::MediaLog>(),
       std::unique_ptr<MediaStreamRendererFactory>(render_factory_),
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
       gpu_factories_.get(), blink::WebString(),
       base::BindOnce(&WebMediaPlayerMSTest::CreateMockSurfaceLayerBridge,
                      base::Unretained(this)),
       base::BindRepeating(
           &WebMediaPlayerMSTest::CreateWebMockVideoFrameSubmitter,
           base::Unretained(this)),
-      enable_surface_layer_for_video_);
+      surface_layer_mode);
 }
 
 MockMediaStreamVideoRenderer* WebMediaPlayerMSTest::LoadAndGetFrameProvider(
@@ -760,7 +767,7 @@
 void WebMediaPlayerMSTest::StartRendering() {
   if (!rendering_) {
     rendering_ = true;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
         FROM_HERE, base::BindOnce(&WebMediaPlayerMSTest::RenderFrame,
                                   base::Unretained(this)));
   }
@@ -795,7 +802,7 @@
     auto frame = compositor_->GetCurrentFrame();
     compositor_->PutCurrentFrame();
   }
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+  blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostDelayedTask(
       FROM_HERE,
       base::BindOnce(&WebMediaPlayerMSTest::RenderFrame,
                      base::Unretained(this)),
diff --git a/content/renderer/media/webrtc/webrtc_audio_renderer_unittest.cc b/content/renderer/media/webrtc/webrtc_audio_renderer_unittest.cc
index 6c98bc2..1ca5083 100644
--- a/content/renderer/media/webrtc/webrtc_audio_renderer_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_audio_renderer_unittest.cc
@@ -20,6 +20,7 @@
 #include "media/base/mock_audio_renderer_sink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_media_stream.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/public/platform/web_string.h"
@@ -66,10 +67,7 @@
   }
 
  protected:
-  WebRtcAudioRendererTest()
-      : task_environment_(
-            base::test::ScopedTaskEnvironment::MainThreadType::IO),
-        source_(new MockAudioRendererSource()) {
+  WebRtcAudioRendererTest() : source_(new MockAudioRendererSource()) {
     blink::WebVector<blink::WebMediaStreamTrack> dummy_tracks;
     stream_.Initialize(blink::WebString::FromUTF8("new stream"), dummy_tracks,
                        dummy_tracks);
@@ -78,8 +76,9 @@
   }
 
   void SetupRenderer(const std::string& device_id) {
-    renderer_ = new WebRtcAudioRenderer(base::ThreadTaskRunnerHandle::Get(),
-                                        stream_, 1, 1, device_id);
+    renderer_ = new WebRtcAudioRenderer(
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting(), stream_, 1, 1,
+        device_id);
     EXPECT_CALL(
         *this, MockCreateAudioRendererSink(AudioDeviceFactory::kSourceWebRtc, _,
                                            _, device_id, _));
@@ -144,7 +143,8 @@
 
   const base::Optional<base::UnguessableToken> kAudioProcessingId =
       base::UnguessableToken::Create();
-  base::test::ScopedTaskEnvironment task_environment_;
+  base::test::ScopedTaskEnvironment task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::IO};
   scoped_refptr<media::MockAudioRendererSink> mock_sink_;
   std::unique_ptr<MockAudioRendererSource> source_;
   blink::WebMediaStream stream_;
@@ -294,8 +294,9 @@
 }
 
 TEST_F(WebRtcAudioRendererTest, InitializeWithInvalidDevice) {
-  renderer_ = new WebRtcAudioRenderer(base::ThreadTaskRunnerHandle::Get(),
-                                      stream_, 1, 1, kInvalidOutputDeviceId);
+  renderer_ = new WebRtcAudioRenderer(
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting(), stream_, 1, 1,
+      kInvalidOutputDeviceId);
 
   EXPECT_CALL(*this, MockCreateAudioRendererSink(
                          AudioDeviceFactory::kSourceWebRtc, _, _,
diff --git a/content/renderer/media_capture_from_element/canvas_capture_handler_unittest.cc b/content/renderer/media_capture_from_element/canvas_capture_handler_unittest.cc
index 2f1e5c29..fdce02d 100644
--- a/content/renderer/media_capture_from_element/canvas_capture_handler_unittest.cc
+++ b/content/renderer/media_capture_from_element/canvas_capture_handler_unittest.cc
@@ -7,11 +7,13 @@
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "content/child/child_process.h"
 #include "content/renderer/media/stream/media_stream_video_capturer_source.h"
 #include "media/base/limits.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_media_stream_source.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/public/platform/web_size.h"
@@ -56,7 +58,7 @@
     canvas_capture_handler_ = CanvasCaptureHandler::CreateCanvasCaptureHandler(
         blink::WebSize(kTestCanvasCaptureWidth, kTestCanvasCaptureHeight),
         kTestCanvasCaptureFramesPerSecond,
-        scoped_task_environment_.GetMainThreadTaskRunner(), &track_);
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting(), &track_);
   }
 
   void TearDown() override {
diff --git a/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc b/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
index d26bc814..434ef10 100644
--- a/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
+++ b/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
@@ -71,6 +71,9 @@
   double CurrentTime() const override { return 0.0; }
   NetworkState GetNetworkState() const override { return kNetworkStateEmpty; }
   ReadyState GetReadyState() const override { return kReadyStateHaveNothing; }
+  SurfaceLayerMode GetVideoSurfaceLayerMode() const override {
+    return SurfaceLayerMode::kNever;
+  }
   blink::WebString GetErrorMessage() const override {
     return blink::WebString();
   }
diff --git a/content/renderer/media_recorder/video_track_recorder_unittest.cc b/content/renderer/media_recorder/video_track_recorder_unittest.cc
index 2860893..f408afa7b 100644
--- a/content/renderer/media_recorder/video_track_recorder_unittest.cc
+++ b/content/renderer/media_recorder/video_track_recorder_unittest.cc
@@ -84,7 +84,7 @@
     // Paranoia checks.
     EXPECT_EQ(blink_track_.Source().GetExtraData(),
               blink_source_.GetExtraData());
-    EXPECT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner()
+    EXPECT_TRUE(blink::scheduler::GetSingleThreadTaskRunnerForTesting()
                     ->BelongsToCurrentThread());
   }
 
@@ -125,7 +125,7 @@
 
   void Encode(const scoped_refptr<VideoFrame>& frame,
               base::TimeTicks capture_time) {
-    EXPECT_TRUE(scoped_task_environment_.GetMainThreadTaskRunner()
+    EXPECT_TRUE(blink::scheduler::GetSingleThreadTaskRunnerForTesting()
                     ->BelongsToCurrentThread());
     video_track_recorder_->OnVideoFrameForTesting(frame, capture_time);
   }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 23d59d8..2c76d74 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -931,7 +931,7 @@
   settings->SetPictureInPictureEnabled(
       prefs.picture_in_picture_enabled &&
       MediaFactory::GetVideoSurfaceLayerMode() !=
-          media::WebMediaPlayerParams::SurfaceLayerMode::kNever);
+          blink::WebMediaPlayer::SurfaceLayerMode::kNever);
 
   settings->SetDataSaverHoldbackWebApi(
       prefs.data_saver_holdback_web_api_enabled);
diff --git a/content/test/gpu/PRESUBMIT.py b/content/test/gpu/PRESUBMIT.py
index fbb651b..61e92376 100644
--- a/content/test/gpu/PRESUBMIT.py
+++ b/content/test/gpu/PRESUBMIT.py
@@ -22,22 +22,3 @@
 
 def CheckChangeOnCommit(input_api, output_api):
   return CommonChecks(input_api, output_api)
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, the WebGL 2.0 conformance tests) in addition
-  to the regular CQ try bots. This test suite is too large to run
-  against all Chromium commits, but should be run against changes
-  likely to affect these tests.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_optional_gpu_tests_rel',
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win_optional_gpu_tests_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
diff --git a/content/test/gpu/gpu_tests/context_lost_expectations.py b/content/test/gpu/gpu_tests/context_lost_expectations.py
index 988dfc33..6089366 100644
--- a/content/test/gpu/gpu_tests/context_lost_expectations.py
+++ b/content/test/gpu/gpu_tests/context_lost_expectations.py
@@ -68,7 +68,3 @@
               ['android', ('qualcomm', 'Adreno (TM) 420')], bug=611906)
     self.Fail('ContextLost_WebGLContextLostFromQuantity',
               ['android', ('qualcomm', 'Adreno (TM) 420')], bug=611906)
-
-    # Temporary until Ganesh fix is made. Too flaky to mark as flaky.
-    self.Fail('GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash',
-               ['win'], bug=878258)
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 3831d579..8a41bc83 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -445,14 +445,14 @@
       'pixel_offscreenCanvas_transferToImageBitmap_main.html',
       base_name + '_OffscreenCanvasTransferToImageBitmap',
       test_rect=[0, 0, 300, 300],
-      revision=5,
+      revision=6,
       browser_args=browser_args),
 
     PixelTestPage(
       'pixel_offscreenCanvas_transferToImageBitmap_worker.html',
       base_name + '_OffscreenCanvasTransferToImageBitmapWorker',
       test_rect=[0, 0, 300, 300],
-      revision=5,
+      revision=6,
       browser_args=browser_args),
 
     PixelTestPage(
diff --git a/device/base/features.cc b/device/base/features.cc
index 164fe58..9745d21 100644
--- a/device/base/features.cc
+++ b/device/base/features.cc
@@ -30,7 +30,7 @@
 // Controls whether the CTAP2 implementation should use a built-in platform
 // authenticator, where available.
 const base::Feature kWebAuthTouchId{"WebAuthenticationTouchId",
-                                    base::FEATURE_DISABLED_BY_DEFAULT};
+                                    base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // defined(OS_MACOSX)
 
 const base::Feature kNewCtap2Device{"WebAuthenticationCtap2",
diff --git a/device/vr/PRESUBMIT.py b/device/vr/PRESUBMIT.py
deleted file mode 100644
index efd7ca5..0000000
--- a/device/vr/PRESUBMIT.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (c) 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for device/vr.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-
-def PostUploadHook(cl, change, output_api):
-    """git cl upload will call this hook after the issue is created/modified.
-
-    This hook modifies the CL description in order to run extra GPU
-    tests (in particular, WebXR and WebVR browser tests) in addition
-    to the regular CQ try bots. This test suite is too large to run
-    against all Chromium commits, but should be run against changes
-    likely to affect these tests.
-    """
-    return output_api.EnsureCQIncludeTrybotsAreAdded(
-        cl,
-        ['luci.chromium.try:win_optional_gpu_tests_rel'],
-        'Automatically added optional GPU tests to run on CQ.')
diff --git a/extensions/browser/api/socket/tcp_socket.cc b/extensions/browser/api/socket/tcp_socket.cc
index dbf14a78..4885df15 100644
--- a/extensions/browser/api/socket/tcp_socket.cc
+++ b/extensions/browser/api/socket/tcp_socket.cc
@@ -144,6 +144,9 @@
 }
 
 void TCPSocket::Disconnect(bool socket_destroying) {
+  // Make sure that any outstanding callbacks from Connect or Listen are
+  // aborted.
+  weak_factory_.InvalidateWeakPtrs();
   is_connected_ = false;
   local_addr_ = base::nullopt;
   peer_addr_ = base::nullopt;
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 27ce3f38..5edd2b3 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -998,7 +998,7 @@
   DELETED_COPRESENCEENDPOINTS_CREATELOCALENDPOINT = 937,
   DELETED_COPRESENCEENDPOINTS_DESTROYLOCALENDPOINT = 938,
   DELETED_COPRESENCEENDPOINTS_SEND = 939,
-  INLINE_INSTALL_PRIVATE_INSTALL = 940,
+  DELETED_INLINE_INSTALL_PRIVATE_INSTALL = 940,
   LAUNCHERPAGE_SETENABLED = 941,
   DELETED_CRYPTOTOKENPRIVATE_REQUESTPERMISSION = 942,
   BLUETOOTHPRIVATE_DISCONNECTALL = 943,
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h
index 58ed2bad..e7a82a3 100644
--- a/extensions/common/permissions/api_permission.h
+++ b/extensions/common/permissions/api_permission.h
@@ -132,7 +132,7 @@
     kIdltest = 88,
     kIdle = 89,
     kImeWindowEnabled = 90,
-    kInlineInstallPrivate = 91,
+    kDeleted_InlineInstallPrivate = 91,
     kInput = 92,
     kInputMethodPrivate = 93,
     kDeleted_InterceptAllKeys = 94,
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index d2ff1a5c..fb24d1c7 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -477,6 +477,7 @@
       "command_buffer/service/gles2_cmd_decoder_passthrough_unittest_commands.cc",
       "command_buffer/service/gles2_cmd_decoder_passthrough_unittest_drawing.cc",
       "command_buffer/service/gles2_cmd_decoder_passthrough_unittest_framebuffers.cc",
+      "command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc",
     ]
   }
 
diff --git a/gpu/PRESUBMIT.py b/gpu/PRESUBMIT.py
index f30a616..a6311f4 100644
--- a/gpu/PRESUBMIT.py
+++ b/gpu/PRESUBMIT.py
@@ -8,28 +8,6 @@
 for more details about the presubmit API built into depot_tools.
 """
 
-def PostUploadHook(cl, _change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, the WebGL 2.0 conformance tests) in addition
-  to the regular CQ try bots. This test suite is too large to run
-  against all Chromium commits, but should be run against changes
-  likely to affect these tests.
-
-  When adding/removing tests here, ensure that both gpu/PRESUBMIT.py and
-  ui/gl/PRESUBMIT.py are updated.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_optional_gpu_tests_rel',
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win_optional_gpu_tests_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
-
 def CommonChecks(input_api, output_api):
   import sys
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index e4b21a6..c53d8ec 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -16,6 +16,7 @@
 #include "gpu/command_buffer/service/gpu_fence_manager.h"
 #include "gpu/command_buffer/service/gpu_tracer.h"
 #include "gpu/command_buffer/service/program_cache.h"
+#include "gpu/command_buffer/service/shared_image_representation.h"
 #include "ui/gl/gl_version_info.h"
 
 namespace gpu {
@@ -179,8 +180,12 @@
         [api](GLuint client_id, scoped_refptr<TexturePassthrough> texture) {
           texture->MarkContextLost();
         });
+    for (const auto& pair : texture_shared_image_map) {
+      pair.second->OnContextLost();
+    }
   }
   texture_object_map.Clear();
+  texture_shared_image_map.clear();
   DestroyPendingTextures(have_context);
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
index 325918d..a600b75 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -39,6 +39,8 @@
 }
 
 namespace gpu {
+class SharedImageRepresentationGLTexturePassthrough;
+
 namespace gles2 {
 
 class ContextGroup;
@@ -87,6 +89,14 @@
   ClientServiceMap<GLuint, scoped_refptr<TexturePassthrough>>
       texture_object_map;
 
+  // Mapping of client texture IDs to
+  // SharedImageRepresentationGLTexturePassthroughs.
+  // TODO(ericrk): Remove this once TexturePassthrough holds a reference to
+  // the SharedImageRepresentationGLTexturePassthrough itself.
+  base::flat_map<GLuint,
+                 std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>>
+      texture_shared_image_map;
+
   // A set of yet-to-be-deleted TexturePassthrough, which should be tossed
   // whenever a context switch happens or the resources is destroyed.
   base::flat_set<scoped_refptr<TexturePassthrough>>
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index c91317f..b175d86 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -9,6 +9,8 @@
 #include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/gpu_fence_manager.h"
 #include "gpu/command_buffer/service/gpu_tracer.h"
+#include "gpu/command_buffer/service/shared_image_manager.h"
+#include "gpu/command_buffer/service/shared_image_representation.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gl/dc_renderer_layer_params.h"
 #include "ui/gl/gl_version_info.h"
@@ -998,6 +1000,7 @@
       // Deleted when unreferenced
       resources_->texture_id_map.RemoveClientID(client_id);
       resources_->texture_object_map.RemoveClientID(client_id);
+      resources_->texture_shared_image_map.erase(client_id);
       UpdateTextureBinding(texture->target(), client_id, nullptr);
     }
   }
@@ -4073,11 +4076,38 @@
 
 error::Error
 GLES2DecoderPassthroughImpl::DoCreateAndTexStorage2DSharedImageINTERNAL(
-    GLuint client_id,
+    GLuint texture_client_id,
     GLenum internal_format,
     const volatile GLbyte* mailbox) {
-  // TODO(ericrk): Implement this.
-  NOTIMPLEMENTED();
+  if (!texture_client_id ||
+      resources_->texture_id_map.HasClientID(texture_client_id)) {
+    InsertError(GL_INVALID_OPERATION, "Invalid texture ID");
+    return error::kNoError;
+  }
+
+  const Mailbox& mb = Mailbox::FromVolatile(
+      *reinterpret_cast<const volatile Mailbox*>(mailbox));
+  auto shared_image =
+      group_->shared_image_manager()->ProduceGLTexturePassthrough(mb);
+  if (shared_image == nullptr) {
+    // Create texture to handle invalid mailbox (see http://crbug.com/472465 and
+    // http://crbug.com/851878).
+    DoGenTextures(1, &texture_client_id);
+    InsertError(GL_INVALID_OPERATION, "Invalid mailbox name.");
+    return error::kNoError;
+  }
+
+  auto texture = shared_image->GetTexturePassthrough();
+
+  // Update id mappings
+  resources_->texture_id_map.RemoveClientID(texture_client_id);
+  resources_->texture_id_map.SetIDMapping(texture_client_id,
+                                          texture->service_id());
+  resources_->texture_object_map.RemoveClientID(texture_client_id);
+  resources_->texture_object_map.SetIDMapping(texture_client_id, texture);
+  resources_->texture_shared_image_map[texture_client_id] =
+      std::move(shared_image);
+
   return error::kNoError;
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc
new file mode 100644
index 0000000..5e3cb66
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc
@@ -0,0 +1,169 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h"
+#include "gpu/command_buffer/service/shared_image_representation.h"
+
+namespace gpu {
+namespace gles2 {
+namespace {
+static const uint32_t kNewServiceId = 431;
+
+class TestSharedImageBackingPassthrough : public SharedImageBacking {
+ public:
+  class TestSharedImageRepresentationPassthrough
+      : public SharedImageRepresentationGLTexturePassthrough {
+   public:
+    TestSharedImageRepresentationPassthrough(
+        SharedImageManager* manager,
+        SharedImageBacking* backing,
+        scoped_refptr<TexturePassthrough>& texture_passthrough)
+        : SharedImageRepresentationGLTexturePassthrough(manager, backing),
+          texture_passthrough_(texture_passthrough) {}
+
+    const scoped_refptr<TexturePassthrough>& GetTexturePassthrough() override {
+      return texture_passthrough_;
+    }
+
+   private:
+    const scoped_refptr<TexturePassthrough>& texture_passthrough_;
+  };
+
+  TestSharedImageBackingPassthrough(const Mailbox& mailbox,
+                                    viz::ResourceFormat format,
+                                    const gfx::Size& size,
+                                    const gfx::ColorSpace& color_space,
+                                    uint32_t usage,
+                                    GLuint texture_id)
+      : SharedImageBacking(mailbox, format, size, color_space, usage) {
+    texture_passthrough_ =
+        base::MakeRefCounted<TexturePassthrough>(texture_id, GL_TEXTURE_2D);
+  }
+
+  bool IsCleared() const override { return false; }
+
+  void SetCleared() override {}
+
+  bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override {
+    return false;
+  }
+
+  void Destroy() override { texture_passthrough_.reset(); }
+
+  size_t EstimatedSize() const override { return 0; }
+
+  void OnMemoryDump(const std::string& dump_name,
+                    base::trace_event::MemoryAllocatorDump* dump,
+                    base::trace_event::ProcessMemoryDump* pmd,
+                    uint64_t client_tracing_id) override {}
+
+ protected:
+  std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+  ProduceGLTexturePassthrough(SharedImageManager* manager) override {
+    return std::make_unique<TestSharedImageRepresentationPassthrough>(
+        manager, this, texture_passthrough_);
+  }
+
+ private:
+  scoped_refptr<TexturePassthrough> texture_passthrough_;
+};
+
+}  // namespace
+
+using namespace cmds;
+
+TEST_F(GLES2DecoderPassthroughTest, CreateAndTexStorage2DSharedImageCHROMIUM) {
+  Mailbox mailbox = Mailbox::Generate();
+  GetSharedImageManager()->Register(
+      std::make_unique<TestSharedImageBackingPassthrough>(
+          mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
+          gfx::ColorSpace(), 0, kNewServiceId));
+
+  CreateAndTexStorage2DSharedImageINTERNALImmediate& cmd =
+      *GetImmediateAs<CreateAndTexStorage2DSharedImageINTERNALImmediate>();
+  cmd.Init(kNewClientId, GL_RGBA, mailbox.name);
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(mailbox.name)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+  // Make sure the new client ID is associated with the provided service ID.
+  uint32_t found_service_id = 0;
+  EXPECT_TRUE(GetPassthroughResources()->texture_id_map.GetServiceID(
+      kNewClientId, &found_service_id));
+  EXPECT_EQ(found_service_id, kNewServiceId);
+  scoped_refptr<TexturePassthrough> found_texture_passthrough;
+  EXPECT_TRUE(GetPassthroughResources()->texture_object_map.GetServiceID(
+      kNewClientId, &found_texture_passthrough));
+  EXPECT_EQ(found_texture_passthrough->service_id(), kNewServiceId);
+  found_texture_passthrough.reset();
+  EXPECT_EQ(1u, GetPassthroughResources()->texture_shared_image_map.count(
+                    kNewClientId));
+
+  // Delete the texture and make sure it is no longer accessible.
+  DoDeleteTexture(kNewClientId);
+  EXPECT_FALSE(GetPassthroughResources()->texture_id_map.GetServiceID(
+      kNewClientId, &found_service_id));
+  EXPECT_FALSE(GetPassthroughResources()->texture_object_map.GetServiceID(
+      kNewClientId, &found_texture_passthrough));
+  EXPECT_EQ(0u, GetPassthroughResources()->texture_shared_image_map.count(
+                    kNewClientId));
+
+  GetSharedImageManager()->Unregister(mailbox);
+}
+
+TEST_F(GLES2DecoderPassthroughTest,
+       CreateAndTexStorage2DSharedImageCHROMIUMInvalidMailbox) {
+  // Attempt to use an invalid mailbox.
+  Mailbox mailbox;
+  CreateAndTexStorage2DSharedImageINTERNALImmediate& cmd =
+      *GetImmediateAs<CreateAndTexStorage2DSharedImageINTERNALImmediate>();
+  cmd.Init(kNewClientId, GL_RGBA, mailbox.name);
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(mailbox.name)));
+
+  // CreateAndTexStorage2DSharedImage should fail if the mailbox is invalid.
+  EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+  // Make sure the new client_id is associated with a texture id, even though
+  // the command failed.
+  uint32_t found_service_id = 0;
+  EXPECT_TRUE(GetPassthroughResources()->texture_id_map.GetServiceID(
+      kNewClientId, &found_service_id));
+  EXPECT_NE(0u, found_service_id);
+}
+
+TEST_F(GLES2DecoderPassthroughTest,
+       CreateAndTexStorage2DSharedImageCHROMIUMPreexistingTexture) {
+  // Create a texture with kNewClientId.
+  Mailbox mailbox = Mailbox::Generate();
+  GetSharedImageManager()->Register(
+      std::make_unique<TestSharedImageBackingPassthrough>(
+          mailbox, viz::ResourceFormat::RGBA_8888, gfx::Size(10, 10),
+          gfx::ColorSpace(), 0, kNewServiceId));
+
+  {
+    CreateAndTexStorage2DSharedImageINTERNALImmediate& cmd =
+        *GetImmediateAs<CreateAndTexStorage2DSharedImageINTERNALImmediate>();
+    cmd.Init(kNewClientId, GL_RGBA, mailbox.name);
+    EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(mailbox.name)));
+    EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  }
+
+  // Try to import the SharedImage a second time at the same client ID. We
+  // should get a GL failure.
+  {
+    CreateAndTexStorage2DSharedImageINTERNALImmediate& cmd =
+        *GetImmediateAs<CreateAndTexStorage2DSharedImageINTERNALImmediate>();
+    cmd.Init(kNewClientId, GL_RGBA, mailbox.name);
+    EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(mailbox.name)));
+    EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+  }
+
+  DoDeleteTexture(kNewClientId);
+  GetSharedImageManager()->Unregister(mailbox);
+}
+
+}  // namespace gles2
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 03fdfe5..91af1dd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -2581,6 +2581,10 @@
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
 }
 
+void GLES2DecoderPassthroughTestBase::DoDeleteTexture(GLuint client_id) {
+  GenHelper<cmds::DeleteTexturesImmediate>(client_id);
+}
+
 void GLES2DecoderPassthroughTestBase::DoBindFramebuffer(GLenum target,
                                                         GLuint client_id) {
   cmds::BindFramebuffer cmd;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 28de0a1f..10eca7d90 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -934,6 +934,9 @@
   PassthroughResources* GetPassthroughResources() const {
     return group_->passthrough_resources();
   }
+  SharedImageManager* GetSharedImageManager() const {
+    return group_->shared_image_manager();
+  }
   const base::circular_deque<GLES2DecoderPassthroughImpl::PendingReadPixels>&
   GetPendingReadPixels() const {
     return decoder_->pending_read_pixels_;
@@ -966,6 +969,7 @@
                     GLenum type,
                     uint32_t shared_memory_id,
                     uint32_t shared_memory_offset);
+  void DoDeleteTexture(GLuint client_id);
 
   void DoBindFramebuffer(GLenum target, GLuint client_id);
   void DoFramebufferTexture2D(GLenum target,
diff --git a/gpu/command_buffer/service/shared_image_backing.cc b/gpu/command_buffer/service/shared_image_backing.cc
index cf829d0c..e7a1b74 100644
--- a/gpu/command_buffer/service/shared_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image_backing.cc
@@ -30,4 +30,9 @@
   return nullptr;
 }
 
+std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+SharedImageBacking::ProduceGLTexturePassthrough(SharedImageManager* manager) {
+  return nullptr;
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing.h b/gpu/command_buffer/service/shared_image_backing.h
index f4fb83464..6cae042 100644
--- a/gpu/command_buffer/service/shared_image_backing.h
+++ b/gpu/command_buffer/service/shared_image_backing.h
@@ -22,6 +22,7 @@
 class MailboxManager;
 class SharedImageManager;
 class SharedImageRepresentationGLTexture;
+class SharedImageRepresentationGLTexturePassthrough;
 
 // Represents the actual storage (GL texture, VkImage, GMB) for a SharedImage.
 // Should not be accessed direclty, instead is accessed through a
@@ -74,6 +75,8 @@
   friend class SharedImageManager;
   virtual std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
       SharedImageManager* manager);
+  virtual std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+  ProduceGLTexturePassthrough(SharedImageManager* manager);
 
   // Used by subclasses in Destroy.
   bool have_context() const { return have_context_; }
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
index 52e47512..9a80074 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
@@ -44,6 +44,27 @@
   gles2::Texture* texture_;
 };
 
+// Representation of a SharedImageBackingGLTexturePassthrough as a GL
+// TexturePassthrough.
+class SharedImageRepresentationGLTexturePassthroughImpl
+    : public SharedImageRepresentationGLTexturePassthrough {
+ public:
+  SharedImageRepresentationGLTexturePassthroughImpl(
+      SharedImageManager* manager,
+      SharedImageBacking* backing,
+      scoped_refptr<gles2::TexturePassthrough> texture_passthrough)
+      : SharedImageRepresentationGLTexturePassthrough(manager, backing),
+        texture_passthrough_(std::move(texture_passthrough)) {}
+
+  const scoped_refptr<gles2::TexturePassthrough>& GetTexturePassthrough()
+      override {
+    return texture_passthrough_;
+  }
+
+ private:
+  scoped_refptr<gles2::TexturePassthrough> texture_passthrough_;
+};
+
 // Implementation of SharedImageBacking that creates a GL Texture and stores it
 // as a gles2::Texture. Can be used with the legacy mailbox implementation.
 class SharedImageBackingGLTexture : public SharedImageBacking {
@@ -152,10 +173,10 @@
   }
 
  protected:
-  std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
-      SharedImageManager* manager) override {
-    // TODO(ericrk): Add support.
-    return nullptr;
+  std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+  ProduceGLTexturePassthrough(SharedImageManager* manager) override {
+    return std::make_unique<SharedImageRepresentationGLTexturePassthroughImpl>(
+        manager, this, passthrough_texture_);
   }
 
  private:
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
index 560a975..45499df1 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
@@ -95,8 +95,8 @@
 
   // Next, validate via a SharedImageRepresentationGLTexture.
   EXPECT_TRUE(shared_image_manager_.Register(std::move(backing)));
-  auto gl_representation = shared_image_manager_.ProduceGLTexture(mailbox);
   if (!use_passthrough()) {
+    auto gl_representation = shared_image_manager_.ProduceGLTexture(mailbox);
     EXPECT_TRUE(gl_representation);
     EXPECT_TRUE(gl_representation->GetTexture()->service_id());
     EXPECT_EQ(expected_target, gl_representation->GetTexture()->target());
@@ -107,6 +107,21 @@
     gl_representation.reset();
   }
 
+  // Finally, validate a SharedImageRepresentationGLTexturePassthrough.
+  if (use_passthrough()) {
+    auto gl_representation =
+        shared_image_manager_.ProduceGLTexturePassthrough(mailbox);
+    EXPECT_TRUE(gl_representation);
+    EXPECT_TRUE(gl_representation->GetTexturePassthrough()->service_id());
+    EXPECT_EQ(expected_target,
+              gl_representation->GetTexturePassthrough()->target());
+    EXPECT_EQ(size, gl_representation->size());
+    EXPECT_EQ(format, gl_representation->format());
+    EXPECT_EQ(color_space, gl_representation->color_space());
+    EXPECT_EQ(usage, gl_representation->usage());
+    gl_representation.reset();
+  }
+
   shared_image_manager_.Unregister(mailbox);
   EXPECT_FALSE(mailbox_manager_.ConsumeTexture(mailbox));
 }
@@ -145,8 +160,8 @@
 
   // Next, validate via a SharedImageRepresentationGLTexture.
   EXPECT_TRUE(shared_image_manager_.Register(std::move(backing)));
-  auto gl_representation = shared_image_manager_.ProduceGLTexture(mailbox);
   if (!use_passthrough()) {
+    auto gl_representation = shared_image_manager_.ProduceGLTexture(mailbox);
     EXPECT_TRUE(gl_representation);
     EXPECT_TRUE(gl_representation->GetTexture()->service_id());
     EXPECT_EQ(size, gl_representation->size());
@@ -156,6 +171,19 @@
     gl_representation.reset();
   }
 
+  // Finally, validate a SharedImageRepresentationGLTexturePassthrough.
+  if (use_passthrough()) {
+    auto gl_representation =
+        shared_image_manager_.ProduceGLTexturePassthrough(mailbox);
+    EXPECT_TRUE(gl_representation);
+    EXPECT_TRUE(gl_representation->GetTexturePassthrough()->service_id());
+    EXPECT_EQ(size, gl_representation->size());
+    EXPECT_EQ(format, gl_representation->format());
+    EXPECT_EQ(color_space, gl_representation->color_space());
+    EXPECT_EQ(usage, gl_representation->usage());
+    gl_representation.reset();
+  }
+
   shared_image_manager_.Unregister(mailbox);
   EXPECT_FALSE(mailbox_manager_.ConsumeTexture(mailbox));
 }
diff --git a/gpu/command_buffer/service/shared_image_manager.cc b/gpu/command_buffer/service/shared_image_manager.cc
index 2abb692..fc787422 100644
--- a/gpu/command_buffer/service/shared_image_manager.cc
+++ b/gpu/command_buffer/service/shared_image_manager.cc
@@ -77,15 +77,36 @@
 SharedImageManager::ProduceGLTexture(const Mailbox& mailbox) {
   auto found = images_.find(mailbox);
   if (found == images_.end()) {
-    LOG(ERROR) << "SharedImageManager::ProduceGLTexture: Trying to Produce a "
-                  "GL texture representation from a non-existent mailbox.";
+    LOG(ERROR) << "SharedImageManager::ProduceGLTexture: Trying to produce a "
+                  "representation from a non-existent mailbox.";
     return nullptr;
   }
 
   auto representation = found->backing->ProduceGLTexture(this);
   if (!representation) {
     LOG(ERROR) << "SharedImageManager::ProduceGLTexture: Trying to produce a "
-                  "GL texture representation from an incompatible mailbox.";
+                  "representation from an incompatible mailbox.";
+    return nullptr;
+  }
+
+  // Take a ref. This is released when we destroy the generated representation.
+  found->ref_count++;
+  return representation;
+}
+
+std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+SharedImageManager::ProduceGLTexturePassthrough(const Mailbox& mailbox) {
+  auto found = images_.find(mailbox);
+  if (found == images_.end()) {
+    LOG(ERROR) << "SharedImageManager::ProduceGLTexturePassthrough: Trying to "
+                  "produce a representation from a non-existent mailbox.";
+    return nullptr;
+  }
+
+  auto representation = found->backing->ProduceGLTexturePassthrough(this);
+  if (!representation) {
+    LOG(ERROR) << "SharedImageManager::ProduceGLTexturePassthrough: Trying to "
+                  "produce a representation from an incompatible mailbox.";
     return nullptr;
   }
 
diff --git a/gpu/command_buffer/service/shared_image_manager.h b/gpu/command_buffer/service/shared_image_manager.h
index 01f973e..a518fde3 100644
--- a/gpu/command_buffer/service/shared_image_manager.h
+++ b/gpu/command_buffer/service/shared_image_manager.h
@@ -33,6 +33,8 @@
   // destroyed.
   std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
       const Mailbox& mailbox);
+  std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+  ProduceGLTexturePassthrough(const Mailbox& mailbox);
 
   // Called by SharedImageRepresentation in the destructor.
   void OnRepresentationDestroyed(const Mailbox& mailbox);
diff --git a/gpu/command_buffer/service/shared_image_representation.h b/gpu/command_buffer/service/shared_image_representation.h
index 1a3b17f..08a5642 100644
--- a/gpu/command_buffer/service/shared_image_representation.h
+++ b/gpu/command_buffer/service/shared_image_representation.h
@@ -16,6 +16,7 @@
 namespace gpu {
 namespace gles2 {
 class Texture;
+class TexturePassthrough;
 }  // namespace gles2
 
 // A representation of a SharedImageBacking for use with a specific use case /
@@ -51,6 +52,17 @@
   virtual gles2::Texture* GetTexture() = 0;
 };
 
+class SharedImageRepresentationGLTexturePassthrough
+    : public SharedImageRepresentation {
+ public:
+  SharedImageRepresentationGLTexturePassthrough(SharedImageManager* manager,
+                                                SharedImageBacking* backing)
+      : SharedImageRepresentation(manager, backing) {}
+
+  virtual const scoped_refptr<gles2::TexturePassthrough>&
+  GetTexturePassthrough() = 0;
+};
+
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_REPRESENTATION_H_
diff --git a/infra/config/branch/cq.cfg b/infra/config/branch/cq.cfg
index cb15313..0cf953c0d 100644
--- a/infra/config/branch/cq.cfg
+++ b/infra/config/branch/cq.cfg
@@ -172,6 +172,10 @@
         path_regexp: "third_party/blink/renderer/modules/webgl/.+"
         path_regexp: "ui/gl/.+"
       }
+      builders {
+        name: "win-libfuzzer-asan-rel"
+        experiment_percentage: 50
+      }
       builders { name: "win10_chromium_x64_rel_ng" }
       builders {
         name: "win7_chromium_rel_loc_exp"
diff --git a/ios/PRESUBMIT.py b/ios/PRESUBMIT.py
index b80e238..47b8cad 100644
--- a/ios/PRESUBMIT.py
+++ b/ios/PRESUBMIT.py
@@ -84,21 +84,3 @@
   results.extend(_CheckBugInToDo(input_api, output_api))
   results.extend(_CheckARCCompilationGuard(input_api, output_api))
   return results
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook adds an extra try bot to the CL description in order to run Cronet
-  and EarlGrey tests in addition to CQ try bots.
-  """
-
-  # TODO(crbug.com/712733): Remove ios-simulator-cronet once Cronet bots are
-  # deployed on CQ.
-  # TODO(crbug.com/782735): Remove ios-simulator-full-configs once EarlGrey
-  # bots are deployed on CQ.
-  try_bots = ['luci.chromium.try:ios-simulator-cronet',
-              'luci.chromium.try:ios-simulator-full-configs']
-
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl, try_bots, 'Automatically added Cronet and EarlGrey trybots to '
-      'run tests on CQ.')
diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py
index f74d6a7..9329788 100644
--- a/ios/build/bots/scripts/test_runner.py
+++ b/ios/build/bots/scripts/test_runner.py
@@ -1032,7 +1032,6 @@
   def set_up(self):
     '''Performs setup actions which must occur prior to every test launch.'''
     super(WprProxySimulatorTestRunner, self).set_up()
-    self.download_replays()
 
     cert_path = "{}/TrustStore_trust.sqlite3".format(self.wpr_tools_path)
 
@@ -1210,8 +1209,8 @@
     '''Starts tsproxy and routes the machine's traffic through tsproxy.'''
 
     # Stops any straggling instances of WPRgo that may hog ports 8080/8081
-    subprocess.check_call('lsof -ti:8080 | xargs kill -9')
-    subprocess.check_call('lsof -ti:8081| xargs kill -9')
+    subprocess.check_call('lsof -ti:8080 | xargs kill -9', shell=True)
+    subprocess.check_call('lsof -ti:8081| xargs kill -9', shell=True)
 
     # We route all network adapters through the proxy, since it is easier than
     # determining which network adapter is being used currently.
@@ -1267,7 +1266,7 @@
     '''
     self.wprgo_process = subprocess.Popen(
         [
-          'wpr', 'run', 'src/wpr.go', 'replay', '--http_port=8080',
+          './wpr', 'replay', '--http_port=8080',
           '--https_port=8081', replay_path
         ],
         cwd='{}/web_page_replay_go/'.format(self.wpr_tools_path),
@@ -1281,21 +1280,6 @@
     if self.wprgo_process != None:
       os.kill(self.wprgo_process.pid, signal.SIGINT)
 
-  def download_replays(self):
-    '''Downloads the replay files from GCS to the replay path folder.
-
-    We store the website replays in GCS due to size; sha1 files in the
-    replay path folder correspond to each of these replays, and running this
-    script will populate those replay files.'''
-
-    subprocess.check_call(
-      [
-        'download_from_google_storage.py',
-        '--bucket', 'chrome-test-web-page-replay-captures/autofill',
-        '--directory', self.replay_path
-      ],
-      cwd=self.wpr_tools_path)
-
 
 class DeviceTestRunner(TestRunner):
   """Class for running tests on devices."""
diff --git a/ios/chrome/browser/ui/toolbar_container/BUILD.gn b/ios/chrome/browser/ui/toolbar_container/BUILD.gn
index 61241bc..3bd253e 100644
--- a/ios/chrome/browser/ui/toolbar_container/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar_container/BUILD.gn
@@ -41,10 +41,13 @@
   sources = [
     "collapsing_toolbar_height_constraint.h",
     "collapsing_toolbar_height_constraint.mm",
+    "collapsing_toolbar_height_constraint_delegate.h",
     "toolbar_container_view.h",
     "toolbar_container_view.mm",
     "toolbar_container_view_controller.h",
     "toolbar_container_view_controller.mm",
+    "toolbar_height_range.h",
+    "toolbar_height_range.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
@@ -63,6 +66,7 @@
   sources = [
     "collapsing_toolbar_height_constraint_unittest.mm",
     "toolbar_container_view_controller_unittest.mm",
+    "toolbar_height_range_unittest.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.h b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.h
index c126eee..0627c38 100644
--- a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.h
+++ b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.h
@@ -7,34 +7,41 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h"
+
+@protocol CollapsingToolbarHeightConstraintDelegate;
+
 // A constraint that scales between a collapsed and expanded height value.
 @interface CollapsingToolbarHeightConstraint : NSLayoutConstraint
 
-// Returns a constraint that manages the height of |view|.  If |view|
-// conforms to the ToolbarCollapsing protocol, the collapsed and expanded
-// heights are set using those return values.  Otherwise, the intrinsic height
-// is used as both the collapsed and expanded height.
+// Returns a constraint that manages the height of |view|.  If |view| conforms
+// to ToolbarCollapsing, updating |progress| will scale between its collapsed
+// and expanded heights.  Otherwise, the constraint will lock |view|'s height
+// to its intrinisic content height.  The height range can be increased using
+// |additionalHeight|.
 + (nullable instancetype)constraintWithView:(nonnull UIView*)view;
 
-// The collapsed and expanded toolbar heights.
-@property(nonatomic, readonly) CGFloat collapsedHeight;
-@property(nonatomic, readonly) CGFloat expandedHeight;
-
 // Used to add additional height to the toolbar.
 @property(nonatomic, assign) CGFloat additionalHeight;
-// Whether the additional height should be collapsed.  When set to YES, the
-// view's height ranges from |collapsedHeight| to |expandedHeight| +
-// |additionalHeight|. When set to NO, the view's height ranges from
-// |additionalHeight| + |collapsedHeight| to |additionalHeight| +
-// |expandedHeight|.
+// Whether the additional height should be collapsed.
 @property(nonatomic, assign) BOOL collapsesAdditionalHeight;
 
+// The height range for the constraint.  If the constrained view conforms to
+// ToolbarCollapsing, the range will be populated using the collapsed and
+// expanded toolbar heights from that protocol, otherwise the intrinsic content
+// height is used.  |additionalHeight| and is added to the max height, and
+// optionally added to the min height if |collapsesAdditionalHeight| is NO.
+@property(nonatomic, readonly)
+    const toolbar_container::HeightRange& heightRange;
+
 // The interpolation progress within the height range to use for the
-// constraint's constant.
+// constraint's constant.  The value is clamped between 0.0 and 1.0.
 @property(nonatomic, assign) CGFloat progress;
 
-// Returns the height of the toolbar at |progress|
-- (CGFloat)toolbarHeightForProgress:(CGFloat)progress;
+// The constraint's delegate.
+@property(nonatomic, weak, nullable)
+    id<CollapsingToolbarHeightConstraintDelegate>
+        delegate;
 
 @end
 
diff --git a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.mm b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.mm
index 8c837f0..571ffd06 100644
--- a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.mm
+++ b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.mm
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/numerics/ranges.h"
+#import "ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_delegate.h"
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_collapsing.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 
@@ -21,20 +22,29 @@
 const CGFloat kMaxProgress = 1.0;
 }  // namespace
 
-@interface CollapsingToolbarHeightConstraint ()
-// Redefine as readwrite.
-@property(nonatomic, readwrite) CGFloat collapsedHeight;
-@property(nonatomic, readwrite) CGFloat expandedHeight;
+using toolbar_container::HeightRange;
+
+@interface CollapsingToolbarHeightConstraint () {
+  // Backing variable for property of same name.
+  HeightRange _heightRange;
+}
+// The height values extracted from the constrained view.  If the view conforms
+// to ToolbarCollapsing, these will be the values from that protocol, and will
+// be updated using KVO if those values change.  Otherwise, they will both be
+// equal to the intrinsic height of the view.
+@property(nonatomic, readwrite) CGFloat collapsedToolbarHeight;
+@property(nonatomic, readwrite) CGFloat expandedToolbarHeight;
 // The collapsing toolbar whose height range is being observed.
 @property(nonatomic, weak) UIView<ToolbarCollapsing>* collapsingToolbar;
 @end
 
 @implementation CollapsingToolbarHeightConstraint
-@synthesize collapsedHeight = _collapsedHeight;
-@synthesize expandedHeight = _expandedHeight;
+@synthesize collapsedToolbarHeight = _collapsedToolbarHeight;
+@synthesize expandedToolbarHeight = _expandedToolbarHeight;
 @synthesize additionalHeight = _additionalHeight;
 @synthesize collapsesAdditionalHeight = _collapsesAdditionalHeight;
 @synthesize progress = _progress;
+@synthesize delegate = _delegate;
 @synthesize collapsingToolbar = _collapsingToolbar;
 
 + (instancetype)constraintWithView:(UIView*)view {
@@ -52,11 +62,11 @@
         static_cast<UIView<ToolbarCollapsing>*>(view);
   } else {
     CGFloat intrinsicHeight = view.intrinsicContentSize.height;
-    constraint.collapsedHeight = intrinsicHeight;
-    constraint.expandedHeight = intrinsicHeight;
+    constraint.collapsedToolbarHeight = intrinsicHeight;
+    constraint.expandedToolbarHeight = intrinsicHeight;
+    [constraint updateToolbarHeightRange];
   }
   constraint.progress = 1.0;
-  [constraint updateHeight];
 
   return constraint;
 }
@@ -71,32 +81,23 @@
     [self stopObservingCollapsingToolbar];
 }
 
-- (void)setCollapsedHeight:(CGFloat)collapsedHeight {
-  if (AreCGFloatsEqual(_collapsedHeight, collapsedHeight))
-    return;
-  _collapsedHeight = collapsedHeight;
-  [self updateHeight];
-}
-
-- (void)setExpandedHeight:(CGFloat)expandedHeight {
-  if (AreCGFloatsEqual(_expandedHeight, expandedHeight))
-    return;
-  _expandedHeight = expandedHeight;
-  [self updateHeight];
-}
-
 - (void)setAdditionalHeight:(CGFloat)additionalHeight {
   if (AreCGFloatsEqual(_additionalHeight, additionalHeight))
     return;
   _additionalHeight = additionalHeight;
-  [self updateHeight];
+  [self updateToolbarHeightRange];
 }
 
 - (void)setCollapsesAdditionalHeight:(BOOL)collapsesAdditionalHeight {
   if (_collapsesAdditionalHeight == collapsesAdditionalHeight)
     return;
   _collapsesAdditionalHeight = collapsesAdditionalHeight;
-  [self updateHeight];
+  [self updateToolbarHeightRange];
+}
+
+- (const HeightRange&)heightRange {
+  // Custom getter is needed to support the C++ reference type.
+  return _heightRange;
 }
 
 - (void)setProgress:(CGFloat)progress {
@@ -104,16 +105,15 @@
   if (AreCGFloatsEqual(_progress, progress))
     return;
   _progress = progress;
-  [self updateHeight];
+  [self updateHeightConstant];
 }
 
 - (void)setCollapsingToolbar:(UIView<ToolbarCollapsing>*)collapsingToolbar {
   if (_collapsingToolbar == collapsingToolbar)
     return;
-
   [self stopObservingCollapsingToolbar];
   _collapsingToolbar = collapsingToolbar;
-  [self updateToolbarHeightRange];
+  [self updateCollapsingToolbarHeights];
   if (self.active)
     [self startObservingCollapsingToolbar];
 }
@@ -122,8 +122,8 @@
 
 - (CGFloat)toolbarHeightForProgress:(CGFloat)progress {
   progress = base::ClampToRange(progress, kMinProgress, kMaxProgress);
-  CGFloat base = self.collapsedHeight;
-  CGFloat range = self.expandedHeight - self.collapsedHeight;
+  CGFloat base = self.collapsedToolbarHeight;
+  CGFloat range = self.expandedToolbarHeight - self.collapsedToolbarHeight;
   if (self.collapsesAdditionalHeight) {
     range += self.additionalHeight;
   } else {
@@ -138,7 +138,7 @@
                       ofObject:(id)object
                         change:(NSDictionary*)change
                        context:(void*)context {
-  [self updateToolbarHeightRange];
+  [self updateCollapsingToolbarHeights];
 }
 
 #pragma mark - KVO Helpers
@@ -166,15 +166,32 @@
 
 #pragma mark - Private
 
-// Updates the constraint using the collapsing toolbar's height range.
+// Upates the collapsed and expanded heights from self.collapsingToolbar.
+- (void)updateCollapsingToolbarHeights {
+  self.collapsedToolbarHeight = self.collapsingToolbar.collapsedToolbarHeight;
+  self.expandedToolbarHeight = self.collapsingToolbar.expandedToolbarHeight;
+  [self updateToolbarHeightRange];
+}
+
+// Updates the height range using the current collapsing toolbar height values
+// and additional height behavior.
 - (void)updateToolbarHeightRange {
-  self.collapsedHeight = self.collapsingToolbar.collapsedToolbarHeight;
-  self.expandedHeight = self.collapsingToolbar.expandedToolbarHeight;
+  HeightRange oldHeightRange = self.heightRange;
+  CGFloat minHeight =
+      self.collapsedToolbarHeight +
+      (self.collapsesAdditionalHeight ? 0.0 : self.additionalHeight);
+  CGFloat maxHeight = self.expandedToolbarHeight + self.additionalHeight;
+  _heightRange = HeightRange(minHeight, maxHeight);
+  if (_heightRange == oldHeightRange)
+    return;
+  [self updateHeightConstant];
+  [self.delegate collapsingHeightConstraint:self
+                   didUpdateFromHeightRange:oldHeightRange];
 }
 
 // Updates the constraint's constant
-- (void)updateHeight {
-  self.constant = [self toolbarHeightForProgress:self.progress];
+- (void)updateHeightConstant {
+  self.constant = self.heightRange.GetInterpolatedHeight(self.progress);
 }
 
 @end
diff --git a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_delegate.h b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_delegate.h
new file mode 100644
index 0000000..12661bf
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_delegate.h
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_COLLAPSING_TOOLBAR_HEIGHT_CONSTRAINT_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_COLLAPSING_TOOLBAR_HEIGHT_CONSTRAINT_DELEGATE_H_
+
+#import <Foundation/Foundation.h>
+
+@class CollapsingToolbarHeightConstraint;
+namespace toolbar_container {
+class HeightRange;
+}  // namespace toolbar_container
+
+// The delegate for the collapsing height constraint.
+@protocol CollapsingToolbarHeightConstraintDelegate<NSObject>
+
+// Called when |constraint|'s height range is changed from |oldHeightRange|.
+- (void)collapsingHeightConstraint:
+            (nonnull CollapsingToolbarHeightConstraint*)constraint
+          didUpdateFromHeightRange:
+              (const toolbar_container::HeightRange&)oldHeightRange;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_COLLAPSING_TOOLBAR_HEIGHT_CONSTRAINT_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_unittest.mm b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_unittest.mm
index 3539060..1e9a9314 100644
--- a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_unittest.mm
+++ b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_unittest.mm
@@ -78,48 +78,6 @@
   NSMutableArray<NSLayoutConstraint*>* constraints_ = nil;
 };
 
-// Tests that |-toolbarHeightForProgress:| returns the expected values.
-TEST_F(CollapsingToolbarHeightConstraintTest, ToolbarHeightForProgress) {
-  CollapsingView* view = [[CollapsingView alloc] initWithFrame:CGRectZero];
-  view.expandedToolbarHeight = 100.0;
-  view.collapsedToolbarHeight = 50.0;
-  CollapsingToolbarHeightConstraint* constraint = AddViewToContainer(view);
-
-  // Test collapsing toolbar.
-  EXPECT_EQ([constraint toolbarHeightForProgress:1.0], 100.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.5], 75.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.0], 50.0);
-  // Tests with collapsing additional height.
-  constraint.additionalHeight = 100.0;
-  constraint.collapsesAdditionalHeight = YES;
-  EXPECT_EQ([constraint toolbarHeightForProgress:1.0], 200.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.5], 125.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.0], 50.0);
-  // Tests with non-collapsing additional height.
-  constraint.collapsesAdditionalHeight = NO;
-  EXPECT_EQ([constraint toolbarHeightForProgress:1.0], 200.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.5], 175.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.0], 150.0);
-
-  // Test non-collapsing toolbar.
-  constraint.additionalHeight = 0.0;
-  view.collapsedToolbarHeight = 100.0;
-  EXPECT_EQ([constraint toolbarHeightForProgress:1.0], 100.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.5], 100.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.0], 100.0);
-  // Tests with collapsing additional height.
-  constraint.additionalHeight = 100.0;
-  constraint.collapsesAdditionalHeight = YES;
-  EXPECT_EQ([constraint toolbarHeightForProgress:1.0], 200.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.5], 150.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.0], 100.0);
-  // Tests with non-collapsing additional height.
-  constraint.collapsesAdditionalHeight = NO;
-  EXPECT_EQ([constraint toolbarHeightForProgress:1.0], 200.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.5], 200.0);
-  EXPECT_EQ([constraint toolbarHeightForProgress:0.0], 200.0);
-}
-
 // Tests interpolating the height value of a collapsing view.
 TEST_F(CollapsingToolbarHeightConstraintTest, CollapsingConstraint) {
   CollapsingView* view = [[CollapsingView alloc] initWithFrame:CGRectZero];
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_coordinator.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_container_coordinator.mm
index 9857a59..b2f796b 100644
--- a/ios/chrome/browser/ui/toolbar_container/toolbar_container_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_coordinator.mm
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h"
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.h"
+#import "ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -63,8 +64,11 @@
 #pragma mark - Public
 
 - (CGFloat)toolbarStackHeightForFullscreenProgress:(CGFloat)progress {
-  return [self.containerViewController
-      toolbarStackHeightForFullscreenProgress:progress];
+  if (!self.started)
+    return 0.0;
+  const toolbar_container::HeightRange& stackHeightRange =
+      self.containerViewController.heightRange;
+  return stackHeightRange.GetInterpolatedHeight(progress);
 }
 
 #pragma mark - ChromeCoordinator
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.h b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.h
index 97e0927..28ea016e 100644
--- a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.h
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.h
@@ -9,6 +9,10 @@
 
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h"
 
+namespace toolbar_container {
+class HeightRange;
+}  // namespace toolbar_container
+
 // The layout orientation for a toolbar container.
 enum class ToolbarContainerOrientation { kTopToBottom, kBottomToTop };
 
@@ -26,9 +30,10 @@
 // The toolbar view controllers being managed by this container.
 @property(nonatomic, strong) NSArray<UIViewController*>* toolbars;
 
-// Returns the height of the toolbar views managed by this container at
-// |progress|.
-- (CGFloat)toolbarStackHeightForFullscreenProgress:(CGFloat)progress;
+// The height range of the overall stack.  It is calculated using the collapsed
+// and expanded heights of the views managed by |toolbars|.
+@property(nonatomic, readonly)
+    const toolbar_container::HeightRange& heightRange;
 
 @end
 
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.mm
index 7de960a7..63bb43b 100644
--- a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.mm
@@ -4,11 +4,15 @@
 
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.h"
 
+#include <vector>
+
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
 #import "ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.h"
+#import "ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_delegate.h"
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_view.h"
+#import "ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 
@@ -16,13 +20,31 @@
 #error "This file requires ARC support."
 #endif
 
-@interface ToolbarContainerViewController ()
+using toolbar_container::HeightRange;
+
+@interface ToolbarContainerViewController ()<
+    CollapsingToolbarHeightConstraintDelegate> {
+  // Backing variables for properties of same name.
+  HeightRange _heightRange;
+  std::vector<CGFloat> _toolbarExpansionStartProgresses;
+}
+
 // The constraint managing the height of the container.
 @property(nonatomic, strong, readonly) NSLayoutConstraint* heightConstraint;
 // The height constraints for the toolbar views.
 @property(nonatomic, strong, readonly)
     NSMutableArray<CollapsingToolbarHeightConstraint*>*
         toolbarHeightConstraints;
+// The fullscreen progresses at which the toolbars begin expanding.  As the
+// fullscreen progress goes from 0.0 to 1.0, the toolbars are expanded in the
+// reverse of order of self.toolbars so that the toolbar closest to the page
+// content is expanded first for scroll events.  Each toolbar is expanded for a
+// portion of the [0.0, 1.0] progress range proportional to its height delta
+// relative to the overall height delta of the toolbar stack.  This creates the
+// effect of the overall stack height adjusting linearly while each individual
+// toolbar's height is adjusted sequentially.
+@property(nonatomic, assign, readonly)
+    std::vector<CGFloat>& toolbarExpansionStartProgresses;
 // Returns the height constraint for the first toolbar in self.toolbars.
 @property(nonatomic, readonly)
     CollapsingToolbarHeightConstraint* firstToolbarHeightConstraint;
@@ -40,6 +62,16 @@
 
 #pragma mark - Accessors
 
+- (const HeightRange&)heightRange {
+  // Custom getter is needed to support the C++ reference type.
+  return _heightRange;
+}
+
+- (std::vector<CGFloat>&)toolbarExpansionStartProgresses {
+  // Custom getter is needed to support the C++ reference type.
+  return _toolbarExpansionStartProgresses;
+}
+
 - (CollapsingToolbarHeightConstraint*)firstToolbarHeightConstraint {
   if (!self.viewLoaded || !self.toolbars.count)
     return nil;
@@ -49,35 +81,57 @@
 }
 
 - (void)setAdditionalStackHeight:(CGFloat)additionalStackHeight {
+  DCHECK_GE(additionalStackHeight, 0.0);
   if (AreCGFloatsEqual(_additionalStackHeight, additionalStackHeight))
     return;
   _additionalStackHeight = additionalStackHeight;
   self.firstToolbarHeightConstraint.additionalHeight = _additionalStackHeight;
-  [self updateHeightConstraint];
 }
 
-#pragma mark - Public
+#pragma mark - CollapsingToolbarHeightConstraintDelegate
 
-- (CGFloat)toolbarStackHeightForFullscreenProgress:(CGFloat)progress {
-  CGFloat height = 0.0;
-  for (CollapsingToolbarHeightConstraint* constraint in self
-           .toolbarHeightConstraints) {
-    height += [constraint toolbarHeightForProgress:progress];
-  }
-  return height;
+- (void)collapsingHeightConstraint:
+            (CollapsingToolbarHeightConstraint*)constraint
+          didUpdateFromHeightRange:
+              (const toolbar_container::HeightRange&)oldHeightRange {
+  [self updateHeightRangeWithRange:self.heightRange + constraint.heightRange -
+                                   oldHeightRange];
 }
 
 #pragma mark - FullscreenUIElement
 
 - (void)updateForFullscreenProgress:(CGFloat)progress {
-  for (CollapsingToolbarHeightConstraint* heightConstraint in self
-           .toolbarHeightConstraints) {
-    heightConstraint.progress = progress;
+  // No changes are needed if there are no collapsing toolbars.
+  CGFloat stackHeightDelta = self.heightRange.delta();
+  if (!self.viewLoaded || AreCGFloatsEqual(stackHeightDelta, 0.0) ||
+      !self.toolbars.count) {
+    return;
+  }
+
+  for (NSUInteger i = 0; i < self.toolbars.count; ++i) {
+    CollapsingToolbarHeightConstraint* constraint =
+        self.toolbarHeightConstraints[i];
+    // Calculate the progress range for the toolbar.  |startProgress| is pre-
+    // calculated and stored in self.toolbarExpansionStartProgresses.  The end
+    // progress is calculated by adding the proportion of the overall stack
+    // height delta created by this toolbar.
+    CGFloat startProgress = self.toolbarExpansionStartProgresses[i];
+    CGFloat endProgress =
+        startProgress + constraint.heightRange.delta() / stackHeightDelta;
+    // CollapsingToolbarHeightConstraint clamps its progress value between 0.0
+    // and 1.0, so |constraint|'s progress value will be set:
+    // -  0.0 when |progress| <= |startProgress|,
+    // -  1.0 when |progress| >= |endProgress|, and
+    // -  scaled linearly from 0.0 to 1.0 for |progress| values within that
+    //    range.
+    constraint.progress =
+        (progress - startProgress) / (endProgress - startProgress);
   }
 }
 
 - (void)updateForFullscreenEnabled:(BOOL)enabled {
-  [self updateForFullscreenProgress:1.0];
+  if (!enabled)
+    [self updateForFullscreenProgress:1.0];
 }
 
 - (void)animateFullscreenWithAnimator:(FullscreenAnimator*)animator {
@@ -103,7 +157,8 @@
   if (_collapsesSafeArea == collapsesSafeArea)
     return;
   _collapsesSafeArea = collapsesSafeArea;
-  self.firstToolbarHeightConstraint.collapsesAdditionalHeight = YES;
+  self.firstToolbarHeightConstraint.collapsesAdditionalHeight =
+      _collapsesSafeArea;
 }
 
 - (void)setToolbars:(NSArray<UIViewController*>*)toolbars {
@@ -111,6 +166,7 @@
     return;
   [self removeToolbars];
   _toolbars = toolbars;
+  self.toolbarExpansionStartProgresses.resize(_toolbars.count);
   [self setUpToolbarStack];
 }
 
@@ -161,7 +217,7 @@
   }
   [self createToolbarHeightConstraints];
   [self updateForSafeArea];
-  [self updateHeightConstraint];
+  [self calculateToolbarExpansionStartProgresses];
 }
 
 // Removes all the toolbars from the view.
@@ -178,8 +234,7 @@
 - (void)addToolbarAtIndex:(NSUInteger)index {
   DCHECK_LT(index, self.toolbars.count);
   UIViewController* toolbar = self.toolbars[index];
-  if (toolbar.parentViewController == self)
-    return;
+  DCHECK(!toolbar.parentViewController);
 
   // Add the toolbar and its view controller.
   UIView* toolbarView = toolbar.view;
@@ -215,9 +270,15 @@
 
 // Deactivates the toolbar height constraints and resets the property.
 - (void)resetToolbarHeightConstraints {
-  if (_toolbarHeightConstraints.count)
+  if (_toolbarHeightConstraints.count) {
     [NSLayoutConstraint deactivateConstraints:_toolbarHeightConstraints];
+    for (CollapsingToolbarHeightConstraint* constraint in
+             _toolbarHeightConstraints) {
+      constraint.delegate = nil;
+    }
+  }
   _toolbarHeightConstraints = nil;
+  _heightRange = HeightRange();
 }
 
 // Creates and activates height constriants for the toolbars and adds them to
@@ -226,6 +287,7 @@
 - (void)createToolbarHeightConstraints {
   [self resetToolbarHeightConstraints];
   _toolbarHeightConstraints = [NSMutableArray array];
+  HeightRange heightRange;
   for (NSUInteger i = 0; i < self.toolbars.count; ++i) {
     UIView* toolbarView = self.toolbars[i].view;
     CollapsingToolbarHeightConstraint* heightConstraint =
@@ -236,11 +298,49 @@
       heightConstraint.additionalHeight = self.additionalStackHeight;
       heightConstraint.collapsesAdditionalHeight = self.collapsesSafeArea;
     }
+    // Set as delegate to receive notifications of height range updates.
+    heightConstraint.delegate = self;
+    // Add the height range values.
+    heightRange += heightConstraint.heightRange;
     [_toolbarHeightConstraints addObject:heightConstraint];
   }
+  [self updateHeightRangeWithRange:heightRange];
 }
 
-// Updates the height of the first toolbar to account for the safe area.
+// Updates the height range of the stack with |range|.
+- (void)updateHeightRangeWithRange:(const HeightRange&)range {
+  if (_heightRange == range)
+    return;
+  BOOL maxHeightUpdated =
+      !AreCGFloatsEqual(_heightRange.max_height(), range.max_height());
+  BOOL deltaUpdated = !AreCGFloatsEqual(_heightRange.delta(), range.delta());
+  _heightRange = range;
+  if (maxHeightUpdated)
+    self.heightConstraint.constant = _heightRange.max_height();
+  if (deltaUpdated)
+    [self calculateToolbarExpansionStartProgresses];
+}
+
+// Calculates the fullscreen progress values at which the toolbars should start
+// expanding.  See comments for self.toolbarExpansionStartProgresses for more
+// details.
+- (void)calculateToolbarExpansionStartProgresses {
+  DCHECK_EQ(self.toolbarExpansionStartProgresses.size(), self.toolbars.count);
+  if (!self.toolbars.count)
+    return;
+  CGFloat startProgress = 0.0;
+  for (NSUInteger i = self.toolbars.count - 1; i > 0; --i) {
+    self.toolbarExpansionStartProgresses[i] = startProgress;
+    CGFloat delta = self.heightRange.delta();
+    if (delta > 0.0) {
+      startProgress +=
+          self.toolbarHeightConstraints[i].heightRange.delta() / delta;
+    }
+  }
+  self.toolbarExpansionStartProgresses[0] = startProgress;
+}
+
+// Adds additional height to the first toolbar to account for the safe area.
 - (void)updateForSafeArea {
   if (@available(iOS 11, *)) {
     if (self.orientation == ToolbarContainerOrientation::kTopToBottom) {
@@ -257,19 +357,4 @@
   }
 }
 
-// Updates the height constraint's constant to the cumulative expanded height of
-// all the toolbars.
-- (void)updateHeightConstraint {
-  if (!self.viewLoaded)
-    return;
-  // Calculate the cumulative expanded toolbar height.
-  CGFloat cumulativeExpandedHeight = 0.0;
-  for (CollapsingToolbarHeightConstraint* constraint in self
-           .toolbarHeightConstraints) {
-    cumulativeExpandedHeight +=
-        constraint.expandedHeight + constraint.additionalHeight;
-  }
-  self.heightConstraint.constant = cumulativeExpandedHeight;
-}
-
 @end
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller_unittest.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller_unittest.mm
index 44b78c2..959901e 100644
--- a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller_unittest.mm
@@ -4,52 +4,87 @@
 
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.h"
 
+#include <algorithm>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_collapsing.h"
+#import "ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#include "testing/platform_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+using toolbar_container::HeightRange;
+
 namespace {
 // The container view width.
 const CGFloat kContainerViewWidth = 300.0;
-// The expanded height of the collapsing toolbar.
-const CGFloat kExpandedToolbarHeight = 100.0;
-// The collapsed height of the collapsing toolbar.
+// The number of toolbars to add.
+const size_t kToolbarCount = 2;
+// The collapsed and expanded heights of the toolbars.
 const CGFloat kCollapsedToolbarHeight = 50.0;
-// The height of the non-collapsing toolbar.
+const CGFloat kExpandedToolbarHeight = 150.0;
+// The non-collapsing toolbar height.
 const CGFloat kNonCollapsingToolbarHeight = 75.0;
+// The inset into the stack for the safe area.
+const CGFloat kSafeAreaStackInset = 100.0;
+// The progress values to check.
+const CGFloat kStackProgressValues[] = {0.0, 0.25, 0.5, 0.75, 1.0};
+// Parameters used for the test fixtures.
+typedef NS_ENUM(NSUInteger, ToolbarContainerTestConfig) {
+  kEmptyConfig = 0,
+  kTopToBottom = 1 << 0,
+  kCollapsingToolbars = 1 << 1,
+  kCollapsingSafeInset = 1 << 2,
+  kToolbarContainerConfigMax = 1 << 3,
+};
+// Returns a string version of |frame| to use for error printing.
+std::string GetFrameString(CGRect frame) {
+  return base::SysNSStringToUTF8(NSStringFromCGRect(frame));
+}
 }  // namespace
 
 // Test toolbar view.
-@interface TestToolbarView : UIView<ToolbarCollapsing>
-// Redefine ToolbarCollapsing properies as readwrite.
-@property(nonatomic, assign, readwrite) CGFloat expandedToolbarHeight;
-@property(nonatomic, assign, readwrite) CGFloat collapsedToolbarHeight;
+@interface TestToolbarView : UIView<ToolbarCollapsing> {
+  HeightRange _heightRange;
+}
+- (instancetype)initWithHeightRange:(const HeightRange&)heightRange;
 @end
 
 @implementation TestToolbarView
-@synthesize expandedToolbarHeight = _expandedToolbarHeight;
-@synthesize collapsedToolbarHeight = _collapsedToolbarHeight;
+- (instancetype)initWithHeightRange:(const HeightRange&)heightRange {
+  if (self = [super init])
+    _heightRange = heightRange;
+  return self;
+}
+- (CGFloat)expandedToolbarHeight {
+  return _heightRange.max_height();
+}
+- (CGFloat)collapsedToolbarHeight {
+  return _heightRange.min_height();
+}
 @end
 
 // Test toolbar view controller.
-@interface TestToolbarViewController : UIViewController
+@interface TestToolbarViewController : UIViewController {
+  HeightRange _heightRange;
+}
 @property(nonatomic, strong, readonly) TestToolbarView* toolbarView;
-@property(nonatomic, assign) CGFloat expandedToolbarHeight;
-@property(nonatomic, assign) CGFloat collapsedToolbarHeight;
+- (instancetype)initWithHeightRange:(const HeightRange&)heightRange;
 @end
 
 @implementation TestToolbarViewController
-@synthesize expandedToolbarHeight = _expandedToolbarHeight;
-@synthesize collapsedToolbarHeight = _collapsedToolbarHeight;
+- (instancetype)initWithHeightRange:(const HeightRange&)heightRange {
+  if (self = [super init])
+    _heightRange = heightRange;
+  return self;
+}
 - (void)loadView {
-  TestToolbarView* view = [[TestToolbarView alloc] initWithFrame:CGRectZero];
-  view.expandedToolbarHeight = self.expandedToolbarHeight;
-  view.collapsedToolbarHeight = self.collapsedToolbarHeight;
-  self.view = view;
+  self.view = [[TestToolbarView alloc] initWithHeightRange:_heightRange];
 }
 - (TestToolbarView*)toolbarView {
   return static_cast<TestToolbarView*>(self.view);
@@ -57,28 +92,21 @@
 @end
 
 // Test fixture for ToolbarContainerViewController.
-class ToolbarContainerViewControllerTest : public PlatformTest {
+class ToolbarContainerViewControllerTest
+    : public ::testing::TestWithParam<ToolbarContainerTestConfig> {
  public:
   ToolbarContainerViewControllerTest()
-      : PlatformTest(),
-        window_([[UIWindow alloc] init]),
-        view_controller_([[ToolbarContainerViewController alloc] init]),
-        collapsing_toolbar_([[TestToolbarViewController alloc] init]),
-        non_collapsing_toolbar_([[TestToolbarViewController alloc] init]) {
-    collapsing_toolbar_.expandedToolbarHeight = kExpandedToolbarHeight;
-    collapsing_toolbar_.collapsedToolbarHeight = kCollapsedToolbarHeight;
-    non_collapsing_toolbar_.expandedToolbarHeight = kNonCollapsingToolbarHeight;
-    non_collapsing_toolbar_.collapsedToolbarHeight =
-        kNonCollapsingToolbarHeight;
-    [container_view().widthAnchor constraintEqualToConstant:kContainerViewWidth]
-        .active = YES;
+      : window_([[UIWindow alloc] init]),
+        view_controller_([[ToolbarContainerViewController alloc] init]) {
+    // Resize the window and add the container view such that it hugs the
+    // leading/trailing edges.
     window_.frame = CGRectMake(0.0, 0.0, kContainerViewWidth, 1000);
     [window_ addSubview:container_view()];
     AddSameConstraintsToSides(window_, container_view(),
                               LayoutSides::kLeading | LayoutSides::kTrailing);
-    SetOrientation(ToolbarContainerOrientation::kTopToBottom);
-    view_controller_.toolbars =
-        @[ non_collapsing_toolbar_, collapsing_toolbar_ ];
+    UpdateForOrientationConfig();
+    UpdateForToolbarCollapsingConfig();
+    UpdateForSafeInsetCollapsingConfig();
     ForceLayout();
   }
 
@@ -86,76 +114,102 @@
     view_controller_.toolbars = nil;
   }
 
-  // Returns the additional stack height created by the safe area insets.
-  CGFloat GetAdditionalStackHeight() {
-    CGFloat additional_height = 0.0;
-    bool top_to_bottom = view_controller_.orientation ==
-                         ToolbarContainerOrientation::kTopToBottom;
+  // Convenience getters for each of the config option flags.
+  bool IsTopToBottom() { return (GetParam() & kTopToBottom) == kTopToBottom; }
+  bool HasCollapsingToolbars() {
+    return (GetParam() & kCollapsingToolbars) == kCollapsingToolbars;
+  }
+  bool HasCollapsingSafeInset() {
+    return (GetParam() & kCollapsingSafeInset) == kCollapsingSafeInset;
+  }
+
+  // Sets the orientation of the container and constraints its view to the top
+  // or bottom of the window.
+  void UpdateForOrientationConfig() {
+    view_controller_.orientation =
+        IsTopToBottom() ? ToolbarContainerOrientation::kTopToBottom
+                        : ToolbarContainerOrientation::kBottomToTop;
     if (@available(iOS 11, *)) {
-      additional_height = top_to_bottom
-                              ? container_view().safeAreaInsets.top
-                              : container_view().safeAreaInsets.bottom;
-    } else if (top_to_bottom) {
-      additional_height = view_controller_.topLayoutGuide.length;
-    }
-    return additional_height;
-  }
-
-  // Returns the expected height of the container.
-  CGFloat GetExpectedContainerHeight() {
-    return kNonCollapsingToolbarHeight + kExpandedToolbarHeight +
-           GetAdditionalStackHeight();
-  }
-
-  // Expand or collapse the toolbars.
-  void SetExpanded(bool expanded) {
-    [view_controller_ updateForFullscreenProgress:expanded ? 1.0 : 0.0];
-    ForceLayout();
-  }
-
-  // Sets the container orientation.
-  void SetOrientation(ToolbarContainerOrientation orientation) {
-    container_positioning_constraint_.active = NO;
-    view_controller_.orientation = orientation;
-    if (orientation == ToolbarContainerOrientation::kTopToBottom) {
-      container_positioning_constraint_ = [container_view().topAnchor
-          constraintEqualToAnchor:window_.topAnchor];
+      UIEdgeInsets safe_insets = container_view().safeAreaInsets;
+      if (IsTopToBottom())
+        safe_insets.top = kSafeAreaStackInset - safe_insets.top;
+      else
+        safe_insets.bottom = kSafeAreaStackInset - safe_insets.bottom;
+      view_controller_.additionalSafeAreaInsets = safe_insets;
     } else {
-      container_positioning_constraint_ = [container_view().bottomAnchor
-          constraintEqualToAnchor:window_.bottomAnchor];
-    }
-    container_positioning_constraint_.active = YES;
-    ForceLayout();
-  }
-
-  // Sets whether the safe area should be collapsed.
-  void SetCollapsesSafeArea(bool collapses_safe_area) {
-    view_controller_.collapsesSafeArea = collapses_safe_area;
-  }
-
-  // Sets the safe area insets or top layout guide for the container and forces
-  // a layout.
-  void SetSafeAreaInsets(UIEdgeInsets insets) {
-    if (@available(iOS 11, *)) {
-      view_controller_.additionalSafeAreaInsets = insets;
-    } else {
-      // Deactivate all pre-existing constraints for the layout guides' heights.
+      // Deactivate all pre-existing constraints for the |guide|'s height.
       // They are added by UIKit at the maximum priority, so must be removed to
-      // update the lengths of the layout guides.
+      // update |guide|'s length.
+      id<UILayoutSupport> guide = IsTopToBottom()
+                                      ? view_controller_.topLayoutGuide
+                                      : view_controller_.bottomLayoutGuide;
       for (NSLayoutConstraint* constraint in container_view().constraints) {
-        if (constraint.firstAttribute == NSLayoutAttributeHeight &&
-            (constraint.firstItem == view_controller_.topLayoutGuide ||
-             constraint.firstItem == view_controller_.bottomLayoutGuide)) {
+        if (constraint.firstItem == guide &&
+            constraint.firstAttribute == NSLayoutAttributeHeight) {
           constraint.active = NO;
         }
       }
-      [view_controller_.topLayoutGuide.heightAnchor
-          constraintEqualToConstant:insets.top]
-          .active = YES;
-      [view_controller_.bottomLayoutGuide.heightAnchor
-          constraintEqualToConstant:insets.bottom]
+      [guide.heightAnchor constraintEqualToConstant:kSafeAreaStackInset]
           .active = YES;
     }
+  }
+
+  // Adds collapsible or non-collapsible toolbars to the container, depending on
+  // the config flag.
+  void UpdateForToolbarCollapsingConfig() {
+    // Calculate the height range for the toolbars.
+    HeightRange toolbar_height_range;
+    if (HasCollapsingToolbars()) {
+      toolbar_height_range =
+          HeightRange(kCollapsedToolbarHeight, kExpandedToolbarHeight);
+    } else {
+      toolbar_height_range =
+          HeightRange(kNonCollapsingToolbarHeight, kNonCollapsingToolbarHeight);
+    }
+    // Add kToolbarCount toolbars with |toolbar_height_range|.
+    height_ranges_ =
+        std::vector<HeightRange>(kToolbarCount, toolbar_height_range);
+    NSMutableArray* toolbars = [NSMutableArray array];
+    for (const HeightRange& height_range : height_ranges_) {
+      TestToolbarViewController* toolbar =
+          [[TestToolbarViewController alloc] initWithHeightRange:height_range];
+      [toolbars addObject:toolbar];
+    }
+    view_controller_.toolbars = toolbars;
+  }
+
+  // Updates the view controller safe inset collapsing behavior based on the
+  // config.
+  void UpdateForSafeInsetCollapsingConfig() {
+    view_controller_.collapsesSafeArea = HasCollapsingSafeInset();
+  }
+
+  // Returns the total height range for the toolbar view at |index|, accounting
+  // for both the toolbar expansion and the collapsing safe area inset.
+  HeightRange GetTotalToolbarHeightRange(NSUInteger index) {
+    HeightRange height_range = height_ranges_[index];
+    if (index == 0) {
+      bool collapses_safe_area = view_controller_.collapsesSafeArea;
+      HeightRange safe_area_height_range = HeightRange(
+          collapses_safe_area ? 0.0 : kSafeAreaStackInset, kSafeAreaStackInset);
+      height_range += safe_area_height_range;
+    }
+    return height_range;
+  }
+
+  // Returns the expected height of the toolbar stack.
+  CGFloat GetExpectedStackHeight() {
+    CGFloat expected_stack_height = 0.0;
+    for (NSUInteger index = 0; index < kToolbarCount; ++index) {
+      expected_stack_height += GetTotalToolbarHeightRange(index).max_height();
+    }
+    return expected_stack_height;
+  }
+
+  // Set the stack progress.
+  void SetStackProgress(CGFloat progress) {
+    stack_progress_ = progress;
+    [view_controller_ updateForFullscreenProgress:progress];
     ForceLayout();
   }
 
@@ -165,186 +219,105 @@
     [window_ layoutIfNeeded];
     [container_view() setNeedsLayout];
     [container_view() layoutIfNeeded];
+    stack_height_delta_ = 0.0;
+    for (NSUInteger index = 0; index < kToolbarCount; ++index) {
+      stack_height_delta_ += GetTotalToolbarHeightRange(index).delta();
+    }
   }
 
-  // The views.
-  UIView* container_view() { return view_controller_.view; }
-  TestToolbarView* collapsing_toolbar_view() {
-    return collapsing_toolbar_.toolbarView;
-  }
-  TestToolbarView* non_collapsing_toolbar_view() {
-    return non_collapsing_toolbar_.toolbarView;
-  }
-  TestToolbarView* first_toolbar_view() {
-    return static_cast<TestToolbarViewController*>(view_controller_.toolbars[0])
+  // Returns the toolbar view at |index|.
+  TestToolbarView* GetToolbarView(NSUInteger index) {
+    return static_cast<TestToolbarViewController*>(
+               view_controller_.toolbars[index])
         .toolbarView;
   }
 
+  // Returns the progress value for the toolbar at |index| for the current stack
+  // progress.
+  CGFloat GetToolbarProgress(NSUInteger index) {
+    // Calculate the start progress.
+    CGFloat start_progress = 0.0;
+    for (NSUInteger i = kToolbarCount - 1; i > index; --i) {
+      if (stack_height_delta_ > 0.0) {
+        start_progress +=
+            GetTotalToolbarHeightRange(i).delta() / stack_height_delta_;
+      }
+    }
+    // Get the individual toolbar progress.
+    HeightRange height_range = GetTotalToolbarHeightRange(index);
+    CGFloat end_progress =
+        start_progress + height_range.delta() / stack_height_delta_;
+    CGFloat progress =
+        (stack_progress_ - start_progress) / (end_progress - start_progress);
+    progress = std::min(static_cast<CGFloat>(1.0), progress);
+    progress = std::max(static_cast<CGFloat>(0.0), progress);
+    return progress;
+  }
+
+  // Returns the expected frame for the toolbar at |index| at the current stack
+  // progress.
+  CGRect GetExpectedToolbarFrame(NSUInteger index) {
+    const HeightRange& height_range = GetTotalToolbarHeightRange(index);
+    CGSize size = CGSizeMake(
+        kContainerViewWidth,
+        height_range.GetInterpolatedHeight(GetToolbarProgress(index)));
+    CGFloat origin_y = 0.0;
+    bool is_first_toolbar = index == 0;
+    if (IsTopToBottom()) {
+      origin_y = is_first_toolbar
+                     ? 0.0
+                     : CGRectGetMaxY(GetExpectedToolbarFrame(index - 1));
+    } else {
+      CGFloat bottom_edge =
+          is_first_toolbar ? CGRectGetMaxY(container_view().bounds)
+                           : CGRectGetMinY(GetExpectedToolbarFrame(index - 1));
+      origin_y = bottom_edge - size.height;
+    }
+    return CGRectMake(0.0, origin_y, size.width, size.height);
+  }
+
+  // Checks that the frames of the toolbar views are expected for the current
+  // stack progress.
+  void CheckToolbarFrames() {
+    for (NSUInteger index = 0; index < kToolbarCount; ++index) {
+      CGRect toolbar_frame = GetToolbarView(index).frame;
+      CGRect expected_toolbar_frame = GetExpectedToolbarFrame(index);
+      EXPECT_TRUE(CGRectEqualToRect(toolbar_frame, expected_toolbar_frame)) <<
+          "IsTopToBottom          : " << IsTopToBottom() << "\n"
+          "HasCollapsingToolbars  : " << HasCollapsingToolbars() << "\n"
+          "HasCollapsingSafeInset : " << HasCollapsingSafeInset() << "\n"
+          "Stack Progress         : " << stack_progress_ << "\n"
+          "Toolbar Index          : " << index << "\n"
+          "toolbar_frame          : " << GetFrameString(toolbar_frame) << "\n"
+          "expected_toolbar_frame : " << GetFrameString(expected_toolbar_frame);
+    }
+  }
+
+  // The view.
+  UIView* container_view() { return view_controller_.view; }
+
  private:
   __strong UIWindow* window_ = nil;
   __strong ToolbarContainerViewController* view_controller_ = nil;
-  __strong NSLayoutConstraint* container_positioning_constraint_ = nil;
-  __strong TestToolbarViewController* collapsing_toolbar_ = nil;
-  __strong TestToolbarViewController* non_collapsing_toolbar_ = nil;
+  std::vector<HeightRange> height_ranges_;
+  CGFloat stack_progress_ = 1.0;
+  CGFloat stack_height_delta_ = 0.0;
 };
 
-// Tests the layout of the toolbar views in when oriented from top to bottom
-// and the toolbars are fully expanded.
-TEST_F(ToolbarContainerViewControllerTest, TopToBottomExpanded) {
-  SetOrientation(ToolbarContainerOrientation::kTopToBottom);
-  SetExpanded(true);
-  EXPECT_EQ(GetExpectedContainerHeight(),
-            CGRectGetHeight(container_view().bounds));
-  CGRect non_collapsing_toolbar_frame =
-      CGRectMake(0.0, 0.0, kContainerViewWidth,
-                 kNonCollapsingToolbarHeight + GetAdditionalStackHeight());
-  EXPECT_TRUE(CGRectEqualToRect(non_collapsing_toolbar_frame,
-                                non_collapsing_toolbar_view().frame));
-  CGRect collapsing_toolbar_frame =
-      CGRectMake(0.0, CGRectGetMaxY(non_collapsing_toolbar_frame),
-                 kContainerViewWidth, kExpandedToolbarHeight);
-  EXPECT_TRUE(CGRectEqualToRect(collapsing_toolbar_frame,
-                                collapsing_toolbar_view().frame));
+// Tests the layout of the toolbar stack configured using the
+// ToolbarContainerTestConfig test fixture parameter.
+TEST_P(ToolbarContainerViewControllerTest, VerifyStackLayoutForProgresses) {
+  // Check that the container height is as expected.
+  EXPECT_EQ(CGRectGetHeight(container_view().bounds), GetExpectedStackHeight());
+  // Set the stack progress to the progress values in kStackProgressValues and
+  // verify the toolbar frames for each of these stack progress values.
+  for (size_t index = 0; index < base::size(kStackProgressValues); ++index) {
+    SetStackProgress(kStackProgressValues[index]);
+    CheckToolbarFrames();
+  }
 }
 
-// Tests the layout of the toolbar views in when oriented from top to bottom
-// and the toolbars are fully collapsed.
-TEST_F(ToolbarContainerViewControllerTest, TopToBottomCollapsed) {
-  SetOrientation(ToolbarContainerOrientation::kTopToBottom);
-  SetExpanded(false);
-  EXPECT_EQ(GetExpectedContainerHeight(),
-            CGRectGetHeight(container_view().bounds));
-  CGRect non_collapsing_toolbar_frame =
-      CGRectMake(0.0, 0.0, kContainerViewWidth,
-                 kNonCollapsingToolbarHeight + GetAdditionalStackHeight());
-  EXPECT_TRUE(CGRectEqualToRect(non_collapsing_toolbar_frame,
-                                non_collapsing_toolbar_view().frame));
-  CGRect collapsing_toolbar_frame =
-      CGRectMake(0.0, CGRectGetMaxY(non_collapsing_toolbar_frame),
-                 kContainerViewWidth, kCollapsedToolbarHeight);
-  EXPECT_TRUE(CGRectEqualToRect(collapsing_toolbar_frame,
-                                collapsing_toolbar_view().frame));
-}
-
-// Tests the layout of the toolbar views in when oriented from bottom to top
-// and the toolbars are fully expanded.
-// TODO(crbug.com/895766): reenable these tests on device.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_BottomToTopExpanded BottomToTopExpanded
-#else
-#define MAYBE_BottomToTopExpanded DISABLED_BottomToTopExpanded
-#endif
-TEST_F(ToolbarContainerViewControllerTest, MAYBE_BottomToTopExpanded) {
-  SetOrientation(ToolbarContainerOrientation::kBottomToTop);
-  SetExpanded(true);
-  CGFloat container_height = CGRectGetHeight(container_view().bounds);
-  EXPECT_EQ(GetExpectedContainerHeight(), container_height);
-  CGRect non_collapsing_toolbar_frame = CGRectMake(
-      0.0, container_height - kNonCollapsingToolbarHeight, kContainerViewWidth,
-      kNonCollapsingToolbarHeight + GetAdditionalStackHeight());
-  EXPECT_TRUE(CGRectEqualToRect(non_collapsing_toolbar_frame,
-                                non_collapsing_toolbar_view().frame));
-  CGRect collapsing_toolbar_frame = CGRectMake(
-      0.0, CGRectGetMinY(non_collapsing_toolbar_frame) - kExpandedToolbarHeight,
-      kContainerViewWidth, kExpandedToolbarHeight);
-  EXPECT_TRUE(CGRectEqualToRect(collapsing_toolbar_frame,
-                                collapsing_toolbar_view().frame));
-}
-
-// Tests the layout of the toolbar views in when oriented from bottom to top
-// and the toolbars are fully collapsed.
-// TODO(crbug.com/895766): reenable these tests on device.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_BottomToTopCollapsed BottomToTopCollapsed
-#else
-#define MAYBE_BottomToTopCollapsed DISABLED_BottomToTopCollapsed
-#endif
-TEST_F(ToolbarContainerViewControllerTest, MAYBE_BottomToTopCollapsed) {
-  SetOrientation(ToolbarContainerOrientation::kBottomToTop);
-  SetExpanded(false);
-  CGFloat container_height = CGRectGetHeight(container_view().bounds);
-  EXPECT_EQ(GetExpectedContainerHeight(), container_height);
-  CGRect non_collapsing_toolbar_frame = CGRectMake(
-      0.0, container_height - kNonCollapsingToolbarHeight, kContainerViewWidth,
-      kNonCollapsingToolbarHeight + GetAdditionalStackHeight());
-  EXPECT_TRUE(CGRectEqualToRect(non_collapsing_toolbar_frame,
-                                non_collapsing_toolbar_view().frame));
-  CGRect collapsing_toolbar_frame = CGRectMake(
-      0.0,
-      CGRectGetMinY(non_collapsing_toolbar_frame) - kCollapsedToolbarHeight,
-      kContainerViewWidth, kCollapsedToolbarHeight);
-  EXPECT_TRUE(CGRectEqualToRect(collapsing_toolbar_frame,
-                                collapsing_toolbar_view().frame));
-}
-
-// Tests that the container and the top toolbar's height accounts for the non-
-// collapsing safe area.
-TEST_F(ToolbarContainerViewControllerTest, NonCollapsingTopSafeArea) {
-  const UIEdgeInsets kSafeInsets = UIEdgeInsetsMake(100.0, 0.0, 0.0, 0.0);
-  SetCollapsesSafeArea(false);
-  SetSafeAreaInsets(kSafeInsets);
-  SetOrientation(ToolbarContainerOrientation::kTopToBottom);
-  EXPECT_EQ(GetExpectedContainerHeight(),
-            CGRectGetHeight(container_view().bounds));
-  SetExpanded(true);
-  TestToolbarView* toolbar_view = first_toolbar_view();
-  EXPECT_EQ(toolbar_view.expandedToolbarHeight + GetAdditionalStackHeight(),
-            CGRectGetHeight(toolbar_view.frame));
-  SetExpanded(false);
-  EXPECT_EQ(toolbar_view.collapsedToolbarHeight + GetAdditionalStackHeight(),
-            CGRectGetHeight(toolbar_view.frame));
-}
-
-// Tests that the container and the bottom toolbar's height accounts for the
-// non-collapsing safe area.
-TEST_F(ToolbarContainerViewControllerTest, NonCollapsingBottomSafeArea) {
-  const UIEdgeInsets kSafeInsets = UIEdgeInsetsMake(100.0, 0.0, 0.0, 0.0);
-  SetCollapsesSafeArea(false);
-  SetSafeAreaInsets(kSafeInsets);
-  SetOrientation(ToolbarContainerOrientation::kBottomToTop);
-  EXPECT_EQ(GetExpectedContainerHeight(),
-            CGRectGetHeight(container_view().bounds));
-  SetExpanded(true);
-  TestToolbarView* toolbar_view = first_toolbar_view();
-  EXPECT_EQ(toolbar_view.expandedToolbarHeight + GetAdditionalStackHeight(),
-            CGRectGetHeight(toolbar_view.frame));
-  SetExpanded(false);
-  EXPECT_EQ(toolbar_view.collapsedToolbarHeight + GetAdditionalStackHeight(),
-            CGRectGetHeight(toolbar_view.frame));
-}
-
-// Tests that the container and the top toolbar's height accounts for the
-// collapsing safe area.
-TEST_F(ToolbarContainerViewControllerTest, CollapsingTopSafeArea) {
-  const UIEdgeInsets kSafeInsets = UIEdgeInsetsMake(100.0, 0.0, 0.0, 0.0);
-  SetCollapsesSafeArea(true);
-  SetSafeAreaInsets(kSafeInsets);
-  SetOrientation(ToolbarContainerOrientation::kTopToBottom);
-  EXPECT_EQ(GetExpectedContainerHeight(),
-            CGRectGetHeight(container_view().bounds));
-  SetExpanded(true);
-  TestToolbarView* toolbar_view = first_toolbar_view();
-  EXPECT_EQ(toolbar_view.expandedToolbarHeight + GetAdditionalStackHeight(),
-            CGRectGetHeight(toolbar_view.frame));
-  SetExpanded(false);
-  EXPECT_EQ(toolbar_view.collapsedToolbarHeight,
-            CGRectGetHeight(toolbar_view.frame));
-}
-
-// Tests that the container and the bottom toolbar's height accounts for the
-// collapsing safe area.
-TEST_F(ToolbarContainerViewControllerTest, CollapsingBottomSafeArea) {
-  const UIEdgeInsets kSafeInsets = UIEdgeInsetsMake(100.0, 0.0, 0.0, 0.0);
-  SetCollapsesSafeArea(true);
-  SetSafeAreaInsets(kSafeInsets);
-  SetOrientation(ToolbarContainerOrientation::kBottomToTop);
-  EXPECT_EQ(GetExpectedContainerHeight(),
-            CGRectGetHeight(container_view().bounds));
-  SetExpanded(true);
-  TestToolbarView* toolbar_view = first_toolbar_view();
-  EXPECT_EQ(toolbar_view.expandedToolbarHeight + GetAdditionalStackHeight(),
-            CGRectGetHeight(toolbar_view.frame));
-  SetExpanded(false);
-  EXPECT_EQ(toolbar_view.collapsedToolbarHeight,
-            CGRectGetHeight(toolbar_view.frame));
-}
+INSTANTIATE_TEST_CASE_P(,
+                        ToolbarContainerViewControllerTest,
+                        ::testing::Range(kEmptyConfig,
+                                         kToolbarContainerConfigMax));
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h
new file mode 100644
index 0000000..356ba30
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_TOOLBAR_HEIGHT_RANGE_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_TOOLBAR_HEIGHT_RANGE_H_
+
+#import <QuartzCore/QuartzCore.h>
+
+namespace toolbar_container {
+
+// A simple container object used to store the height range for a collapsible
+// toolbar.
+class HeightRange {
+ public:
+  HeightRange() = default;
+  HeightRange(CGFloat min_height, CGFloat max_height);
+
+  // The max and min heights.
+  CGFloat min_height() const { return min_height_; }
+  CGFloat max_height() const { return max_height_; }
+
+  // Returns the delta between the max and min height.
+  CGFloat delta() const { return max_height_ - min_height_; }
+
+  // Returns the height value at the given interpolation value.
+  CGFloat GetInterpolatedHeight(CGFloat progress) const;
+
+  // Operators.
+  bool operator==(const HeightRange& other) const;
+  bool operator!=(const HeightRange& other) const;
+  HeightRange operator+(const HeightRange& other) const;
+  HeightRange operator-(const HeightRange& other) const;
+  HeightRange& operator+=(const HeightRange& other);
+  HeightRange& operator-=(const HeightRange& other);
+
+ private:
+  // The min and max heights.
+  CGFloat min_height_ = 0.0;
+  CGFloat max_height_ = 0.0;
+};
+
+}  // namespace toolbar_container
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_CONTAINER_TOOLBAR_HEIGHT_RANGE_H_
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm
new file mode 100644
index 0000000..309b92a
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h"
+
+#include <algorithm>
+
+#import "base/logging.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace toolbar_container {
+
+HeightRange::HeightRange(CGFloat min_height, CGFloat max_height)
+    : min_height_(min_height), max_height_(max_height) {}
+
+CGFloat HeightRange::GetInterpolatedHeight(CGFloat progress) const {
+  progress = std::min(static_cast<CGFloat>(1.0), progress);
+  progress = std::max(static_cast<CGFloat>(0.0), progress);
+  return min_height() + progress * delta();
+}
+
+bool HeightRange::operator==(const HeightRange& other) const {
+  return AreCGFloatsEqual(min_height(), other.min_height()) &&
+         AreCGFloatsEqual(max_height(), other.max_height());
+}
+
+bool HeightRange::operator!=(const HeightRange& other) const {
+  return !(*this == other);
+}
+
+HeightRange HeightRange::operator+(const HeightRange& other) const {
+  return HeightRange(min_height() + other.min_height(),
+                     max_height() + other.max_height());
+}
+
+HeightRange HeightRange::operator-(const HeightRange& other) const {
+  return HeightRange(min_height() - other.min_height(),
+                     max_height() - other.max_height());
+}
+
+HeightRange& HeightRange::operator+=(const HeightRange& other) {
+  min_height_ += other.min_height();
+  max_height_ += other.max_height();
+  return *this;
+}
+
+HeightRange& HeightRange::operator-=(const HeightRange& other) {
+  min_height_ -= other.min_height();
+  max_height_ -= other.max_height();
+  return *this;
+}
+
+}  // namespace toolbar_container
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_height_range_unittest.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range_unittest.mm
new file mode 100644
index 0000000..afe3719
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range_unittest.mm
@@ -0,0 +1,82 @@
+// 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 "ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h"
+
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using toolbar_container::HeightRange;
+
+// Test fixture for HeightRange.
+using HeightRangeTest = PlatformTest;
+
+// Tests that the default constructor creates a [0.0, 0.0] range.
+TEST_F(HeightRangeTest, DefaultConstructor) {
+  HeightRange range;
+  EXPECT_EQ(range.min_height(), 0.0);
+  EXPECT_EQ(range.max_height(), 0.0);
+}
+
+// Simple test for setting the height range values.
+TEST_F(HeightRangeTest, Creation) {
+  const CGFloat kMin = 50.0;
+  const CGFloat kMax = 100.0;
+  HeightRange range(kMin, kMax);
+  EXPECT_EQ(range.min_height(), kMin);
+  EXPECT_EQ(range.max_height(), kMax);
+  EXPECT_EQ(range.delta(), kMax - kMin);
+}
+
+// Test for getting interpolation values.
+TEST_F(HeightRangeTest, Interpolation) {
+  const CGFloat kMin = 0.0;
+  const CGFloat kMax = 100.0;
+  HeightRange range(kMin, kMax);
+  EXPECT_EQ(range.GetInterpolatedHeight(-0.5), 0.0);
+  EXPECT_EQ(range.GetInterpolatedHeight(0.0), 0.0);
+  EXPECT_EQ(range.GetInterpolatedHeight(0.25), 25.0);
+  EXPECT_EQ(range.GetInterpolatedHeight(0.5), 50.0);
+  EXPECT_EQ(range.GetInterpolatedHeight(0.75), 75.0);
+  EXPECT_EQ(range.GetInterpolatedHeight(1.0), 100.0);
+  EXPECT_EQ(range.GetInterpolatedHeight(1.5), 100.0);
+}
+
+// Test for comparing ranges.
+TEST_F(HeightRangeTest, Equality) {
+  const CGFloat kMin = 0.0;
+  const CGFloat kMax = 100.0;
+  HeightRange range(kMin, kMax);
+  HeightRange equal_range(kMin, kMax);
+  EXPECT_EQ(range, equal_range);
+  HeightRange unequal_range;
+  EXPECT_NE(range, unequal_range);
+}
+
+// Test for the + and - operators
+TEST_F(HeightRangeTest, AdditionSubtraction) {
+  const CGFloat kMin1 = 0.0;
+  const CGFloat kMax1 = 100.0;
+  HeightRange range1(kMin1, kMax1);
+  const CGFloat kMin2 = 80.0;
+  const CGFloat kMax2 = 110.0;
+  HeightRange range2(kMin2, kMax2);
+  HeightRange sum = range1 + range2;
+  EXPECT_EQ(sum, HeightRange(kMin1 + kMin2, kMax1 + kMax2));
+  EXPECT_EQ(sum - range2, range1);
+}
+
+// Test for the += and -= operators.
+TEST_F(HeightRangeTest, AssignAdditionSubtraction) {
+  const CGFloat kMin = 0.0;
+  const CGFloat kMax = 100.0;
+  HeightRange range(kMin, kMax);
+  range += range;
+  EXPECT_EQ(range, HeightRange(2.0 * kMin, 2.0 * kMax));
+  range -= HeightRange(kMin, kMax);
+  EXPECT_EQ(range, HeightRange(kMin, kMax));
+}
diff --git a/ios/web/navigation/error_retry_state_machine.h b/ios/web/navigation/error_retry_state_machine.h
index 79a25223..89a5602 100644
--- a/ios/web/navigation/error_retry_state_machine.h
+++ b/ios/web/navigation/error_retry_state_machine.h
@@ -84,6 +84,9 @@
   // Transitions the state machine to kDisplayingNativeErrorForFailedNavigation.
   void SetDisplayingNativeError();
 
+  // Transitions the state machine to kDisplayingWebErrorForFailedNavigation.
+  void SetDisplayingWebError();
+
   // Runs state transitions upon a failed provisional navigation.
   ErrorRetryCommand DidFailProvisionalNavigation(const GURL& web_view_url,
                                                  const GURL& error_url);
diff --git a/ios/web/navigation/error_retry_state_machine.mm b/ios/web/navigation/error_retry_state_machine.mm
index 8b7d6d3..e840af3 100644
--- a/ios/web/navigation/error_retry_state_machine.mm
+++ b/ios/web/navigation/error_retry_state_machine.mm
@@ -45,6 +45,23 @@
   state_ = ErrorRetryState::kDisplayingNativeErrorForFailedNavigation;
 }
 
+void ErrorRetryStateMachine::SetDisplayingWebError() {
+  // Web error is displayed in two scenarios:
+  // (1) Placeholder entry for network load error finished loading in web view.
+  //     This is the common case.
+  // (2) Retry of a previously failed load failed in SSL error. This can happen
+  //     when the first navigation failed in offline mode. SSL interstitial does
+  //     not normally trigger ErrorRetryStateMachine because the error page is
+  //     not to become part of the navigation history. This leaves the item
+  //     stuck in the transient kRetryFailedNavigationItem state. So for this
+  //     specific case, treat the SSL interstitial as a web error so that
+  //     error retry works as expected on subsequent back/forward navigations.
+  DCHECK(state_ == ErrorRetryState::kReadyToDisplayErrorForFailedNavigation ||
+         state_ == ErrorRetryState::kRetryFailedNavigationItem)
+      << "Unexpected error retry state: " << static_cast<int>(state_);
+  state_ = ErrorRetryState::kDisplayingWebErrorForFailedNavigation;
+}
+
 ErrorRetryCommand ErrorRetryStateMachine::DidFailProvisionalNavigation(
     const GURL& web_view_url,
     const GURL& error_url) {
diff --git a/ios/web/navigation/error_retry_state_machine_unittest.mm b/ios/web/navigation/error_retry_state_machine_unittest.mm
index ab698ac..5b371ca9 100644
--- a/ios/web/navigation/error_retry_state_machine_unittest.mm
+++ b/ios/web/navigation/error_retry_state_machine_unittest.mm
@@ -4,7 +4,9 @@
 
 #include "ios/web/navigation/error_retry_state_machine.h"
 
+#include "base/feature_list.h"
 #include "ios/web/navigation/wk_navigation_util.h"
+#include "ios/web/public/features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -41,10 +43,16 @@
   ASSERT_EQ(ErrorRetryState::kReadyToDisplayErrorForFailedNavigation,
             machine.state());
 
-  // Presents error in native view.
-  machine.SetDisplayingNativeError();
-  ASSERT_EQ(ErrorRetryState::kDisplayingNativeErrorForFailedNavigation,
-            machine.state());
+  // Presents error.
+  if (base::FeatureList::IsEnabled(web::features::kWebErrorPages)) {
+    machine.SetDisplayingWebError();
+    ASSERT_EQ(ErrorRetryState::kDisplayingWebErrorForFailedNavigation,
+              machine.state());
+  } else {
+    machine.SetDisplayingNativeError();
+    ASSERT_EQ(ErrorRetryState::kDisplayingNativeErrorForFailedNavigation,
+              machine.state());
+  }
 
   // Reload the failed navigation.
   ASSERT_EQ(ErrorRetryCommand::kRewriteWebViewURL,
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 1749c6063..2442187 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -3893,7 +3893,11 @@
         self.navigationManagerImpl, context->GetNavigationItemUniqueID());
     if (item && item->error_retry_state_machine().state() ==
                     web::ErrorRetryState::kRetryFailedNavigationItem) {
-      item->error_retry_state_machine().SetDisplayingNativeError();
+      if (base::FeatureList::IsEnabled(web::features::kWebErrorPages)) {
+        item->error_retry_state_machine().SetDisplayingWebError();
+      } else {
+        item->error_retry_state_machine().SetDisplayingNativeError();
+      }
     }
   }
 
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 85a892d..a4fe3de1 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -144,6 +144,7 @@
     "//media/filters:unit_tests",
     "//media/formats:unit_tests",
     "//media/gpu:unit_tests",
+    "//media/learning:unit_tests",
     "//media/mojo:unit_tests",
     "//media/muxers:unit_tests",
     "//media/renderers:unit_tests",
diff --git a/media/audio/PRESUBMIT.py b/media/audio/PRESUBMIT.py
deleted file mode 100644
index 401a6ae..0000000
--- a/media/audio/PRESUBMIT.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (c) 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for media/audio/.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, the WebGL 2.0 conformance tests) in addition
-  to the regular CQ try bots. This test suite is too large to run
-  against all Chromium commits, but should be run against changes
-  likely to affect these tests.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_optional_gpu_tests_rel',
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win_optional_gpu_tests_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 2fa1fa5a..7afd69d 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -223,6 +223,8 @@
     "routing_token_callback.h",
     "sample_rates.cc",
     "sample_rates.h",
+    "scoped_async_trace.cc",
+    "scoped_async_trace.h",
     "seekable_buffer.cc",
     "seekable_buffer.h",
     "serial_runner.cc",
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index f5b922f7..41bfa91 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -331,11 +331,7 @@
 // If enabled, use SurfaceLayer instead of VideoLayer for all playbacks that
 // aren't MediaStream.
 const base::Feature kUseSurfaceLayerForVideo{"UseSurfaceLayerForVideo",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Use SurfaceLayer instead of VideoLayer for MediaStream.
-const base::Feature kUseSurfaceLayerForVideoMS{
-    "UseSurfaceLayerForVideoMS", base::FEATURE_DISABLED_BY_DEFAULT};
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Use SurfaceLayer instead of VideoLayer when entering Picture-in-Picture mode.
 // Does nothing if UseSurfaceLayerForVideo is enabled.  Does not affect
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index f8c55e19..5bb7c850 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -138,7 +138,6 @@
 MEDIA_EXPORT extern const base::Feature kUseNewMediaCache;
 MEDIA_EXPORT extern const base::Feature kUseR16Texture;
 MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideo;
-MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideoMS;
 MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideoPIP;
 MEDIA_EXPORT extern const base::Feature kVaapiVP8Encoder;
 MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy;
diff --git a/media/base/scoped_async_trace.cc b/media/base/scoped_async_trace.cc
new file mode 100644
index 0000000..42f8935
--- /dev/null
+++ b/media/base/scoped_async_trace.cc
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/scoped_async_trace.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/trace_event/trace_event.h"
+
+namespace media {
+
+// static
+std::unique_ptr<ScopedAsyncTrace> ScopedAsyncTrace::CreateIfEnabled(
+    const char* category,
+    const char* name) {
+  bool enabled = false;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(category, &enabled);
+  return enabled ? base::WrapUnique(new ScopedAsyncTrace(category, name))
+                 : nullptr;
+}
+
+ScopedAsyncTrace::ScopedAsyncTrace(const char* category, const char* name)
+    : category_(category), name_(name) {
+  TRACE_EVENT_ASYNC_BEGIN0(category_, name_, this);
+}
+
+ScopedAsyncTrace::~ScopedAsyncTrace() {
+  TRACE_EVENT_ASYNC_END0(category_, name_, this);
+}
+
+}  // namespace media
diff --git a/media/base/scoped_async_trace.h b/media/base/scoped_async_trace.h
new file mode 100644
index 0000000..affac29c
--- /dev/null
+++ b/media/base/scoped_async_trace.h
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_SCOPED_ASYNC_TRACE_H_
+#define MEDIA_BASE_SCOPED_ASYNC_TRACE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+// Utility class that starts and stops an async trace event.  The intention is
+// that it it will be created somewhere to start the trace event, passed around
+// such as via unique_ptr argument in a callback, and eventually freed to end
+// the trace event.  This guarantees that it'll be closed, even if the callback
+// is destroyed without being run.
+class MEDIA_EXPORT ScopedAsyncTrace {
+ public:
+  // Create a ScopedAsyncTrace if tracing for |category| is enabled, else return
+  // nullptr.  |name| provided to the trace as the name(!).
+  // IMPORTANT: These strings must outlive |this|, since tracing needs it.  In
+  // other words, use literal strings only.  See trace_event_common.h .
+  static std::unique_ptr<ScopedAsyncTrace> CreateIfEnabled(const char* category,
+                                                           const char* name);
+
+  ~ScopedAsyncTrace();
+
+  // TODO(liberato): Add StepInto / StepPast.
+
+ private:
+  ScopedAsyncTrace(const char* category, const char* name);
+
+  const char* category_ = nullptr;
+  const char* name_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAsyncTrace);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_SCOPED_ASYNC_TRACE_H_
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index e62118c..fcc9016 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -311,13 +311,13 @@
   // with the MediaStream startup.
   const char* surface_layer_mode_name = "(unset)";
   switch (surface_layer_mode_) {
-    case WebMediaPlayerParams::SurfaceLayerMode::kAlways:
+    case SurfaceLayerMode::kAlways:
       surface_layer_mode_name = "kAlways";
       break;
-    case WebMediaPlayerParams::SurfaceLayerMode::kOnDemand:
+    case SurfaceLayerMode::kOnDemand:
       surface_layer_mode_name = "kOnDemand";
       break;
-    case WebMediaPlayerParams::SurfaceLayerMode::kNever:
+    case SurfaceLayerMode::kNever:
       surface_layer_mode_name = "kNever";
       break;
   }
@@ -1053,6 +1053,11 @@
   return ready_state_;
 }
 
+blink::WebMediaPlayer::SurfaceLayerMode
+WebMediaPlayerImpl::GetVideoSurfaceLayerMode() const {
+  return surface_layer_mode_;
+}
+
 blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
@@ -1699,7 +1704,7 @@
     }
 
     if (surface_layer_mode_ !=
-        WebMediaPlayerParams::SurfaceLayerMode::kAlways) {
+        blink::WebMediaPlayer::SurfaceLayerMode::kAlways) {
       DCHECK(!video_layer_);
       video_layer_ = cc::VideoLayer::Create(
           compositor_.get(),
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 94dc02b7..d025b81 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -186,6 +186,9 @@
   blink::WebMediaPlayer::NetworkState GetNetworkState() const override;
   blink::WebMediaPlayer::ReadyState GetReadyState() const override;
 
+  blink::WebMediaPlayer::SurfaceLayerMode GetVideoSurfaceLayerMode()
+      const override;
+
   blink::WebString GetErrorMessage() const override;
   bool DidLoadingProgress() override;
   bool WouldTaintOrigin() const override;
@@ -889,8 +892,8 @@
   bool embedded_media_experience_enabled_ = false;
 
   // When should we use SurfaceLayer for video?
-  WebMediaPlayerParams::SurfaceLayerMode surface_layer_mode_ =
-      WebMediaPlayerParams::SurfaceLayerMode::kNever;
+  blink::WebMediaPlayer::SurfaceLayerMode surface_layer_mode_ =
+      blink::WebMediaPlayer::SurfaceLayerMode::kNever;
 
   // Whether surface layer is currently in use to display frames.
   bool surface_layer_for_video_enabled_ = false;
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index fe57cf581..a4682a3 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -398,8 +398,8 @@
                        base::Unretained(this)),
         viz::TestContextProvider::Create(),
         base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo)
-            ? WebMediaPlayerParams::SurfaceLayerMode::kAlways
-            : WebMediaPlayerParams::SurfaceLayerMode::kNever);
+            ? blink::WebMediaPlayer::SurfaceLayerMode::kAlways
+            : blink::WebMediaPlayer::SurfaceLayerMode::kNever);
 
     auto compositor = std::make_unique<StrictMock<MockVideoFrameCompositor>>(
         params->video_frame_compositor_task_runner());
@@ -1449,6 +1449,9 @@
 
 // Tests delegate methods are called when Picture-in-Picture is triggered.
 TEST_F(WebMediaPlayerImplTest, PictureInPictureTriggerCallback) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitFromCommandLine(kUseSurfaceLayerForVideo.name, "");
+
   InitializeWebMediaPlayerImpl();
 
   EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer());
diff --git a/media/blink/webmediaplayer_params.cc b/media/blink/webmediaplayer_params.cc
index 3e57144..2538520 100644
--- a/media/blink/webmediaplayer_params.cc
+++ b/media/blink/webmediaplayer_params.cc
@@ -28,7 +28,7 @@
     mojom::MediaMetricsProviderPtr metrics_provider,
     CreateSurfaceLayerBridgeCB create_bridge_callback,
     scoped_refptr<viz::ContextProvider> context_provider,
-    SurfaceLayerMode use_surface_layer_for_video)
+    blink::WebMediaPlayer::SurfaceLayerMode use_surface_layer_for_video)
     : defer_load_cb_(defer_load_cb),
       audio_renderer_sink_(audio_renderer_sink),
       media_log_(std::move(media_log)),
diff --git a/media/blink/webmediaplayer_params.h b/media/blink/webmediaplayer_params.h
index 713c9e2..73b3d0d 100644
--- a/media/blink/webmediaplayer_params.h
+++ b/media/blink/webmediaplayer_params.h
@@ -22,6 +22,7 @@
 #include "media/blink/media_blink_export.h"
 #include "media/filters/context_3d.h"
 #include "media/mojo/interfaces/media_metrics_provider.mojom.h"
+#include "third_party/blink/public/platform/web_media_player.h"
 #include "third_party/blink/public/platform/web_video_frame_submitter.h"
 
 namespace base {
@@ -66,18 +67,6 @@
   // not the WebMediaPlayer!
   typedef base::Callback<int64_t(int64_t)> AdjustAllocatedMemoryCB;
 
-  // Describes when we use SurfaceLayer for video instead of VideoLayer.
-  enum class SurfaceLayerMode {
-    // Always use VideoLayer
-    kNever,
-
-    // Use SurfaceLayer only when we switch to Picture-in-Picture.
-    kOnDemand,
-
-    // Always use SurfaceLayer for video.
-    kAlways,
-  };
-
   // |defer_load_cb|, |audio_renderer_sink|, |compositor_task_runner|, and
   // |context_3d_cb| may be null.
   WebMediaPlayerParams(
@@ -98,7 +87,7 @@
       mojom::MediaMetricsProviderPtr metrics_provider,
       CreateSurfaceLayerBridgeCB bridge_callback,
       scoped_refptr<viz::ContextProvider> context_provider,
-      SurfaceLayerMode use_surface_layer_for_video);
+      blink::WebMediaPlayer::SurfaceLayerMode use_surface_layer_for_video);
 
   ~WebMediaPlayerParams();
 
@@ -165,7 +154,7 @@
     return context_provider_;
   }
 
-  SurfaceLayerMode use_surface_layer_for_video() const {
+  blink::WebMediaPlayer::SurfaceLayerMode use_surface_layer_for_video() const {
     return use_surface_layer_for_video_;
   }
 
@@ -188,7 +177,7 @@
   mojom::MediaMetricsProviderPtr metrics_provider_;
   CreateSurfaceLayerBridgeCB create_bridge_callback_;
   scoped_refptr<viz::ContextProvider> context_provider_;
-  SurfaceLayerMode use_surface_layer_for_video_;
+  blink::WebMediaPlayer::SurfaceLayerMode use_surface_layer_for_video_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(WebMediaPlayerParams);
 };
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 1d1e212..8645fe41 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
@@ -24,16 +24,21 @@
 #include "media/cdm/cdm_type_conversion.h"
 #include "media/cdm/library_cdm/cdm_host_proxy.h"
 #include "media/media_buildflags.h"
+#include "third_party/libaom/av1_buildflags.h"
 #include "third_party/libyuv/include/libyuv/planar_functions.h"
 
-#if BUILDFLAG(ENABLE_FFMPEG)
-#include "media/filters/ffmpeg_video_decoder.h"
-#endif
-
 #if BUILDFLAG(ENABLE_LIBVPX)
 #include "media/filters/vpx_video_decoder.h"
 #endif
 
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+#include "media/filters/aom_video_decoder.h"
+#endif
+
+#if BUILDFLAG(ENABLE_FFMPEG)
+#include "media/filters/ffmpeg_video_decoder.h"
+#endif
+
 namespace media {
 
 namespace {
@@ -296,6 +301,11 @@
     video_decoder.reset(new VpxVideoDecoder());
 #endif
 
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+  if (config.codec == cdm::kCodecAv1)
+    video_decoder.reset(new AomVideoDecoder(null_media_log.get()));
+#endif
+
 #if BUILDFLAG(ENABLE_FFMPEG)
   if (!video_decoder)
     video_decoder.reset(new FFmpegVideoDecoder(null_media_log.get()));
diff --git a/media/filters/PRESUBMIT.py b/media/filters/PRESUBMIT.py
deleted file mode 100644
index a46c3061..0000000
--- a/media/filters/PRESUBMIT.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (c) 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for media/filters/.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, the WebGL 2.0 conformance tests) in addition
-  to the regular CQ try bots. This test suite is too large to run
-  against all Chromium commits, but should be run against changes
-  likely to affect these tests.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_optional_gpu_tests_rel',
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win_optional_gpu_tests_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
diff --git a/media/gpu/PRESUBMIT.py b/media/gpu/PRESUBMIT.py
deleted file mode 100644
index c00d8905..0000000
--- a/media/gpu/PRESUBMIT.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (c) 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for media/gpu/.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, the WebGL 2.0 conformance tests) in addition
-  to the regular CQ try bots. This test suite is too large to run
-  against all Chromium commits, but should be run against changes
-  likely to affect these tests.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_optional_gpu_tests_rel',
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win_optional_gpu_tests_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
diff --git a/media/gpu/android/codec_image.cc b/media/gpu/android/codec_image.cc
index 30e71e3..5842a65 100644
--- a/media/gpu/android/codec_image.cc
+++ b/media/gpu/android/codec_image.cc
@@ -70,6 +70,7 @@
 void CodecImage::ReleaseTexImage(unsigned target) {}
 
 bool CodecImage::CopyTexImage(unsigned target) {
+  TRACE_EVENT0("media", "CodecImage::CopyTexImage");
   if (!texture_owner_ || target != GL_TEXTURE_EXTERNAL_OES)
     return false;
 
@@ -97,6 +98,7 @@
     const gfx::RectF& crop_rect,
     bool enable_blend,
     std::unique_ptr<gfx::GpuFence> gpu_fence) {
+  TRACE_EVENT0("media", "CodecImage::ScheduleOverlayPlane");
   if (texture_owner_) {
     DVLOG(1) << "Invalid call to ScheduleOverlayPlane; this image is "
                 "TextureOwner backed.";
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index 3e94d9a..5bb56c9 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -20,6 +20,7 @@
 #include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_switches.h"
+#include "media/base/scoped_async_trace.h"
 #include "media/base/video_codecs.h"
 #include "media/base/video_decoder_config.h"
 #include "media/base/video_frame.h"
@@ -154,12 +155,14 @@
 
 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
   DVLOG(2) << __func__;
+  TRACE_EVENT0("media", "MediaCodecVideoDecoder::~MediaCodecVideoDecoder");
   ReleaseCodec();
   codec_allocator_->StopThread(this);
 }
 
 void MediaCodecVideoDecoder::Destroy() {
   DVLOG(1) << __func__;
+  TRACE_EVENT0("media", "MediaCodecVideoDecoder::Destroy");
 
   if (media_crypto_context_) {
     // Cancel previously registered callback (if any).
@@ -310,6 +313,7 @@
 
 void MediaCodecVideoDecoder::StartLazyInit() {
   DVLOG(2) << __func__;
+  TRACE_EVENT0("media", "MediaCodecVideoDecoder::StartLazyInit");
   lazy_init_pending_ = false;
   codec_allocator_->StartThread(this);
 
@@ -333,6 +337,8 @@
 void MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized(
     scoped_refptr<TextureOwner> texture_owner) {
   DVLOG(2) << __func__;
+  TRACE_EVENT0("media",
+               "MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized");
   if (!texture_owner) {
     EnterTerminalState(State::kError);
     return;
@@ -376,6 +382,8 @@
   DVLOG(2) << __func__;
   DCHECK(state_ == State::kInitializing ||
          device_info_->IsSetOutputSurfaceSupported());
+  TRACE_EVENT1("media", "MediaCodecVideoDecoder::OnSurfaceChosen", "overlay",
+               overlay ? "yes" : "no");
 
   if (overlay) {
     overlay->AddSurfaceDestroyedCallback(
@@ -397,6 +405,7 @@
 void MediaCodecVideoDecoder::OnSurfaceDestroyed(AndroidOverlay* overlay) {
   DVLOG(2) << __func__;
   DCHECK_NE(state_, State::kInitializing);
+  TRACE_EVENT0("media", "MediaCodecVideoDecoder::OnSurfaceDestroyed");
 
   // If SetOutputSurface() is not supported we only ever observe destruction of
   // a single overlay so this must be the one we're using. In this case it's
@@ -733,12 +742,16 @@
           1);  // PRESUBMIT_IGNORE_UMA_MAX
 
   gfx::Rect visible_rect(output_buffer->size());
+  std::unique_ptr<ScopedAsyncTrace> async_trace =
+      ScopedAsyncTrace::CreateIfEnabled(
+          "media", "MediaCodecVideoDecoder::CreateVideoFrame");
   video_frame_factory_->CreateVideoFrame(
       std::move(output_buffer), presentation_time,
       GetNaturalSize(visible_rect, decoder_config_.GetPixelAspectRatio()),
       CreatePromotionHintCB(),
-      base::Bind(&MediaCodecVideoDecoder::ForwardVideoFrame,
-                 weak_factory_.GetWeakPtr(), reset_generation_));
+      base::BindOnce(&MediaCodecVideoDecoder::ForwardVideoFrame,
+                     weak_factory_.GetWeakPtr(), reset_generation_,
+                     std::move(async_trace)));
   return true;
 }
 
@@ -754,6 +767,7 @@
 
 void MediaCodecVideoDecoder::ForwardVideoFrame(
     int reset_generation,
+    std::unique_ptr<ScopedAsyncTrace> async_trace,
     const scoped_refptr<VideoFrame>& frame) {
   DVLOG(3) << __func__ << " : "
            << (frame ? frame->AsHumanReadableString() : "null");
@@ -780,6 +794,7 @@
 
 void MediaCodecVideoDecoder::StartDrainingCodec(DrainType drain_type) {
   DVLOG(2) << __func__;
+  TRACE_EVENT0("media", "MediaCodecVideoDecoder::StartDrainingCodec");
   DCHECK(pending_decodes_.empty());
   // It's okay if there's already a drain ongoing. We'll only enqueue an EOS if
   // the codec isn't already draining.
@@ -820,6 +835,7 @@
 
 void MediaCodecVideoDecoder::OnCodecDrained() {
   DVLOG(2) << __func__;
+  TRACE_EVENT0("media", "MediaCodecVideoDecoder::OnCodecDrained");
   DrainType drain_type = *drain_type_;
   drain_type_.reset();
 
diff --git a/media/gpu/android/media_codec_video_decoder.h b/media/gpu/android/media_codec_video_decoder.h
index f113d77..38cf622 100644
--- a/media/gpu/android/media_codec_video_decoder.h
+++ b/media/gpu/android/media_codec_video_decoder.h
@@ -24,6 +24,8 @@
 
 namespace media {
 
+class ScopedAsyncTrace;
+
 struct PendingDecode {
   static PendingDecode CreateEos();
   PendingDecode(scoped_refptr<DecoderBuffer> buffer,
@@ -166,8 +168,10 @@
   void RunEosDecodeCb(int reset_generation);
 
   // Forwards |frame| via |output_cb_| if |reset_generation| matches
-  // |reset_generation_|.
+  // |reset_generation_|.  |async_trace| is the (optional) scoped trace that
+  // started when we dequeued the corresponding output buffer.
   void ForwardVideoFrame(int reset_generation,
+                         std::unique_ptr<ScopedAsyncTrace> async_trace,
                          const scoped_refptr<VideoFrame>& frame);
 
   // Starts draining the codec by queuing an EOS if required. It skips the drain
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index 121ec92f9..1f4415bed 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -63,14 +63,13 @@
                     bool use_texture_owner_as_overlay,
                     InitCb init_cb));
   MOCK_METHOD1(MockSetSurfaceBundle, void(scoped_refptr<AVDASurfaceBundle>));
-  MOCK_METHOD6(
+  MOCK_METHOD5(
       MockCreateVideoFrame,
       void(CodecOutputBuffer* raw_output_buffer,
            scoped_refptr<TextureOwner> texture_owner,
            base::TimeDelta timestamp,
            gfx::Size natural_size,
-           PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
-           VideoDecoder::OutputCB output_cb));
+           PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb));
   MOCK_METHOD1(MockRunAfterPendingVideoFrames,
                void(base::OnceClosure* closure));
   MOCK_METHOD0(CancelPendingCallbacks, void());
@@ -91,11 +90,11 @@
       base::TimeDelta timestamp,
       gfx::Size natural_size,
       PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
-      VideoDecoder::OutputCB output_cb) override {
+      VideoFrameFactory::OnceOutputCb output_cb) override {
     MockCreateVideoFrame(output_buffer.get(), texture_owner_, timestamp,
-                         natural_size, promotion_hint_cb, output_cb);
+                         natural_size, promotion_hint_cb);
     last_output_buffer_ = std::move(output_buffer);
-    output_cb.Run(VideoFrame::CreateBlackFrame(gfx::Size(10, 10)));
+    std::move(output_cb).Run(VideoFrame::CreateBlackFrame(gfx::Size(10, 10)));
   }
 
   void RunAfterPendingVideoFrames(base::OnceClosure closure) override {
@@ -924,7 +923,7 @@
   // Produce one output.
   codec->AcceptOneInput();
   codec->ProduceOneOutput();
-  EXPECT_CALL(*video_frame_factory_, MockCreateVideoFrame(_, _, _, _, _, _));
+  EXPECT_CALL(*video_frame_factory_, MockCreateVideoFrame(_, _, _, _, _));
   PumpCodec();
   base::RunLoop().RunUntilIdle();
 
diff --git a/media/gpu/android/video_frame_factory.h b/media/gpu/android/video_frame_factory.h
index c5120fd..b3e87cb 100644
--- a/media/gpu/android/video_frame_factory.h
+++ b/media/gpu/android/video_frame_factory.h
@@ -32,6 +32,8 @@
  public:
   using GetStubCb = base::Callback<gpu::CommandBufferStub*()>;
   using InitCb = base::RepeatingCallback<void(scoped_refptr<TextureOwner>)>;
+  using OnceOutputCb =
+      base::OnceCallback<void(const scoped_refptr<VideoFrame>&)>;
 
   VideoFrameFactory() = default;
   virtual ~VideoFrameFactory() = default;
@@ -52,16 +54,14 @@
   virtual void SetSurfaceBundle(
       scoped_refptr<AVDASurfaceBundle> surface_bundle) = 0;
 
-  // Creates a new VideoFrame backed by |output_buffer| and |texture_owner|.
-  // |texture_owner| may be null if the buffer is backed by an overlay
-  // instead. Runs |output_cb| on the calling sequence to return the frame.
-  // TODO(liberato): update the comment.
+  // Creates a new VideoFrame backed by |output_buffer|.  Runs |output_cb| on
+  // the calling sequence to return the frame.
   virtual void CreateVideoFrame(
       std::unique_ptr<CodecOutputBuffer> output_buffer,
       base::TimeDelta timestamp,
       gfx::Size natural_size,
       PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
-      VideoDecoder::OutputCB output_cb) = 0;
+      OnceOutputCb output_cb) = 0;
 
   // Runs |closure| on the calling sequence after all previous
   // CreateVideoFrame() calls have completed.
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index b9639db..083fc296 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -100,15 +100,16 @@
     base::TimeDelta timestamp,
     gfx::Size natural_size,
     PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
-    VideoDecoder::OutputCB output_cb) {
+    OnceOutputCb output_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   gpu_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&GpuVideoFrameFactory::CreateVideoFrame,
-                 base::Unretained(gpu_video_frame_factory_.get()),
-                 base::Passed(&output_buffer), texture_owner_, timestamp,
-                 natural_size, std::move(promotion_hint_cb),
-                 std::move(output_cb), base::ThreadTaskRunnerHandle::Get()));
+      base::BindOnce(&GpuVideoFrameFactory::CreateVideoFrame,
+                     base::Unretained(gpu_video_frame_factory_.get()),
+                     base::Passed(&output_buffer), texture_owner_, timestamp,
+                     natural_size, std::move(promotion_hint_cb),
+                     std::move(output_cb),
+                     base::ThreadTaskRunnerHandle::Get()));
 }
 
 void VideoFrameFactoryImpl::RunAfterPendingVideoFrames(
@@ -153,7 +154,7 @@
     base::TimeDelta timestamp,
     gfx::Size natural_size,
     PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
-    VideoDecoder::OutputCB output_cb,
+    VideoFrameFactory::OnceOutputCb output_cb,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   scoped_refptr<VideoFrame> frame;
@@ -163,6 +164,7 @@
                            timestamp, natural_size,
                            std::move(promotion_hint_cb), &frame, &texture,
                            &codec_image);
+  TRACE_EVENT0("media", "GpuVideoFrameFactory::CreateVideoFrame");
   if (!frame || !texture)
     return;
 
@@ -199,7 +201,8 @@
   auto release_cb = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
       BindToCurrentLoop(std::move(drop_texture_ref)), gpu::SyncToken());
   frame->SetReleaseMailboxCB(std::move(release_cb));
-  task_runner->PostTask(FROM_HERE, base::BindOnce(output_cb, std::move(frame)));
+  task_runner->PostTask(FROM_HERE,
+                        base::BindOnce(std::move(output_cb), std::move(frame)));
 }
 
 void GpuVideoFrameFactory::CreateVideoFrameInternal(
diff --git a/media/gpu/android/video_frame_factory_impl.h b/media/gpu/android/video_frame_factory_impl.h
index db02d0e..f93760f 100644
--- a/media/gpu/android/video_frame_factory_impl.h
+++ b/media/gpu/android/video_frame_factory_impl.h
@@ -48,7 +48,7 @@
       base::TimeDelta timestamp,
       gfx::Size natural_size,
       PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
-      VideoDecoder::OutputCB output_cb) override;
+      OnceOutputCb output_cb) override;
   void RunAfterPendingVideoFrames(base::OnceClosure closure) override;
 
  private:
@@ -84,7 +84,7 @@
       base::TimeDelta timestamp,
       gfx::Size natural_size,
       PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
-      VideoDecoder::OutputCB output_cb,
+      VideoFrameFactory::OnceOutputCb output_cb,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // Set our image group.  Must be called before the first call to
diff --git a/media/learning/BUILD.gn b/media/learning/BUILD.gn
new file mode 100644
index 0000000..2300291
--- /dev/null
+++ b/media/learning/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("learning") {
+  # Do not expand the visibility here without double-checking with OWNERS, this
+  # is a roll-up target which is part of the //media component. Most other DEPs
+  # should be using //media and not directly DEP this roll-up target.
+  visibility = [ "//media" ]
+
+  sources = [
+    "instance.cc",
+    "instance.h",
+    "learner.h",
+    "learner_factory.h",
+    "learning_task.cc",
+    "learning_task.h",
+    "value.cc",
+    "value.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//media/base",
+  ]
+
+  configs += [ "//media:subcomponent_config" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "value_unittest.cc",
+  ]
+
+  deps = [
+    "//base/test:test_support",
+    "//media:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/media/learning/README.md b/media/learning/README.md
new file mode 100644
index 0000000..6a87dc43
--- /dev/null
+++ b/media/learning/README.md
@@ -0,0 +1,66 @@
+# Media Local Learning Framework
+
+This directory contains code to support media's local learning experiment.
+It provides lightweight learning algorithms that can be trained on the user's
+local device to tailor media performance / behavior to match the user's usage.
+
+## Terms
+
+**Feature vector** - How we describe the "state of the world" to the learner.
+  For example, we might describe a video using the features {width, height,
+  format, frame rate}.
+
+**Target** - The output value we'd like to predict, given some features.  We
+  might want to know a boolean representing "will playback be smooth?".
+
+**Training example** - A tuple {Feature vector, Target value} that demonstrates
+  the desired target for some feature vector. The learning algorithm collects
+  examples, and tries to generalize them to unseen features.
+
+**Classification** - Class of problems for which the target value is nominal.
+  For example, predicting the expected color from a set of five colors is
+  a classification task.  The key idea is that the target values are unordered.
+
+**Regression** - Class of problems for which the target value is numeric.  For
+  example, predicting how tall a plant will grow is regression.
+
+**Model** - A class of functions that relates features (inputs) to target values
+  (outputs).  For example, a linear model relates them as:
+  ```
+  target = weight1 * feature1 + weight2 * feature2 + ...
+  ```
+  Note that the weights aren't known in advance; we'll choose them as part of
+  the training process based on the training examples.
+
+**Model parameters** - The missing values in our model that the learning
+  learning algorithm tries to figure out based on the training data.  In our
+  linear model, we'd need to know `weight1` and `weight2`.
+
+**Learning task** - A problem we're trying to solve.  For example, "Will this
+  video element be played before it's destroyed?"
+
+## Classes
+
+There are several classes that we define here.  While more detail can generally
+be found in the header for the class, an overview of the main ones is:
+
+**Learner** - Base class for a thing that knows how to convert training data
+  into a fully trained model (model + parameters).  For example, we might have
+  a Learner subclass that chooses the parameters for a Naive Bayes model.
+  Similarly, we might have a Learner that trains a linear regression model.
+
+**LearningTask** - Description of a task, and also, because it's convenient,
+  a choice of model that will be used to learn it.  It contains:
+
+    * name
+    * description of features (name, nominal vs numeric, etc.)
+    * description of the target value
+    * description / parameters of the learning model to be used
+
+**Instance** - Set of feature values.
+
+**Value** - Representation of a number or (hashed) string.
+
+## Models
+
+All of our models are supervised.
diff --git a/media/learning/instance.cc b/media/learning/instance.cc
new file mode 100644
index 0000000..bbc9855c
--- /dev/null
+++ b/media/learning/instance.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/learning/instance.h"
+
+namespace media {
+namespace learning {
+
+Instance::Instance() = default;
+Instance::~Instance() = default;
+Instance::Instance(Instance&& rhs) {
+  features = std::move(rhs.features);
+}
+
+std::ostream& operator<<(std::ostream& out, const Instance& instance) {
+  for (const auto& feature : instance.features)
+    out << " " << feature;
+
+  return out;
+}
+
+}  // namespace learning
+}  // namespace media
diff --git a/media/learning/instance.h b/media/learning/instance.h
new file mode 100644
index 0000000..2a30770
--- /dev/null
+++ b/media/learning/instance.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_LEARNING_INSTANCE_H_
+#define MEDIA_LEARNING_INSTANCE_H_
+
+#include <ostream>
+#include <vector>
+
+#include "base/macros.h"
+#include "media/base/media_export.h"
+#include "media/learning/value.h"
+
+namespace media {
+namespace learning {
+
+// One instance == group of feature values.
+struct MEDIA_EXPORT Instance {
+  Instance();
+  ~Instance();
+  // Declare a no-exception move constructor so that std::vector will use it.
+  Instance(Instance&& rhs) noexcept;
+
+  // It's up to you to add the right number of features to match the learner
+  // description.  Otherwise, the learner will ignore (training) or lie to you
+  // (inference), silently.
+  std::vector<FeatureValue> features;
+
+  DISALLOW_COPY_AND_ASSIGN(Instance);
+};
+
+MEDIA_EXPORT std::ostream& operator<<(std::ostream& out,
+                                      const Instance& instance);
+
+}  // namespace learning
+}  // namespace media
+
+#endif  // MEDIA_LEARNING_INSTANCE_H_
diff --git a/media/learning/learner.h b/media/learning/learner.h
new file mode 100644
index 0000000..bff1cbb
--- /dev/null
+++ b/media/learning/learner.h
@@ -0,0 +1,32 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_LEARNING_LEARNER_H_
+#define MEDIA_LEARNING_LEARNER_H_
+
+#include "base/values.h"
+#include "media/base/media_export.h"
+#include "media/learning/instance.h"
+
+namespace media {
+namespace learning {
+
+// Base class for a thing that takes examples of the form {features, target},
+// and trains a model to predict the target given the features.  The target may
+// be either nominal (classification) or numeric (regression), though this must
+// be chosen in advance when creating the learner via LearnerFactory.
+class MEDIA_EXPORT Learner {
+ public:
+  virtual ~Learner() = default;
+
+  // Tell the learner that |instance| has been observed with the target value
+  // |target| during training.
+  virtual void AddExample(const Instance& instance,
+                          const TargetValue& target) = 0;
+};
+
+}  // namespace learning
+}  // namespace media
+
+#endif  // MEDIA_LEARNING_LEARNER_H_
diff --git a/media/learning/learner_factory.h b/media/learning/learner_factory.h
new file mode 100644
index 0000000..fc30f31f
--- /dev/null
+++ b/media/learning/learner_factory.h
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_LEARNING_LEARNER_FACTORY_H_
+#define MEDIA_LEARNING_LEARNER_FACTORY_H_
+
+#include <string>
+
+#include "media/base/media_export.h"
+#include "media/learning/learing_task.h"
+#include "media/learning/learner.h"
+
+namespace media {
+namespace learning {
+
+// Factory class for learner instances.
+class MEDIA_EXPORT LearnerFactory {
+ public:
+  virtual ~LearnerFactory() = default;
+
+  // Provide a learner that matches |task|.
+  virtual std::unique_ptr<Learner> CreateLearner(const LearningTask& task) = 0;
+};
+
+}  // namespace learning
+}  // namespace media
+
+#endif  // MEDIA_LEARNING_LEARNER_FACTORY_H_
diff --git a/media/learning/learning_task.cc b/media/learning/learning_task.cc
new file mode 100644
index 0000000..78e43d23
--- /dev/null
+++ b/media/learning/learning_task.cc
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/learning/learning_task.h"
+
+namespace media {
+namespace learning {
+
+LearningTask::LearningTask() = default;
+LearningTask::LearningTask(const LearningTask&) = default;
+LearningTask::~LearningTask() = default;
+
+}  // namespace learning
+}  // namespace media
diff --git a/media/learning/learning_task.h b/media/learning/learning_task.h
new file mode 100644
index 0000000..2fe086c
--- /dev/null
+++ b/media/learning/learning_task.h
@@ -0,0 +1,96 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_LEARNING_LEARNING_TASK_H_
+#define MEDIA_LEARNING_LEARNING_TASK_H_
+
+#include <initializer_list>
+#include <string>
+
+#include "media/base/media_export.h"
+#include "media/learning/instance.h"
+
+namespace media {
+namespace learning {
+
+// Description of a learning task.  This includes both the description of the
+// inputs (features) and output (target value), plus a choice of the model and
+// parameters for learning.
+// TODO(liberato): Consider separating the task from the choice of model.
+struct MEDIA_EXPORT LearningTask {
+  // Not all models support all feature / target descriptions.  For example,
+  // NaiveBayes requires kUnordered features.  Similarly, kLogLinear doesn't
+  // support kUnordered features or targets.  kRandomForest might support more
+  // combination of orderings and types.
+  //
+  // Also note that not all of these are implemented yet.
+  enum class Model {
+    kMostCommonTarget,
+    kNaiveBayes,
+    kRandomForest,
+    kLogLinear,
+  };
+
+  enum class Ordering {
+    // Values are not ordered; nearby values might have wildly different
+    // meanings.  For example, two ints that are computed by taking the hash
+    // of a string are unordered; it's categorical data.  Values of type DOUBLE
+    // should almost certainly not be kUnordered; discretize them in some way
+    // if you really want to make discrete, unordered buckets out of them.
+    kUnordered,
+
+    // Values may be interpreted as being in numeric order.  For example, two
+    // ints that represent the number of elapsed milliseconds are numerically
+    // ordered in a meaningful way.
+    kNumeric,
+  };
+
+  enum class PrivacyMode {
+    // Value represents private information, such as a URL that was visited by
+    // the user.
+    kPrivate,
+
+    // Value does not represent private information, such as video width.
+    kPublic,
+  };
+
+  // Description of how a Value should be interpreted.
+  struct ValueDescription {
+    // Name of this value, such as "source_url" or "width".
+    std::string name;
+
+    // Is this value nominal or not?
+    Ordering ordering = Ordering::kUnordered;
+
+    // Should this value be treated as being private?
+    PrivacyMode privacy_mode = PrivacyMode::kPublic;
+  };
+
+  LearningTask();
+  LearningTask(const std::string& name,
+               Model model,
+               std::initializer_list<ValueDescription> feature_init_list,
+               ValueDescription target_description);
+  LearningTask(const LearningTask&);
+  ~LearningTask();
+
+  // Unique name for this learner.
+  std::string name;
+
+  Model model = Model::kMostCommonTarget;
+
+  std::vector<ValueDescription> feature_descriptions;
+
+  // Note that kUnordered targets indicate classification, while kOrdered
+  // targes indicate regression.
+  ValueDescription target_description;
+
+  // TODO(liberato): add training parameters, like smoothing constants.  It's
+  // okay if some of these are model-specific.
+};
+
+}  // namespace learning
+}  // namespace media
+
+#endif  // MEDIA_LEARNING_LEARNING_TASK_H_
diff --git a/media/learning/value.cc b/media/learning/value.cc
new file mode 100644
index 0000000..88e1033
--- /dev/null
+++ b/media/learning/value.cc
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/learning/value.h"
+
+#include "base/hash.h"
+
+namespace media {
+namespace learning {
+
+Value::Value(int x) : value_(x) {}
+Value::Value(const char* x) {
+  // std::hash would be nice, but it can (and does) change values between
+  // different instances of the class.  In other words, Value("foo") !=
+  // Value("foo") necessarily.
+  if (x)
+    value_ = base::PersistentHash(x, strlen(x));
+}
+
+Value::Value(const std::string& x) : value_(base::PersistentHash(x)) {}
+
+Value::Value(const Value& other) : value_(other.value_) {}
+
+bool Value::operator==(const Value& rhs) const {
+  return value_ == rhs.value_;
+}
+
+bool Value::operator!=(const Value& rhs) const {
+  return value_ != rhs.value_;
+}
+
+bool Value::operator<(const Value& rhs) const {
+  return value_ < rhs.value_;
+}
+
+std::ostream& operator<<(std::ostream& out, const Value& value) {
+  return out << value.value_;
+}
+
+}  // namespace learning
+}  // namespace media
diff --git a/media/learning/value.h b/media/learning/value.h
new file mode 100644
index 0000000..fc49f47
--- /dev/null
+++ b/media/learning/value.h
@@ -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.
+
+#ifndef MEDIA_LEARNING_VALUE_H_
+#define MEDIA_LEARNING_VALUE_H_
+
+#include <cstdint>
+#include <ostream>
+#include <string>
+
+#include "media/base/media_export.h"
+
+namespace media {
+namespace learning {
+
+// Lightweight, copyable value for features and labels.
+// Strings are hashed into ints in an implementation-specific way, so don't
+// count on ordering between them.  See LearningTask for more info about nominal
+// versus numerical values.
+//
+// For numeric values, ==, !=, > operators behave as one would expect.
+//
+// For strings, only == and != are guaranteed to be meaningful.
+class MEDIA_EXPORT Value {
+ public:
+  explicit Value(int x);
+  explicit Value(const char* x);
+  explicit Value(const std::string& x);
+
+  Value(const Value& other);
+
+  bool operator==(const Value& rhs) const;
+  bool operator!=(const Value& rhs) const;
+  bool operator<(const Value& rhs) const;
+
+ private:
+  int64_t value_ = 0;
+
+  friend MEDIA_EXPORT std::ostream& operator<<(std::ostream& out,
+                                               const Value& value);
+
+  // Copy and assign are fine.
+};
+
+// Just to make it clearer what type of value we mean in context.
+using FeatureValue = Value;
+using TargetValue = Value;
+
+MEDIA_EXPORT std::ostream& operator<<(std::ostream& out, const Value& value);
+
+}  // namespace learning
+}  // namespace media
+
+#endif  // MEDIA_LEARNING_VALUE_H_
diff --git a/media/learning/value_unittest.cc b/media/learning/value_unittest.cc
new file mode 100644
index 0000000..054d419c
--- /dev/null
+++ b/media/learning/value_unittest.cc
@@ -0,0 +1,48 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/learning/value.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+namespace learning {
+
+class LearnerValueTest : public testing::Test {};
+
+TEST_F(LearnerValueTest, EqualStringsCompareAsEqual) {
+  const char* value = "value";
+  Value v1(value);
+  Value v2(value);
+  EXPECT_TRUE(v1 == v2);
+}
+
+TEST_F(LearnerValueTest, UnequalStringsDoNotCompareAsEqual) {
+  Value v1("value");
+  Value v2("nonvalue");
+  EXPECT_TRUE(v1 != v2);
+}
+
+TEST_F(LearnerValueTest, ConstCharAndStdStringsCompareAsEqual) {
+  const char* value_as_char = "value";
+  std::string value_as_str(value_as_char);
+  Value v1(value_as_char);
+  Value v2(value_as_str);
+  EXPECT_TRUE(v1 == v2);
+}
+
+TEST_F(LearnerValueTest, IntsCompareCorrectly) {
+  const int i1 = 12345;
+  const int i2 = 67890;
+  Value v1(i1);
+  Value v2(i1);
+  Value v3(i2);
+  EXPECT_TRUE(v1 == v2);
+  EXPECT_TRUE(v1 != v3);
+  EXPECT_TRUE(v1 < v3);
+  EXPECT_FALSE(v3 < v1);
+}
+
+}  // namespace learning
+}  // namespace media
diff --git a/media/media_options.gni b/media/media_options.gni
index 46eaa581..fed7f8c 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -21,6 +21,7 @@
   "//media/device_monitors",
   "//media/filters",
   "//media/formats",
+  "//media/learning",
   "//media/muxers",
   "//media/renderers",
   "//media/video",
diff --git a/media/test/data/README.md b/media/test/data/README.md
index 6bf32c7..f789ab7 100644
--- a/media/test/data/README.md
+++ b/media/test/data/README.md
@@ -125,7 +125,6 @@
   --lag-in-frames=0 --test-decode=fatal --target-bitrate=50 \
   -o bear-av1-640x480.webm
 ```
-
 ### Alpha Channel
 
 #### bear-vp8a.webm
@@ -404,6 +403,21 @@
 third_party/WebKit/LayoutTests/media/resources/frame_size_change.webm encrypted
 using key ID [1] and key [2].
 
+### AV1
+
+#### bear-av1-cenc.mp4
+Encrypted version of bear-av1.mp4. Encrypted by [Shaka Packager] built locally
+at commit 53aa775ea488c0ffd3a2e1cb78ad000154e414e1 using key ID [1] and key [2].
+```
+packager in=bear-av1.mp4,stream=video,output=bear-av1-cenc.mp4
+         --enable_raw_key_encryption --protection_scheme cenc --clear_lead 0
+         --keys label=:key_id=30313233343536373839303132333435:key=ebdd62f16814d27b68ef122afce4ae3c
+         --pssh 000000327073736800000000EDEF8BA979D64ACEA3C827DCD51D21ED000000121210303132333435363738393031323334350000003470737368010000001077EFECC0B24D02ACE33C1E52E2FB4B000000013031323334353637383930313233343500000000
+```
+
+#### bear-av1-cenc.webm
+Same as bear-av1-cenc.mp4, except that the output name is bear-av1-cenc.webm.
+
 ### Encryption Scheme Test
 
 * bear-640x360-v_frag-cenc.mp4
diff --git a/media/test/data/bear-av1-cenc.mp4 b/media/test/data/bear-av1-cenc.mp4
new file mode 100644
index 0000000..9510b31
--- /dev/null
+++ b/media/test/data/bear-av1-cenc.mp4
Binary files differ
diff --git a/media/test/data/bear-av1-cenc.webm b/media/test/data/bear-av1-cenc.webm
new file mode 100644
index 0000000..6b42c8fb
--- /dev/null
+++ b/media/test/data/bear-av1-cenc.webm
Binary files differ
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 7424b71e..22d5961 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1365,6 +1365,8 @@
       "third_party/quic/core/frames/quic_window_update_frame.h",
       "third_party/quic/core/http/http_decoder.cc",
       "third_party/quic/core/http/http_decoder.h",
+      "third_party/quic/core/http/http_encoder.cc",
+      "third_party/quic/core/http/http_encoder.h",
       "third_party/quic/core/http/http_frames.h",
       "third_party/quic/core/http/quic_client_promised_info.cc",
       "third_party/quic/core/http/quic_client_promised_info.h",
@@ -1396,6 +1398,8 @@
       "third_party/quic/core/qpack/qpack_encoder_stream_sender.h",
       "third_party/quic/core/qpack/qpack_header_table.cc",
       "third_party/quic/core/qpack/qpack_header_table.h",
+      "third_party/quic/core/qpack/qpack_static_table.cc",
+      "third_party/quic/core/qpack/qpack_static_table.h",
       "third_party/quic/core/quic_ack_listener_interface.cc",
       "third_party/quic/core/quic_ack_listener_interface.h",
       "third_party/quic/core/quic_alarm.cc",
@@ -5010,6 +5014,7 @@
     "third_party/quic/core/crypto/transport_parameters_test.cc",
     "third_party/quic/core/frames/quic_frames_test.cc",
     "third_party/quic/core/http/http_decoder_test.cc",
+    "third_party/quic/core/http/http_encoder_test.cc",
     "third_party/quic/core/http/quic_client_promised_info_test.cc",
     "third_party/quic/core/http/quic_client_push_promise_index_test.cc",
     "third_party/quic/core/http/quic_header_list_test.cc",
@@ -5019,6 +5024,7 @@
     "third_party/quic/core/qpack/qpack_encoder_stream_receiver_test.cc",
     "third_party/quic/core/qpack/qpack_encoder_stream_sender_test.cc",
     "third_party/quic/core/qpack/qpack_encoder_test.cc",
+    "third_party/quic/core/qpack/qpack_static_table_test.cc",
     "third_party/quic/core/quic_alarm_test.cc",
     "third_party/quic/core/quic_arena_scoped_ptr_test.cc",
     "third_party/quic/core/quic_bandwidth_test.cc",
diff --git a/net/dns/dns_query.cc b/net/dns/dns_query.cc
index a5e9726..da8c36d 100644
--- a/net/dns/dns_query.cc
+++ b/net/dns/dns_query.cc
@@ -5,7 +5,9 @@
 #include "net/dns/dns_query.h"
 
 #include "base/big_endian.h"
+#include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/sys_byteorder.h"
 #include "net/base/io_buffer.h"
 #include "net/dns/dns_protocol.h"
@@ -84,15 +86,16 @@
   return base::WrapUnique(new DnsQuery(*this, id));
 }
 
-bool DnsQuery::Parse() {
+bool DnsQuery::Parse(size_t valid_bytes) {
   if (io_buffer_ == nullptr || io_buffer_->data() == nullptr) {
     return false;
   }
+  CHECK(valid_bytes <= base::checked_cast<size_t>(io_buffer_->size()));
   // We should only parse the query once if the query is constructed from a raw
   // buffer. If we have constructed the query from data or the query is already
   // parsed after constructed from a raw buffer, |header_| is not null.
   DCHECK(header_ == nullptr);
-  base::BigEndianReader reader(io_buffer_->data(), io_buffer_->size());
+  base::BigEndianReader reader(io_buffer_->data(), valid_bytes);
   dns_protocol::Header header;
   if (!ReadHeader(&reader, &header)) {
     return false;
diff --git a/net/dns/dns_query.h b/net/dns/dns_query.h
index 8e77ac5..981cc9e8 100644
--- a/net/dns/dns_query.h
+++ b/net/dns/dns_query.h
@@ -54,7 +54,13 @@
   // Returns true and populates the query if the internally stored raw packet
   // can be parsed. This should only be called when DnsQuery is constructed from
   // the raw buffer.
-  bool Parse();
+  // |valid_bytes| indicates the number of initialized bytes in the raw buffer.
+  // E.g. if the buffer holds a packet received from the network, the buffer may
+  // be allocated with the maximum size of a UDP packet, but |valid_bytes|
+  // indicates the number of bytes actually received from the network. If the
+  // parsing requires reading more than the number of initialized bytes, this
+  // method fails and returns false.
+  bool Parse(size_t valid_bytes);
 
   // DnsQuery field accessors.
   uint16_t id() const;
diff --git a/net/dns/dns_query_parse_fuzzer.cc b/net/dns/dns_query_parse_fuzzer.cc
index f936218..c524f62 100644
--- a/net/dns/dns_query_parse_fuzzer.cc
+++ b/net/dns/dns_query_parse_fuzzer.cc
@@ -15,6 +15,6 @@
   auto packet = base::MakeRefCounted<net::IOBufferWithSize>(size);
   memcpy(packet->data(), data, size);
   auto out = std::make_unique<net::DnsQuery>(packet);
-  out->Parse();
+  out->Parse(size);
   return 0;
 }
diff --git a/net/dns/dns_query_unittest.cc b/net/dns/dns_query_unittest.cc
index 0638bb1..0cbb7a4 100644
--- a/net/dns/dns_query_unittest.cc
+++ b/net/dns/dns_query_unittest.cc
@@ -27,7 +27,7 @@
   auto packet = base::MakeRefCounted<IOBufferWithSize>(length);
   memcpy(packet->data(), data, length);
   out->reset(new DnsQuery(packet));
-  return (*out)->Parse();
+  return (*out)->Parse(length);
 }
 
 // This includes \0 at the end.
diff --git a/net/dns/dns_response.cc b/net/dns/dns_response.cc
index 7177dcaf..2b2c456 100644
--- a/net/dns/dns_response.cc
+++ b/net/dns/dns_response.cc
@@ -9,6 +9,8 @@
 #include <vector>
 
 #include "base/big_endian.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/sys_byteorder.h"
 #include "net/base/address_list.h"
@@ -227,6 +229,9 @@
     io_buffer_size_ = 0;
     return;
   }
+  // Ensure we don't have any remaining uninitialized bytes in the buffer.
+  DCHECK(!writer.remaining());
+  memset(writer.ptr(), 0, writer.remaining());
   if (has_query) {
     InitParse(io_buffer_size_, query.value());
   } else {
@@ -257,7 +262,7 @@
 
 bool DnsResponse::InitParse(size_t nbytes, const DnsQuery& query) {
   // Response includes query, it should be at least that size.
-  if (nbytes < static_cast<size_t>(query.io_buffer()->size()) ||
+  if (nbytes < base::checked_cast<size_t>(query.io_buffer()->size()) ||
       nbytes > io_buffer_size_) {
     return false;
   }
diff --git a/net/dns/dns_response_fuzzer.cc b/net/dns/dns_response_fuzzer.cc
index c53e179a..a2020a1 100644
--- a/net/dns/dns_response_fuzzer.cc
+++ b/net/dns/dns_response_fuzzer.cc
@@ -18,7 +18,7 @@
   memcpy(packet->data(), data, size);
   base::Optional<net::DnsQuery> query;
   query.emplace(packet);
-  if (!query->Parse()) {
+  if (!query->Parse(size)) {
     return 0;
   }
   net::DnsResponse response(query->id(), true /* is_authoritative */,
diff --git a/net/dns/dns_response_unittest.cc b/net/dns/dns_response_unittest.cc
index 7ec9410d..5e3afcfe 100644
--- a/net/dns/dns_response_unittest.cc
+++ b/net/dns/dns_response_unittest.cc
@@ -732,7 +732,7 @@
   // buf contains 10 extra zero bytes.
   base::Optional<DnsQuery> query;
   query.emplace(buf);
-  query->Parse();
+  query->Parse(buf_size);
   net::DnsResourceRecord answer;
   answer.name = dotted_name;
   answer.type = dns_protocol::kTypeA;
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 648ace6..1f389731 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -394,6 +394,7 @@
     case CONNECTION_INFO_QUIC_43:
     case CONNECTION_INFO_QUIC_44:
     case CONNECTION_INFO_QUIC_45:
+    case CONNECTION_INFO_QUIC_46:
     case CONNECTION_INFO_QUIC_99:
       return true;
     case NUM_OF_CONNECTION_INFOS:
@@ -455,6 +456,8 @@
       return "http/2+quic/44";
     case CONNECTION_INFO_QUIC_45:
       return "http/2+quic/45";
+    case CONNECTION_INFO_QUIC_46:
+      return "http/2+quic/46";
     case CONNECTION_INFO_QUIC_99:
       return "http/2+quic/99";
     case CONNECTION_INFO_HTTP0_9:
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index bac2637..166dee91 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -58,6 +58,7 @@
     CONNECTION_INFO_QUIC_99 = 22,
     CONNECTION_INFO_QUIC_44 = 23,
     CONNECTION_INFO_QUIC_45 = 24,
+    CONNECTION_INFO_QUIC_46 = 25,
     NUM_OF_CONNECTION_INFOS,
   };
 
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index 328feec..5efeb24 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -244,12 +244,9 @@
 // ACK frame are sent and processed.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_send_timestamps, false)
 
-// If true, use a common stream ID limit checking method.
-QUIC_FLAG(bool, FLAGS_quic_use_common_stream_check, false)
-
 // When true, don't arm the path degrading alarm on the server side and stop
 // using HasUnackedPackets to decide when to arm it.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_path_degrading_alarm, false)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_path_degrading_alarm, true)
 
 // When true, QUIC server push uses a unidirectional stream.
 QUIC_FLAG(bool,
@@ -266,10 +263,33 @@
 // wrong when getting proof asynchronously.
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_fix_last_packet_is_ietf_quic,
-          false)
+          true)
 
 // If true, dispatcher passes in a single version when creating a server
 // connection, such that version negotiation is not supported in connection.
 QUIC_FLAG(bool,
           FLAGS_quic_restart_flag_quic_no_server_conn_ver_negotiation,
           false)
+
+// If true, enable QUIC version 46 which adds CRYPTO frames.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_46, false)
+
+// When true, cache that encryption has been established to save CPU.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_optimize_encryption_established,
+          false)
+
+// When in STARTUP and recovery, do not add bytes_acked to QUIC BBR's CWND in
+// CalculateCongestionWindow()
+QUIC_FLAG(
+    bool,
+    FLAGS_quic_reloadable_flag_quic_bbr_no_bytes_acked_in_startup_recovery,
+    false)
+
+// If true, make GeneralLossAlgorithm::DetectLosses faster by never rescanning
+// the same packet in QuicUnackedPacketMap.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_faster_detect_loss, false)
+
+// If true, use common code for checking whether a new stream ID may be
+// allocated.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_common_stream_check, false)
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index 13a2d9aa..28c79bf 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -90,6 +90,8 @@
       return HttpResponseInfo::CONNECTION_INFO_QUIC_44;
     case quic::QUIC_VERSION_45:
       return HttpResponseInfo::CONNECTION_INFO_QUIC_45;
+    case quic::QUIC_VERSION_46:
+      return HttpResponseInfo::CONNECTION_INFO_QUIC_46;
     case quic::QUIC_VERSION_99:
       return HttpResponseInfo::CONNECTION_INFO_QUIC_99;
   }
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 740d144f..da7a1832 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -2242,10 +2242,14 @@
 }
 
 TEST_P(QuicStreamFactoryTest, MigrateOnNetworkMadeDefaultWithSynchronousWrite) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   TestMigrationOnNetworkMadeDefault(SYNCHRONOUS);
 }
 
 TEST_P(QuicStreamFactoryTest, MigrateOnNetworkMadeDefaultWithAsyncWrite) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   TestMigrationOnNetworkMadeDefault(ASYNC);
 }
 
@@ -2428,6 +2432,8 @@
 // successfully, the probing writer will be unblocked on the network level, it
 // will not attempt to write new packets until the socket level is unblocked.
 TEST_P(QuicStreamFactoryTest, MigratedToBlockedSocketAfterProbing) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   InitializeConnectionMigrationV2Test({kDefaultNetworkForTests});
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -2608,6 +2614,8 @@
 //   comes up in the next kWaitTimeForNewNetworkSecs seonds.
 // - no new network is connected, migration times out. Session is closed.
 TEST_P(QuicStreamFactoryTest, MigrationTimeoutWithNoNewNetwork) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   InitializeConnectionMigrationV2Test({kDefaultNetworkForTests});
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -2679,6 +2687,8 @@
 // successfully probed path, any non-migratable stream will be reset. And if
 // the connection becomes idle then, close the connection.
 TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultNonMigratableStream) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   InitializeConnectionMigrationV2Test(
       {kDefaultNetworkForTests, kNewNetworkForTests});
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
@@ -3272,6 +3282,8 @@
 // connection being closed with INTERNAL_ERROR as pending ACK frame is not
 // allowed when processing a new packet.
 TEST_P(QuicStreamFactoryTest, MigrateToProbingSocket) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   InitializeConnectionMigrationV2Test(
       {kDefaultNetworkForTests, kNewNetworkForTests});
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
@@ -3434,6 +3446,8 @@
 // early when path degrading is detected with an ASYNCHRONOUS write before
 // migration.
 TEST_P(QuicStreamFactoryTest, MigrateEarlyOnPathDegradingAysnc) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   TestMigrationOnPathDegrading(/*async_write_before_migration*/ true);
 }
 
@@ -3441,6 +3455,8 @@
 // early when path degrading is detected with a SYNCHRONOUS write before
 // migration.
 TEST_P(QuicStreamFactoryTest, MigrateEarlyOnPathDegradingSync) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   TestMigrationOnPathDegrading(/*async_write_before_migration*/ false);
 }
 
@@ -3815,6 +3831,8 @@
 // The first packet being written after migration is a synchrnous write, which
 // will cause a PING packet being sent.
 TEST_P(QuicStreamFactoryTest, MigrateSessionWithDrainingStreamSync) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   TestMigrateSessionWithDrainingStream(SYNCHRONOUS);
 }
 
@@ -3824,6 +3842,8 @@
 // The first packet being written after migration is an asynchronous write, no
 // PING packet will be sent.
 TEST_P(QuicStreamFactoryTest, MigrateSessionWithDrainingStreamAsync) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   TestMigrateSessionWithDrainingStream(ASYNC);
 }
 
@@ -3995,6 +4015,8 @@
 // This test verifies that the connection migrates to the alternate network
 // when the alternate network is connected after path has been degrading.
 TEST_P(QuicStreamFactoryTest, MigrateOnNewNetworkConnectAfterPathDegrading) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   InitializeConnectionMigrationV2Test({kDefaultNetworkForTests});
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -4362,6 +4384,8 @@
 // alternate network on path degrading, and close the non-migratable streams
 // when probe is successful.
 TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNonMigratableStream) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   InitializeConnectionMigrationV2Test(
       {kDefaultNetworkForTests, kNewNetworkForTests});
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
@@ -4656,6 +4680,8 @@
 // - session attempts to migrate back to default network post migration;
 // - migration back to the default network is successful.
 TEST_P(QuicStreamFactoryTest, MigrateBackToDefaultPostMigrationOnWriteError) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   InitializeConnectionMigrationV2Test(
       {kDefaultNetworkForTests, kNewNetworkForTests});
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
@@ -4916,11 +4942,15 @@
 }
 
 TEST_P(QuicStreamFactoryTest, NewConnectionBeforeHandshakeAfterIdleTimeout) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   TestNewConnectionOnAlternateNetworkBeforeHandshake(
       quic::QUIC_NETWORK_IDLE_TIMEOUT);
 }
 
 TEST_P(QuicStreamFactoryTest, NewConnectionAfterHandshakeTimeout) {
+  if (version_ == quic::QUIC_VERSION_99)
+    return;
   TestNewConnectionOnAlternateNetworkBeforeHandshake(
       quic::QUIC_HANDSHAKE_TIMEOUT);
 }
diff --git a/net/third_party/quic/core/congestion_control/bbr_sender.cc b/net/third_party/quic/core/congestion_control/bbr_sender.cc
index f833609..7546844 100644
--- a/net/third_party/quic/core/congestion_control/bbr_sender.cc
+++ b/net/third_party/quic/core/congestion_control/bbr_sender.cc
@@ -773,11 +773,15 @@
   // Instead of immediately setting the target CWND as the new one, BBR grows
   // the CWND towards |target_window| by only increasing it |bytes_acked| at a
   // time.
+  const bool add_bytes_acked =
+      !GetQuicReloadableFlag(quic_bbr_no_bytes_acked_in_startup_recovery) ||
+      !InRecovery();
   if (is_at_full_bandwidth_) {
     congestion_window_ =
         std::min(target_window, congestion_window_ + bytes_acked);
-  } else if (congestion_window_ < target_window ||
-             sampler_.total_bytes_acked() < initial_congestion_window_) {
+  } else if (add_bytes_acked &&
+             (congestion_window_ < target_window ||
+              sampler_.total_bytes_acked() < initial_congestion_window_)) {
     // If the connection is not yet out of startup phase, do not decrease the
     // window.
     congestion_window_ = congestion_window_ + bytes_acked;
diff --git a/net/third_party/quic/core/congestion_control/bbr_sender_test.cc b/net/third_party/quic/core/congestion_control/bbr_sender_test.cc
index 8e1a695..75a65c93 100644
--- a/net/third_party/quic/core/congestion_control/bbr_sender_test.cc
+++ b/net/third_party/quic/core/congestion_control/bbr_sender_test.cc
@@ -264,8 +264,6 @@
   EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
   // At startup make sure we can send.
   EXPECT_TRUE(sender_->CanSend(0));
-  // Make sure we can send.
-  EXPECT_TRUE(sender_->CanSend(0));
   // And that window is un-affected.
   EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
 
@@ -302,6 +300,46 @@
   EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
 }
 
+TEST_F(BbrSenderTest, SimpleTransferEarlyPacketLoss) {
+  SetQuicReloadableFlag(quic_bbr_no_bytes_acked_in_startup_recovery, true);
+  // Enable rate based startup so the recovery window doesn't hide the true
+  // congestion_window_ in GetCongestionWindow().
+  SetConnectionOption(kBBS1);
+  // Disable Ack Decimation on the receiver, because it can increase srtt.
+  QuicConnectionPeer::SetAckMode(receiver_.connection(),
+                                 QuicConnection::AckMode::TCP_ACKING);
+  CreateDefaultSetup();
+
+  // At startup make sure we are at the default.
+  EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+  // Verify that Sender is in slow start.
+  EXPECT_TRUE(sender_->InSlowStart());
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_->CanSend(0));
+  // And that window is un-affected.
+  EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+
+  // Transfer 12MB.
+  bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024);
+  // Drop the first packet.
+  receiver_.DropNextIncomingPacket();
+  bool simulator_result = simulator_.RunUntilOrTimeout(
+      [this]() {
+        if (sender_->InRecovery()) {
+          // Two packets are acked before the first is declared lost.
+          EXPECT_LE(sender_->GetCongestionWindow(),
+                    (kDefaultWindowTCP + 2 * kDefaultTCPMSS));
+        }
+        return bbr_sender_.bytes_to_transfer() == 0 || !sender_->InSlowStart();
+      },
+      QuicTime::Delta::FromSeconds(30));
+  EXPECT_TRUE(simulator_result) << "Simple transfer failed.  Bytes remaining: "
+                                << bbr_sender_.bytes_to_transfer();
+  EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode);
+  EXPECT_EQ(1u, bbr_sender_.connection()->GetStats().packets_lost);
+  EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
+}
+
 // Test a simple long data transfer with 2 rtts of aggregation.
 TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) {
   CreateDefaultSetup();
diff --git a/net/third_party/quic/core/congestion_control/general_loss_algorithm.cc b/net/third_party/quic/core/congestion_control/general_loss_algorithm.cc
index 38dbf7ff8..5e8b038c 100644
--- a/net/third_party/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/net/third_party/quic/core/congestion_control/general_loss_algorithm.cc
@@ -30,7 +30,10 @@
 GeneralLossAlgorithm::GeneralLossAlgorithm() : GeneralLossAlgorithm(kNack) {}
 
 GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type)
-    : loss_detection_timeout_(QuicTime::Zero()), largest_lost_(0) {
+    : loss_detection_timeout_(QuicTime::Zero()),
+      largest_lost_(0),
+      least_in_flight_(1),
+      faster_detect_loss_(GetQuicReloadableFlag(quic_faster_detect_loss)) {
   SetLossDetectionType(loss_type);
 }
 
@@ -59,8 +62,27 @@
     QuicTime time,
     const RttStats& rtt_stats,
     QuicPacketNumber largest_newly_acked,
+    const AckedPacketVector& packets_acked,
     LostPacketVector* packets_lost) {
   loss_detection_timeout_ = QuicTime::Zero();
+  if (faster_detect_loss_ && !packets_acked.empty() &&
+      packets_acked.front().packet_number == least_in_flight_) {
+    if (least_in_flight_ + packets_acked.size() - 1 == largest_newly_acked) {
+      // Optimization for the case when no packet is missing.
+      QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_faster_detect_loss, 1, 3);
+      least_in_flight_ = largest_newly_acked + 1;
+      largest_previously_acked_ = largest_newly_acked;
+      return;
+    }
+    QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_faster_detect_loss, 2, 3);
+    // There is hole in acked_packets, increment least_in_flight_ if possible.
+    for (const auto& acked : packets_acked) {
+      if (acked.packet_number != least_in_flight_) {
+        break;
+      }
+      ++least_in_flight_;
+    }
+  }
   QuicTime::Delta max_rtt =
       std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
   QuicTime::Delta loss_delay =
@@ -68,14 +90,30 @@
                max_rtt + (max_rtt >> reordering_shift_));
   QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
   auto it = unacked_packets.begin();
-  if (largest_lost_ >= packet_number) {
-    if (largest_lost_ > unacked_packets.largest_sent_packet()) {
-      QUIC_BUG << "largest_lost: " << largest_lost_
-               << " is greater than largest_sent_packet: "
-               << unacked_packets.largest_sent_packet();
-    } else {
-      it += (largest_lost_ - packet_number + 1);
-      packet_number = largest_lost_ + 1;
+  if (faster_detect_loss_) {
+    if (least_in_flight_ >= packet_number) {
+      if (least_in_flight_ > unacked_packets.largest_sent_packet() + 1) {
+        QUIC_BUG << "least_in_flight: " << least_in_flight_
+                 << " is greater than largest_sent_packet + 1: "
+                 << unacked_packets.largest_sent_packet() + 1;
+      } else {
+        QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_faster_detect_loss, 3, 3);
+        it += (least_in_flight_ - packet_number);
+        packet_number = least_in_flight_;
+      }
+    }
+    // Clear least_in_flight_.
+    least_in_flight_ = kInvalidPacketNumber;
+  } else {
+    if (largest_lost_ >= packet_number) {
+      if (largest_lost_ > unacked_packets.largest_sent_packet()) {
+        QUIC_BUG << "largest_lost: " << largest_lost_
+                 << " is greater than largest_sent_packet: "
+                 << unacked_packets.largest_sent_packet();
+      } else {
+        it += (largest_lost_ - packet_number + 1);
+        packet_number = largest_lost_ + 1;
+      }
     }
   }
   for (; it != unacked_packets.end() && packet_number <= largest_newly_acked;
@@ -112,6 +150,10 @@
       QuicTime when_lost = it->sent_time + loss_delay;
       if (time < when_lost) {
         loss_detection_timeout_ = when_lost;
+        if (least_in_flight_ == kInvalidPacketNumber) {
+          // At this point, packet_number is in flight and not detected as lost.
+          least_in_flight_ = packet_number;
+        }
         break;
       }
       packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
@@ -124,6 +166,14 @@
       packets_lost->push_back(LostPacket(packet_number, it->bytes_sent));
       continue;
     }
+    if (least_in_flight_ == kInvalidPacketNumber) {
+      // At this point, packet_number is in flight and not detected as lost.
+      least_in_flight_ = packet_number;
+    }
+  }
+  if (least_in_flight_ == kInvalidPacketNumber) {
+    // There is no in flight packet.
+    least_in_flight_ = largest_newly_acked + 1;
   }
   largest_previously_acked_ = largest_newly_acked;
   if (!packets_lost->empty()) {
diff --git a/net/third_party/quic/core/congestion_control/general_loss_algorithm.h b/net/third_party/quic/core/congestion_control/general_loss_algorithm.h
index e69e0c7..65d2496 100644
--- a/net/third_party/quic/core/congestion_control/general_loss_algorithm.h
+++ b/net/third_party/quic/core/congestion_control/general_loss_algorithm.h
@@ -42,6 +42,7 @@
                     QuicTime time,
                     const RttStats& rtt_stats,
                     QuicPacketNumber largest_newly_acked,
+                    const AckedPacketVector& packets_acked,
                     LostPacketVector* packets_lost) override;
 
   // Returns a non-zero value when the early retransmit timer is active.
@@ -71,7 +72,14 @@
   // The largest newly acked from the previous call to DetectLosses.
   QuicPacketNumber largest_previously_acked_;
   // The largest lost packet.
+  // TODO(fayang): Remove this variable when deprecate
+  // quic_reloadable_flag_quic_faster_detect_loss.
   QuicPacketNumber largest_lost_;
+  // The least in flight packet. Loss detection should start from this. Please
+  // note, least_in_flight_ could be largest packet ever sent + 1.
+  QuicPacketNumber least_in_flight_;
+  // Latched value of quic_reloadable_flag_quic_faster_detect_loss.
+  const bool faster_detect_loss_;
 };
 
 }  // namespace quic
diff --git a/net/third_party/quic/core/congestion_control/general_loss_algorithm_test.cc b/net/third_party/quic/core/congestion_control/general_loss_algorithm_test.cc
index 1f72dc1..82b514d4 100644
--- a/net/third_party/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/net/third_party/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -50,13 +50,15 @@
   }
 
   void VerifyLosses(QuicPacketNumber largest_newly_acked,
+                    const AckedPacketVector& packets_acked,
                     const std::vector<QuicPacketNumber>& losses_expected) {
     if (largest_newly_acked > unacked_packets_.largest_acked()) {
       unacked_packets_.IncreaseLargestAcked(largest_newly_acked);
     }
     LostPacketVector lost_packets;
     loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_,
-                                 largest_newly_acked, &lost_packets);
+                                 largest_newly_acked, packets_acked,
+                                 &lost_packets);
     ASSERT_EQ(losses_expected.size(), lost_packets.size());
     for (size_t i = 0; i < losses_expected.size(); ++i) {
       EXPECT_EQ(lost_packets[i].packet_number, losses_expected[i]);
@@ -75,15 +77,21 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
+  AckedPacketVector packets_acked;
   // No loss on one ack.
   unacked_packets_.RemoveFromInFlight(2);
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   // No loss on two acks.
   unacked_packets_.RemoveFromInFlight(3);
-  VerifyLosses(3, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(3, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   // Loss on three acks.
   unacked_packets_.RemoveFromInFlight(4);
-  VerifyLosses(4, {1});
+  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -95,12 +103,15 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
-
+  AckedPacketVector packets_acked;
   // Nack the first packet 3 times in a single StretchAck.
   unacked_packets_.RemoveFromInFlight(2);
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
   unacked_packets_.RemoveFromInFlight(3);
+  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
   unacked_packets_.RemoveFromInFlight(4);
-  VerifyLosses(4, {1});
+  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -111,10 +122,11 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
-
+  AckedPacketVector packets_acked;
   // Nack the first packet 3 times in an AckFrame with three missing packets.
   unacked_packets_.RemoveFromInFlight(4);
-  VerifyLosses(4, {1});
+  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -124,14 +136,17 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
+  AckedPacketVector packets_acked;
   // Early retransmit when the final packet gets acked and the first is nacked.
   unacked_packets_.RemoveFromInFlight(2);
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 
   clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
-  VerifyLosses(2, {1});
+  VerifyLosses(2, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -144,23 +159,26 @@
       clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
     }
   }
-
+  AckedPacketVector packets_acked;
   // Early retransmit when the final packet gets acked and 1.25 RTTs have
   // elapsed since the packets were sent.
   unacked_packets_.RemoveFromInFlight(kNumSentPackets);
+  packets_acked.push_back(
+      AckedPacket(kNumSentPackets, kMaxPacketSize, QuicTime::Zero()));
   // This simulates a single ack following multiple missing packets with FACK.
-  VerifyLosses(kNumSentPackets, {1, 2});
+  VerifyLosses(kNumSentPackets, packets_acked, {1, 2});
+  packets_acked.clear();
   // The time has already advanced 1/4 an RTT, so ensure the timeout is set
   // 1.25 RTTs after the earliest pending packet(3), not the last(4).
   EXPECT_EQ(clock_.Now() + rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
-  VerifyLosses(kNumSentPackets, {3});
+  VerifyLosses(kNumSentPackets, packets_acked, {3});
   EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
-  VerifyLosses(kNumSentPackets, {4});
+  VerifyLosses(kNumSentPackets, packets_acked, {4});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -170,6 +188,7 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
+  AckedPacketVector packets_acked;
   // Neuter packet 1.
   unacked_packets_.RemoveRetransmittability(1);
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
@@ -177,7 +196,8 @@
   // Early retransmit when the final packet gets acked and the first is nacked.
   unacked_packets_.IncreaseLargestAcked(2);
   unacked_packets_.RemoveFromInFlight(2);
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
   EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 }
@@ -187,18 +207,21 @@
   SendDataPacket(1);
   SendDataPacket(2);
   SendAckPacket(3);
+  AckedPacketVector packets_acked;
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
 
   // Early retransmit when the final packet gets acked and the first is nacked.
   unacked_packets_.IncreaseLargestAcked(2);
   unacked_packets_.RemoveFromInFlight(2);
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 
   // The packet should be lost once the loss timeout is reached.
   clock_.AdvanceTime(0.25 * rtt_stats_.latest_rtt());
-  VerifyLosses(2, {1});
+  VerifyLosses(2, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -211,12 +234,13 @@
   // Transmit 2 packets.
   SendDataPacket(2);
   SendDataPacket(3);
-
+  AckedPacketVector packets_acked;
   // Wait another RTT and ack 2.
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
   unacked_packets_.IncreaseLargestAcked(2);
   unacked_packets_.RemoveFromInFlight(2);
-  VerifyLosses(2, {1});
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, {1});
 }
 
 // NoFack loss detection tests.
@@ -227,15 +251,21 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
+  AckedPacketVector packets_acked;
   // No loss on one ack.
   unacked_packets_.RemoveFromInFlight(2);
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   // No loss on two acks.
   unacked_packets_.RemoveFromInFlight(3);
-  VerifyLosses(3, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(3, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   // Loss on three acks.
   unacked_packets_.RemoveFromInFlight(4);
-  VerifyLosses(4, {1});
+  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -249,17 +279,22 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
-
+  AckedPacketVector packets_acked;
   // Nack the first packet 3 times in a single StretchAck.
   unacked_packets_.RemoveFromInFlight(2);
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
   unacked_packets_.RemoveFromInFlight(3);
+  packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero()));
   unacked_packets_.RemoveFromInFlight(4);
-  VerifyLosses(4, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   // The timer isn't set because we expect more acks.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Process another ack and then packet 1 will be lost.
   unacked_packets_.RemoveFromInFlight(5);
-  VerifyLosses(5, {1});
+  packets_acked.push_back(AckedPacket(5, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(5, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -271,15 +306,18 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
-
+  AckedPacketVector packets_acked;
   // Nack the first packet 3 times in an AckFrame with three missing packets.
   unacked_packets_.RemoveFromInFlight(4);
-  VerifyLosses(4, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(4, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   // The timer isn't set because we expect more acks.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Process another ack and then packet 1 and 2 will be lost.
   unacked_packets_.RemoveFromInFlight(5);
-  VerifyLosses(5, {1, 2});
+  packets_acked.push_back(AckedPacket(5, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(5, packets_acked, {1, 2});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -291,9 +329,12 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
+  AckedPacketVector packets_acked;
   unacked_packets_.RemoveFromInFlight(2);
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
   for (size_t i = 1; i < 500; ++i) {
-    VerifyLosses(2, std::vector<QuicPacketNumber>{});
+    VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+    packets_acked.clear();
   }
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     EXPECT_EQ(1.125 * rtt_stats_.smoothed_rtt(),
@@ -312,11 +353,14 @@
     SendDataPacket(i);
     clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
   }
+  AckedPacketVector packets_acked;
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
   unacked_packets_.RemoveFromInFlight(2);
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
     EXPECT_EQ(0.125 * rtt_stats_.smoothed_rtt(),
@@ -326,9 +370,9 @@
     EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
               loss_algorithm_.GetLossTimeout() - clock_.Now());
   }
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
-  VerifyLosses(2, {1});
+  VerifyLosses(2, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -340,17 +384,20 @@
     SendDataPacket(i);
     clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
   }
+  AckedPacketVector packets_acked;
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost without a nack.
   unacked_packets_.RemoveFromInFlight(1);
-  VerifyLosses(1, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(1, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   // The timer should still not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
-  VerifyLosses(1, std::vector<QuicPacketNumber>{});
+  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
-  VerifyLosses(1, std::vector<QuicPacketNumber>{});
+  VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{});
 
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
@@ -362,12 +409,15 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
+  AckedPacketVector packets_acked;
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
   unacked_packets_.RemoveFromInFlight(10);
-  VerifyLosses(10, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(10, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(10, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
     EXPECT_EQ(0.125 * rtt_stats_.smoothed_rtt(),
@@ -378,7 +428,7 @@
               loss_algorithm_.GetLossTimeout() - clock_.Now());
   }
   clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
-  VerifyLosses(10, {1, 2, 3, 4, 5, 6, 7, 8, 9});
+  VerifyLosses(10, packets_acked, {1, 2, 3, 4, 5, 6, 7, 8, 9});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -389,13 +439,16 @@
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
   }
+  AckedPacketVector packets_acked;
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // The packet should not be lost until 1.25 RTTs pass.
 
   unacked_packets_.RemoveFromInFlight(10);
-  VerifyLosses(10, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(10, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(10, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) {
     // Expect the timer to be set to 0.25 RTT's in the future.
     EXPECT_EQ(0.125 * rtt_stats_.smoothed_rtt(),
@@ -410,7 +463,9 @@
   // are lost.
   for (QuicPacketNumber i = 1; i <= 9; ++i) {
     unacked_packets_.RemoveFromInFlight(i);
-    VerifyLosses(i, std::vector<QuicPacketNumber>{});
+    packets_acked.push_back(AckedPacket(i, kMaxPacketSize, QuicTime::Zero()));
+    VerifyLosses(i, packets_acked, std::vector<QuicPacketNumber>{});
+    packets_acked.clear();
     EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   }
 }
@@ -425,18 +480,20 @@
     clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
   }
   EXPECT_EQ(QuicTime::Zero() + rtt_stats_.smoothed_rtt(), clock_.Now());
-
+  AckedPacketVector packets_acked;
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Packet 1 should not be lost until 1/16 RTTs pass.
   unacked_packets_.RemoveFromInFlight(2);
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero()));
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
+  packets_acked.clear();
   // Expect the timer to be set to 1/16 RTT's in the future.
   EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 16),
             loss_algorithm_.GetLossTimeout() - clock_.Now());
-  VerifyLosses(2, std::vector<QuicPacketNumber>{});
+  VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{});
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 16));
-  VerifyLosses(2, {1});
+  VerifyLosses(2, packets_acked, {1});
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
   // Retransmit packet 1 as 11 and 2 as 12.
   SendDataPacket(11);
diff --git a/net/third_party/quic/core/congestion_control/loss_detection_interface.h b/net/third_party/quic/core/congestion_control/loss_detection_interface.h
index 73954b3..6a8ff06 100644
--- a/net/third_party/quic/core/congestion_control/loss_detection_interface.h
+++ b/net/third_party/quic/core/congestion_control/loss_detection_interface.h
@@ -28,6 +28,7 @@
                             QuicTime time,
                             const RttStats& rtt_stats,
                             QuicPacketNumber largest_newly_acked,
+                            const AckedPacketVector& packets_acked,
                             LostPacketVector* packets_lost) = 0;
 
   // Get the time the LossDetectionAlgorithm wants to re-evaluate losses.
diff --git a/net/third_party/quic/core/congestion_control/send_algorithm_interface.cc b/net/third_party/quic/core/congestion_control/send_algorithm_interface.cc
index 2a0c2c9..c0d83a0 100644
--- a/net/third_party/quic/core/congestion_control/send_algorithm_interface.cc
+++ b/net/third_party/quic/core/congestion_control/send_algorithm_interface.cc
@@ -11,7 +11,6 @@
 #include "net/third_party/quic/platform/api/quic_fallthrough.h"
 #include "net/third_party/quic/platform/api/quic_flag_utils.h"
 #include "net/third_party/quic/platform/api/quic_flags.h"
-#include "net/third_party/quic/platform/api/quic_goog_cc_sender.h"
 #include "net/third_party/quic/platform/api/quic_pcc_sender.h"
 
 namespace quic {
@@ -29,10 +28,7 @@
     QuicPacketCount initial_congestion_window) {
   QuicPacketCount max_congestion_window = kDefaultMaxCongestionWindowPackets;
   switch (congestion_control_type) {
-    case kGoogCC:
-      return CreateGoogCcSender(clock, rtt_stats, unacked_packets, random,
-                                stats, initial_congestion_window,
-                                max_congestion_window);
+    case kGoogCC:  // GoogCC is not supported by quic/core, fall back to BBR.
     case kBBR:
       return new BbrSender(rtt_stats, unacked_packets,
                            initial_congestion_window, max_congestion_window,
diff --git a/net/third_party/quic/core/crypto/quic_compressed_certs_cache.cc b/net/third_party/quic/core/crypto/quic_compressed_certs_cache.cc
index 11b1240..d374046 100644
--- a/net/third_party/quic/core/crypto/quic_compressed_certs_cache.cc
+++ b/net/third_party/quic/core/crypto/quic_compressed_certs_cache.cc
@@ -17,6 +17,8 @@
 
 }  // namespace
 
+const size_t QuicCompressedCertsCache::kQuicCompressedCertsCacheSize = 225;
+
 QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts()
     : chain(nullptr),
       client_common_set_hashes(nullptr),
diff --git a/net/third_party/quic/core/crypto/quic_compressed_certs_cache.h b/net/third_party/quic/core/crypto/quic_compressed_certs_cache.h
index 05d20283..6cf9630 100644
--- a/net/third_party/quic/core/crypto/quic_compressed_certs_cache.h
+++ b/net/third_party/quic/core/crypto/quic_compressed_certs_cache.h
@@ -46,7 +46,7 @@
   size_t Size();
 
   // Default size of the QuicCompressedCertsCache per server side investigation.
-  static const size_t kQuicCompressedCertsCacheSize = 225;
+  static const size_t kQuicCompressedCertsCacheSize;
 
  private:
   // A wrapper of the tuple:
diff --git a/net/third_party/quic/core/http/http_decoder.cc b/net/third_party/quic/core/http/http_decoder.cc
index 3d57e8b..484e18c 100644
--- a/net/third_party/quic/core/http/http_decoder.cc
+++ b/net/third_party/quic/core/http/http_decoder.cc
@@ -142,13 +142,18 @@
     }
     case 0x3: {  // CANCEL_PUSH
       // TODO(rch): Handle partial delivery.
-      CancelPushFrame frame;
-      if (!reader->ReadVarInt62(&frame.push_id)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
-        return;
+      BufferFramePayload(reader);
+      if (remaining_frame_length_ == 0) {
+        CancelPushFrame frame;
+        QuicDataReader reader(buffer_.data(), current_frame_length_,
+                              NETWORK_BYTE_ORDER);
+        if (!reader.ReadVarInt62(&frame.push_id)) {
+          RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
+          return;
+        }
+        visitor_->OnCancelPushFrame(frame);
+        state_ = STATE_READING_FRAME_LENGTH;
       }
-      visitor_->OnCancelPushFrame(frame);
-      state_ = STATE_READING_FRAME_LENGTH;
       return;
     }
     case 0x4: {  // SETTINGS
@@ -219,13 +224,18 @@
 
     case 0xD: {  // MAX_PUSH_ID
       // TODO(rch): Handle partial delivery.
-      MaxPushIdFrame frame;
-      if (!reader->ReadVarInt62(&frame.push_id)) {
-        RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
-        return;
+      BufferFramePayload(reader);
+      if (remaining_frame_length_ == 0) {
+        QuicDataReader reader(buffer_.data(), current_frame_length_,
+                              NETWORK_BYTE_ORDER);
+        MaxPushIdFrame frame;
+        if (!reader.ReadVarInt62(&frame.push_id)) {
+          RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
+          return;
+        }
+        visitor_->OnMaxPushIdFrame(frame);
+        state_ = STATE_READING_FRAME_LENGTH;
       }
-      visitor_->OnMaxPushIdFrame(frame);
-      state_ = STATE_READING_FRAME_LENGTH;
       return;
     }
     // Reserved frame types.
diff --git a/net/third_party/quic/core/http/http_decoder_test.cc b/net/third_party/quic/core/http/http_decoder_test.cc
index 5e3876f..6040fea 100644
--- a/net/third_party/quic/core/http/http_decoder_test.cc
+++ b/net/third_party/quic/core/http/http_decoder_test.cc
@@ -98,7 +98,7 @@
 
 TEST_F(HttpDecoderTest, CancelPush) {
   char input[] = {// length
-                  0x2,
+                  0x1,
                   // type (CANCEL_PUSH)
                   0x03,
                   // Push Id
@@ -159,7 +159,7 @@
 
 TEST_F(HttpDecoderTest, MaxPushId) {
   char input[] = {// length
-                  0x2,
+                  0x1,
                   // type (MAX_PUSH_ID)
                   0x0D,
                   // Push Id
diff --git a/net/third_party/quic/core/http/http_encoder.cc b/net/third_party/quic/core/http/http_encoder.cc
new file mode 100644
index 0000000..214cc80
--- /dev/null
+++ b/net/third_party/quic/core/http/http_encoder.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quic/core/http/http_encoder.h"
+#include "net/third_party/quic/core/quic_data_writer.h"
+#include "net/third_party/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quic/platform/api/quic_fallthrough.h"
+#include "net/third_party/quic/platform/api/quic_logging.h"
+#include "net/third_party/quic/platform/api/quic_string.h"
+
+namespace quic {
+
+namespace {
+
+// Set the first byte of a PRIORITY frame according to its fields.
+uint8_t SetPriorityFields(uint8_t num,
+                          PriorityElementType type,
+                          bool prioritized) {
+  switch (type) {
+    case REQUEST_STREAM:
+      return num;
+    case PUSH_STREAM:
+      if (prioritized) {
+        return num | (1 << 6);
+      }
+      return num | (1 << 4);
+    case PLACEHOLDER:
+      if (prioritized) {
+        return num | (1 << 7);
+      }
+      return num | (1 << 5);
+    case ROOT_OF_TREE:
+      if (prioritized) {
+        num = num | (1 << 6);
+        return num | (1 << 7);
+      }
+      num = num | (1 << 4);
+      return num | (1 << 5);
+    default:
+      QUIC_NOTREACHED();
+      return num;
+  }
+}
+
+// Length of the type field of a frame.
+static const size_t kFrameTypeLength = 1;
+// Length of the weight field of a priority frame.
+static const size_t kPriorityWeightLength = 1;
+// Length of a priority frame's first byte.
+static const size_t kPriorityFirstByteLength = 1;
+// Length of a key in the map of a settings frame.
+static const size_t kSettingsMapKeyLength = 2;
+
+}  // namespace
+
+HttpEncoder::HttpEncoder() {}
+
+HttpEncoder::~HttpEncoder() {}
+
+QuicByteCount HttpEncoder::SerializeDataFrameHeader(
+    const DataFrame& data,
+    std::unique_ptr<char[]>* output) {
+  int header_length =
+      QuicDataWriter::GetVarInt62Len(data.data.length()) + kFrameTypeLength;
+
+  output->reset(new char[header_length]);
+  QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER);
+
+  if (WriteFrameHeader(data.data.length(), HttpFrameType::DATA, &writer)) {
+    return header_length;
+  }
+  return 0;
+}
+
+QuicByteCount HttpEncoder::SerializePriorityFrame(
+    const PriorityFrame& priority,
+    std::unique_ptr<char[]>* output) {
+  QuicByteCount payload_length =
+      kPriorityFirstByteLength +
+      QuicDataWriter::GetVarInt62Len(priority.prioritized_element_id) +
+      QuicDataWriter::GetVarInt62Len(priority.element_dependency_id) +
+      kPriorityWeightLength;
+  QuicByteCount total_length = GetTotalLength(payload_length);
+
+  output->reset(new char[total_length]);
+  QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+
+  if (!WriteFrameHeader(payload_length, HttpFrameType::PRIORITY, &writer)) {
+    return 0;
+  }
+
+  // Set the first byte of the payload.
+  uint8_t bits = 0;
+  bits = SetPriorityFields(bits, priority.prioritized_type, true);
+  bits = SetPriorityFields(bits, priority.dependency_type, false);
+  if (priority.exclusive) {
+    bits |= 1;
+  }
+
+  if (writer.WriteUInt8(bits) &&
+      writer.WriteVarInt62(priority.prioritized_element_id) &&
+      writer.WriteVarInt62(priority.element_dependency_id) &&
+      writer.WriteUInt8(priority.weight)) {
+    return total_length;
+  }
+  return 0;
+}
+
+QuicByteCount HttpEncoder::SerializeCancelPushFrame(
+    const CancelPushFrame& cancel_push,
+    std::unique_ptr<char[]>* output) {
+  QuicByteCount payload_length =
+      QuicDataWriter::GetVarInt62Len(cancel_push.push_id);
+  QuicByteCount total_length = GetTotalLength(payload_length);
+
+  output->reset(new char[total_length]);
+  QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+
+  if (WriteFrameHeader(payload_length, HttpFrameType::CANCEL_PUSH, &writer) &&
+      writer.WriteVarInt62(cancel_push.push_id)) {
+    return total_length;
+  }
+  return 0;
+}
+
+QuicByteCount HttpEncoder::SerializeSettingsFrame(
+    const SettingsFrame& settings,
+    std::unique_ptr<char[]>* output) {
+  // Calculate the key sizes.
+  QuicByteCount payload_length = settings.values.size() * kSettingsMapKeyLength;
+  // Calculate the value sizes.
+  for (auto it = settings.values.begin(); it != settings.values.end(); ++it) {
+    payload_length += QuicDataWriter::GetVarInt62Len(it->second);
+  }
+
+  QuicByteCount total_length = GetTotalLength(payload_length);
+
+  output->reset(new char[total_length]);
+  QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+
+  if (!WriteFrameHeader(payload_length, HttpFrameType::SETTINGS, &writer)) {
+    return 0;
+  }
+
+  for (auto it = settings.values.begin(); it != settings.values.end(); ++it) {
+    if (!writer.WriteUInt16(it->first) || !writer.WriteVarInt62(it->second)) {
+      return 0;
+    }
+  }
+
+  return total_length;
+}
+
+QuicByteCount HttpEncoder::SerializeGoAwayFrame(
+    const GoAwayFrame& goaway,
+    std::unique_ptr<char[]>* output) {
+  QuicByteCount payload_length =
+      QuicDataWriter::GetVarInt62Len(goaway.stream_id);
+  QuicByteCount total_length = GetTotalLength(payload_length);
+
+  output->reset(new char[total_length]);
+  QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+
+  if (WriteFrameHeader(payload_length, HttpFrameType::GOAWAY, &writer) &&
+      writer.WriteVarInt62(goaway.stream_id)) {
+    return total_length;
+  }
+  return 0;
+}
+
+QuicByteCount HttpEncoder::SerializeMaxPushIdFrame(
+    const MaxPushIdFrame& max_push_id,
+    std::unique_ptr<char[]>* output) {
+  QuicByteCount payload_length =
+      QuicDataWriter::GetVarInt62Len(max_push_id.push_id);
+  QuicByteCount total_length = GetTotalLength(payload_length);
+
+  output->reset(new char[total_length]);
+  QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER);
+
+  if (WriteFrameHeader(payload_length, HttpFrameType::MAX_PUSH_ID, &writer) &&
+      writer.WriteVarInt62(max_push_id.push_id)) {
+    return total_length;
+  }
+  return 0;
+}
+
+bool HttpEncoder::WriteFrameHeader(QuicByteCount length,
+                                   HttpFrameType type,
+                                   QuicDataWriter* writer) {
+  return writer->WriteVarInt62(length) &&
+         writer->WriteUInt8(static_cast<uint8_t>(type));
+}
+
+QuicByteCount HttpEncoder::GetTotalLength(QuicByteCount payload_length) {
+  return QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength +
+         payload_length;
+}
+
+}  // namespace quic
diff --git a/net/third_party/quic/core/http/http_encoder.h b/net/third_party/quic/core/http/http_encoder.h
new file mode 100644
index 0000000..00b0f0b
--- /dev/null
+++ b/net/third_party/quic/core/http/http_encoder.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_THIRD_PARTY_QUIC_CORE_HTTP_HTTP_ENCODER_H_
+#define NET_THIRD_PARTY_QUIC_CORE_HTTP_HTTP_ENCODER_H_
+
+#include <cstddef>
+
+#include "net/third_party/quic/core/http/http_frames.h"
+#include "net/third_party/quic/core/quic_error_codes.h"
+#include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+class QuicDataWriter;
+
+// A class for encoding the HTTP frames that are exchanged in an HTTP over QUIC
+// session.
+class QUIC_EXPORT_PRIVATE HttpEncoder {
+ public:
+  HttpEncoder();
+
+  ~HttpEncoder();
+
+  // Serializes the header of a DATA frame into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeDataFrameHeader(const DataFrame& data,
+                                         std::unique_ptr<char[]>* output);
+
+  // Serializes a PRIORITY frame into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializePriorityFrame(const PriorityFrame& priority,
+                                       std::unique_ptr<char[]>* output);
+
+  // Serializes a CANCEL_PUSH frame into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeCancelPushFrame(const CancelPushFrame& cancel_push,
+                                         std::unique_ptr<char[]>* output);
+
+  // Serializes a SETTINGS frame into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeSettingsFrame(const SettingsFrame& settings,
+                                       std::unique_ptr<char[]>* output);
+
+  // Serializes a GOAWAY frame into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeGoAwayFrame(const GoAwayFrame& goaway,
+                                     std::unique_ptr<char[]>* output);
+
+  // Serializes a MAX_PUSH frame into a new buffer stored in |output|.
+  // Returns the length of the buffer on success, or 0 otherwise.
+  QuicByteCount SerializeMaxPushIdFrame(const MaxPushIdFrame& max_push_id,
+                                        std::unique_ptr<char[]>* output);
+
+ private:
+  bool WriteFrameHeader(QuicByteCount length,
+                        HttpFrameType type,
+                        QuicDataWriter* writer);
+
+  QuicByteCount GetTotalLength(QuicByteCount payload_length);
+};
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_CORE_HTTP_HTTP_ENCODER_H_
diff --git a/net/third_party/quic/core/http/http_encoder_test.cc b/net/third_party/quic/core/http/http_encoder_test.cc
new file mode 100644
index 0000000..d36ac86e
--- /dev/null
+++ b/net/third_party/quic/core/http/http_encoder_test.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quic/core/http/http_encoder.h"
+#include "net/third_party/quic/platform/api/quic_arraysize.h"
+#include "net/third_party/quic/platform/api/quic_string.h"
+#include "net/third_party/quic/platform/api/quic_test.h"
+#include "net/third_party/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+
+class HttpEncoderTest : public QuicTest {
+ public:
+  HttpEncoderTest() {}
+  HttpEncoder encoder_;
+};
+
+TEST_F(HttpEncoderTest, SerializeDataFrame) {
+  DataFrame data;
+  data.data = "Data!";
+  std::unique_ptr<char[]> buffer;
+  uint64_t length = encoder_.SerializeDataFrameHeader(data, &buffer);
+  char output[] = {// length
+                   0x05,
+                   // type (DATA)
+                   0x00};
+  EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
+  CompareCharArraysWithHexError("DATA", buffer.get(), length, output,
+                                QUIC_ARRAYSIZE(output));
+}
+
+TEST_F(HttpEncoderTest, SerializePriorityFrame) {
+  PriorityFrame priority;
+  priority.prioritized_type = REQUEST_STREAM;
+  priority.dependency_type = REQUEST_STREAM;
+  priority.exclusive = true;
+  priority.prioritized_element_id = 0x03;
+  priority.element_dependency_id = 0x04;
+  priority.weight = 0xFF;
+  char output[] = {// length
+                   0x4,
+                   // type (PRIORITY)
+                   0x2,
+                   // request stream, request stream, exclusive
+                   0x01,
+                   // prioritized_element_id
+                   0x03,
+                   // element_dependency_id
+                   0x04,
+                   // weight
+                   0xFF};
+
+  std::unique_ptr<char[]> buffer;
+  uint64_t length = encoder_.SerializePriorityFrame(priority, &buffer);
+  EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
+  CompareCharArraysWithHexError("PRIORITY", buffer.get(), length, output,
+                                QUIC_ARRAYSIZE(output));
+}
+
+TEST_F(HttpEncoderTest, SerializeCancelPushFrame) {
+  CancelPushFrame cancel_push;
+  cancel_push.push_id = 0x01;
+  char output[] = {// length
+                   0x1,
+                   // type (CANCEL_PUSH)
+                   0x03,
+                   // Push Id
+                   0x01};
+  std::unique_ptr<char[]> buffer;
+  uint64_t length = encoder_.SerializeCancelPushFrame(cancel_push, &buffer);
+  EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
+  CompareCharArraysWithHexError("CANCEL_PUSH", buffer.get(), length, output,
+                                QUIC_ARRAYSIZE(output));
+}
+
+TEST_F(HttpEncoderTest, SerializeSettingsFrame) {
+  SettingsFrame settings;
+  settings.values[3] = 2;
+  settings.values[6] = 5;
+  // clang-format off
+  char output[] = {
+      // length
+      0x06,
+      // type (SETTINGS)
+      0x04,
+      // identifier (SETTINGS_NUM_PLACEHOLDERS)
+      0x00,
+      0x03,
+      // content
+      0x02,
+      // identifier (SETTINGS_MAX_HEADER_LIST_SIZE)
+      0x00,
+      0x06,
+      // content
+      0x05,
+  };
+  // clang-format on
+  std::unique_ptr<char[]> buffer;
+  uint64_t length = encoder_.SerializeSettingsFrame(settings, &buffer);
+  EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
+  CompareCharArraysWithHexError("SETTINGS", buffer.get(), length, output,
+                                QUIC_ARRAYSIZE(output));
+}
+
+TEST_F(HttpEncoderTest, SerializeGoAwayFrame) {
+  GoAwayFrame goaway;
+  goaway.stream_id = 0x1;
+  char output[] = {// length
+                   0x1,
+                   // type (GOAWAY)
+                   0x07,
+                   // StreamId
+                   0x01};
+  std::unique_ptr<char[]> buffer;
+  uint64_t length = encoder_.SerializeGoAwayFrame(goaway, &buffer);
+  EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
+  CompareCharArraysWithHexError("GOAWAY", buffer.get(), length, output,
+                                QUIC_ARRAYSIZE(output));
+}
+
+TEST_F(HttpEncoderTest, SerializeMaxPushIdFrame) {
+  MaxPushIdFrame max_push_id;
+  max_push_id.push_id = 0x1;
+  char output[] = {// length
+                   0x1,
+                   // type (MAX_PUSH_ID)
+                   0x0D,
+                   // Push Id
+                   0x01};
+  std::unique_ptr<char[]> buffer;
+  uint64_t length = encoder_.SerializeMaxPushIdFrame(max_push_id, &buffer);
+  EXPECT_EQ(QUIC_ARRAYSIZE(output), length);
+  CompareCharArraysWithHexError("MAX_PUSH_ID", buffer.get(), length, output,
+                                QUIC_ARRAYSIZE(output));
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/net/third_party/quic/core/http/http_frames.h b/net/third_party/quic/core/http/http_frames.h
index 6ff9206..57a7ed75 100644
--- a/net/third_party/quic/core/http/http_frames.h
+++ b/net/third_party/quic/core/http/http_frames.h
@@ -9,6 +9,17 @@
 
 namespace quic {
 
+enum class HttpFrameType : uint8_t {
+  DATA = 0x0,
+  HEADERS = 0x1,
+  PRIORITY = 0X2,
+  CANCEL_PUSH = 0X3,
+  SETTINGS = 0x4,
+  PUSH_PROMISE = 0x5,
+  GOAWAY = 0x7,
+  MAX_PUSH_ID = 0xD
+};
+
 // 4.2.2.  DATA
 //
 //   DATA frames (type=0x0) convey arbitrary, variable-length sequences of
@@ -75,7 +86,7 @@
 //   on peer behavior
 
 using SettingsId = uint16_t;
-using SettingsMap = std::map<SettingsId, uint32_t>;
+using SettingsMap = std::map<SettingsId, uint64_t>;
 
 struct SettingsFrame {
   SettingsMap values;
diff --git a/net/third_party/quic/core/http/quic_server_session_base.cc b/net/third_party/quic/core/http/quic_server_session_base.cc
index 711d8e2..0fcaaff 100644
--- a/net/third_party/quic/core/http/quic_server_session_base.cc
+++ b/net/third_party/quic/core/http/quic_server_session_base.cc
@@ -220,14 +220,14 @@
     QUIC_BUG << "Encryption not established so no outgoing stream created.";
     return false;
   }
-  if (!GetQuicFlag(FLAGS_quic_use_common_stream_check)) {
+  if (!GetQuicReloadableFlag(quic_use_common_stream_check)) {
     if (GetNumOpenOutgoingStreams() >= max_open_outgoing_streams()) {
       VLOG(1) << "No more streams should be created. "
               << "Already " << GetNumOpenOutgoingStreams() << " open.";
       return false;
     }
   }
-  QUIC_FLAG_COUNT_N(quic_use_common_stream_check, 2, 2);
+  QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_common_stream_check, 2, 2);
   return CanOpenNextOutgoingStream();
 }
 
diff --git a/net/third_party/quic/core/http/quic_spdy_client_session.cc b/net/third_party/quic/core/http/quic_spdy_client_session.cc
index 2014db4..f2266bdb 100644
--- a/net/third_party/quic/core/http/quic_spdy_client_session.cc
+++ b/net/third_party/quic/core/http/quic_spdy_client_session.cc
@@ -47,7 +47,7 @@
     QUIC_DLOG(INFO) << "Encryption not active so no outgoing stream created.";
     return false;
   }
-  if (!GetQuicFlag(FLAGS_quic_use_common_stream_check)) {
+  if (!GetQuicReloadableFlag(quic_use_common_stream_check)) {
     if (GetNumOpenOutgoingStreams() >= max_open_outgoing_streams()) {
       QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
                       << "Already " << GetNumOpenOutgoingStreams() << " open.";
@@ -65,7 +65,7 @@
                     << "Already received goaway.";
     return false;
   }
-  QUIC_FLAG_COUNT_N(quic_use_common_stream_check, 1, 2);
+  QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_common_stream_check, 1, 2);
   return CanOpenNextOutgoingStream();
 }
 
diff --git a/net/third_party/quic/core/http/quic_spdy_session_test.cc b/net/third_party/quic/core/http/quic_spdy_session_test.cc
index 082265f..bd73634f 100644
--- a/net/third_party/quic/core/http/quic_spdy_session_test.cc
+++ b/net/third_party/quic/core/http/quic_spdy_session_test.cc
@@ -851,15 +851,14 @@
   QuicSocketAddress new_peer_address =
       QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort + 1);
 
-  MockPacketWriter* writer = static_cast<MockPacketWriter*>(
-      QuicConnectionPeer::GetWriter(session_.connection()));
-  EXPECT_CALL(*writer, WritePacket(_, _, _, new_peer_address, _))
-      .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
   EXPECT_CALL(*connection_,
-              SendConnectivityProbingPacket(nullptr, new_peer_address))
-      .WillOnce(
-          Invoke(connection_,
-                 &MockQuicConnection::ReallySendConnectivityProbingPacket));
+              SendConnectivityProbingResponsePacket(new_peer_address));
+  if (transport_version() == QUIC_VERSION_99) {
+    // Need to explicitly do this to emulate the reception of a PathChallenge,
+    // which stores its payload for use in generating the response.
+    connection_->OnPathChallengeFrame(
+        QuicPathChallengeFrame(0, {{0, 1, 2, 3, 4, 5, 6, 7}}));
+  }
   session_.OnConnectivityProbeReceived(session_.self_address(),
                                        new_peer_address);
   EXPECT_EQ(old_peer_address, session_.peer_address());
diff --git a/net/third_party/quic/core/qpack/qpack_decoder.cc b/net/third_party/quic/core/qpack/qpack_decoder.cc
index 13d1fc1..b862c93 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder.cc
+++ b/net/third_party/quic/core/qpack/qpack_decoder.cc
@@ -194,6 +194,8 @@
 
 void QpackDecoder::ProgressiveDecoder::DoVarintDone() {
   if (literal_name_) {
+    // TODO(bnc): Impose a sensible limit on length to avoid memory exhaustion
+    // attacks.
     name_length_ = varint_decoder_.value();
     name_.clear();
     name_.reserve(name_length_);
@@ -308,6 +310,8 @@
 
 void QpackDecoder::ProgressiveDecoder::DoValueLengthDone() {
   value_.clear();
+  // TODO(bnc): Impose a sensible limit on length to avoid memory exhaustion
+  // attacks.
   value_length_ = varint_decoder_.value();
 
   // If value is empty, skip DoReadValue() and DoDecodeValue() and jump directly
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_test.cc b/net/third_party/quic/core/qpack/qpack_decoder_test.cc
index 3a84e9a2..9f43a39 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder_test.cc
+++ b/net/third_party/quic/core/qpack/qpack_decoder_test.cc
@@ -122,14 +122,14 @@
   EXPECT_CALL(handler_, OnDecodingErrorDetected(
                             QuicStringPiece("Encoded integer too large.")));
 
-  Decode(QuicTextUtils::HexDecode("27ffffffffff"));
+  Decode(QuicTextUtils::HexDecode("27ffffffffffffffffffff"));
 }
 
 TEST_P(QpackDecoderTest, ValueLenTooLarge) {
   EXPECT_CALL(handler_,
               OnDecodingErrorDetected(QuicStringPiece("ValueLen too large.")));
 
-  Decode(QuicTextUtils::HexDecode("23666f6f7fffffffffff"));
+  Decode(QuicTextUtils::HexDecode("23666f6f7fffffffffffffffffffff"));
 }
 
 TEST_P(QpackDecoderTest, IncompleteHeaderBlock) {
@@ -213,50 +213,38 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
                                         QuicStringPiece("POST")));
   EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":method"),
-                                        QuicStringPiece("CONNECT")));
+                                        QuicStringPiece("TRACE")));
 
   // A header name that has a single entry with non-empty value.
   EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
-                                        QuicStringPiece("gzip, deflate")));
+                                        QuicStringPiece("gzip, deflate, br")));
   EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
-                                        QuicStringPiece("brotli")));
+                                        QuicStringPiece("compress")));
   EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("accept-encoding"),
                                         QuicStringPiece("")));
 
   // A header name that has a single entry with empty value.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("cache-control"),
+  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("location"),
                                         QuicStringPiece("")));
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("cache-control"),
+  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("location"),
                                         QuicStringPiece("foo")));
 
   EXPECT_CALL(handler_, OnDecodingCompleted());
 
   Decode(QuicTextUtils::HexDecode(
-      "c2c35207434f4e4e454354d05f010662726f746c695f0100d85f0903666f6f"));
-}
-
-TEST_P(QpackDecoderTest, TooLowStaticTableIndex) {
-  // This is the first entry in the static table with index 1.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece(":authority"),
-                                        QuicStringPiece("")));
-
-  // Addressing entry 0 should trigger an error.
-  EXPECT_CALL(handler_, OnDecodingErrorDetected(
-                            QuicStringPiece("Invalid static table index.")));
-
-  Decode(QuicTextUtils::HexDecode("c1c0"));
+      "d1dfccd45f108621e9aec2a11f5c8294e75f000554524143455f1000"));
 }
 
 TEST_P(QpackDecoderTest, TooHighStaticTableIndex) {
-  // This is the last entry in the static table with index 61.
-  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("www-authenticate"),
-                                        QuicStringPiece("")));
+  // This is the last entry in the static table with index 98.
+  EXPECT_CALL(handler_, OnHeaderDecoded(QuicStringPiece("x-frame-options"),
+                                        QuicStringPiece("sameorigin")));
 
-  // Addressing entry 62 should trigger an error.
+  // Addressing entry 99 should trigger an error.
   EXPECT_CALL(handler_, OnDecodingErrorDetected(
                             QuicStringPiece("Invalid static table index.")));
 
-  Decode(QuicTextUtils::HexDecode("fdfe"));
+  Decode(QuicTextUtils::HexDecode("ff23ff24"));
 }
 }  // namespace
 }  // namespace test
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_test.cc b/net/third_party/quic/core/qpack/qpack_encoder_test.cc
index 2755665..8cc733c 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder_test.cc
+++ b/net/third_party/quic/core/qpack/qpack_encoder_test.cc
@@ -99,29 +99,28 @@
   {
     spdy::SpdyHeaderBlock header_list;
     header_list[":method"] = "GET";
-    header_list["accept-encoding"] = "gzip, deflate";
-    header_list["cache-control"] = "";
+    header_list["accept-encoding"] = "gzip, deflate, br";
+    header_list["location"] = "";
 
     QuicString output = Encode(&header_list);
-    EXPECT_EQ(QuicTextUtils::HexDecode("c2d0d8"), output);
+    EXPECT_EQ(QuicTextUtils::HexDecode("d1dfcc"), output);
   }
   {
     spdy::SpdyHeaderBlock header_list;
     header_list[":method"] = "POST";
-    header_list["accept-encoding"] = "brotli";
-    header_list["cache-control"] = "foo";
+    header_list["accept-encoding"] = "compress";
+    header_list["location"] = "foo";
 
     QuicString output = Encode(&header_list);
-    DLOG(INFO) << QuicTextUtils::HexEncode(output);
-    EXPECT_EQ(QuicTextUtils::HexDecode("c35f01858ec3a6837f5f098294e7"), output);
+    EXPECT_EQ(QuicTextUtils::HexDecode("d45f108621e9aec2a11f5c8294e7"), output);
   }
   {
     spdy::SpdyHeaderBlock header_list;
-    header_list[":method"] = "CONNECT";
+    header_list[":method"] = "TRACE";
     header_list["accept-encoding"] = "";
 
     QuicString output = Encode(&header_list);
-    EXPECT_EQ(QuicTextUtils::HexDecode("5207434f4e4e4543545f0100"), output);
+    EXPECT_EQ(QuicTextUtils::HexDecode("5f000554524143455f1000"), output);
   }
 }
 
diff --git a/net/third_party/quic/core/qpack/qpack_header_table.cc b/net/third_party/quic/core/qpack/qpack_header_table.cc
index de07681e..81bf49d2 100644
--- a/net/third_party/quic/core/qpack/qpack_header_table.cc
+++ b/net/third_party/quic/core/qpack/qpack_header_table.cc
@@ -1,49 +1,45 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 #include "net/third_party/quic/core/qpack/qpack_header_table.h"
 
 #include "base/logging.h"
-#include "net/third_party/spdy/core/hpack/hpack_constants.h"
-#include "net/third_party/spdy/core/hpack/hpack_entry.h"
-#include "net/third_party/spdy/core/hpack/hpack_static_table.h"
+#include "net/third_party/quic/core/qpack/qpack_static_table.h"
 
 namespace quic {
 
-// Currently using HPACK static tables.
-// TODO(bnc):  QPACK is likely to get its own static table.  When this happens,
-// fork HpackStaticTable code and modify static table.
 QpackHeaderTable::QpackHeaderTable()
-    : static_entries_(spdy::ObtainHpackStaticTable().GetStaticEntries()),
-      static_index_(spdy::ObtainHpackStaticTable().GetStaticIndex()),
-      static_name_index_(spdy::ObtainHpackStaticTable().GetStaticNameIndex()) {}
+    : static_entries_(ObtainQpackStaticTable().GetStaticEntries()),
+      static_index_(ObtainQpackStaticTable().GetStaticIndex()),
+      static_name_index_(ObtainQpackStaticTable().GetStaticNameIndex()) {}
 
 QpackHeaderTable::~QpackHeaderTable() = default;
 
-const spdy::HpackEntry* QpackHeaderTable::LookupEntry(size_t index) const {
-  // Static table indexing starts with 1.
-  if (index == 0 || index > static_entries_.size()) {
+const QpackEntry* QpackHeaderTable::LookupEntry(size_t index) const {
+  if (index >= static_entries_.size()) {
     return nullptr;
   }
 
-  return &static_entries_[index - 1];
+  return &static_entries_[index];
 }
 
 QpackHeaderTable::MatchType QpackHeaderTable::FindHeaderField(
     QuicStringPiece name,
     QuicStringPiece value,
     size_t* index) const {
-  spdy::HpackEntry query(name, value);
+  QpackEntry query(name, value);
   auto static_index_it = static_index_.find(&query);
   if (static_index_it != static_index_.end()) {
     DCHECK((*static_index_it)->IsStatic());
-    // Static table indexing starts with 1.
-    *index = (*static_index_it)->InsertionIndex() + 1;
+    *index = (*static_index_it)->InsertionIndex();
     return MatchType::kNameAndValue;
   }
 
   auto static_name_index_it = static_name_index_.find(name);
   if (static_name_index_it != static_name_index_.end()) {
     DCHECK(static_name_index_it->second->IsStatic());
-    // Static table indexing starts with 1.
-    *index = static_name_index_it->second->InsertionIndex() + 1;
+    *index = static_name_index_it->second->InsertionIndex();
     return MatchType::kName;
   }
 
diff --git a/net/third_party/quic/core/qpack/qpack_header_table.h b/net/third_party/quic/core/qpack/qpack_header_table.h
index 5fa4554..559d9ce 100644
--- a/net/third_party/quic/core/qpack/qpack_header_table.h
+++ b/net/third_party/quic/core/qpack/qpack_header_table.h
@@ -1,3 +1,7 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 #ifndef NET_THIRD_PARTY_QUIC_CORE_QPACK_QPACK_HEADER_TABLE_H_
 #define NET_THIRD_PARTY_QUIC_CORE_QPACK_QPACK_HEADER_TABLE_H_
 
@@ -5,10 +9,13 @@
 
 #include "net/third_party/quic/platform/api/quic_export.h"
 #include "net/third_party/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/spdy/core/hpack/hpack_entry.h"
 #include "net/third_party/spdy/core/hpack/hpack_header_table.h"
 
 namespace quic {
 
+using QpackEntry = spdy::HpackEntry;
+
 // This class manages the QPACK static and dynamic tables.
 // TODO(bnc): Implement dynamic table.
 class QUIC_EXPORT_PRIVATE QpackHeaderTable {
@@ -29,7 +36,7 @@
   ~QpackHeaderTable();
 
   // Returns the entry at given index, or nullptr on error.
-  const spdy::HpackEntry* LookupEntry(size_t index) const;
+  const QpackEntry* LookupEntry(size_t index) const;
 
   // Returns the index of an entry with matching name and value if such exists,
   // otherwise one with matching name is such exists.
@@ -39,12 +46,12 @@
 
  private:
   // |static_entries_|, |static_index_|, |static_name_index_| are owned by
-  // HpackStaticTable singleton.
+  // QpackStaticTable singleton.
 
-  // Tracks HpackEntries by index.
+  // Tracks QpackEntries by index.
   const EntryTable& static_entries_;
 
-  // Tracks the unique HpackEntry for a given header name and value.
+  // Tracks the unique QpackEntry for a given header name and value.
   const UnorderedEntrySet& static_index_;
 
   // Tracks the first static entry for each name in the static table.
diff --git a/net/third_party/quic/core/qpack/qpack_header_table_test.cc b/net/third_party/quic/core/qpack/qpack_header_table_test.cc
index f15073b..fd67304 100644
--- a/net/third_party/quic/core/qpack/qpack_header_table_test.cc
+++ b/net/third_party/quic/core/qpack/qpack_header_table_test.cc
@@ -1,5 +1,11 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 #include "net/third_party/quic/core/qpack/qpack_header_table.h"
 
+#include "net/third_party/quic/core/qpack/qpack_static_table.h"
+#include "net/third_party/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quic/platform/api/quic_test.h"
 #include "net/third_party/spdy/core/hpack/hpack_entry.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -15,21 +21,20 @@
 
 TEST_F(QpackHeaderTableTest, LookupEntry) {
   const auto* entry = table_.LookupEntry(0);
-  EXPECT_FALSE(entry);
-
-  entry = table_.LookupEntry(1);
   EXPECT_EQ(":authority", entry->name());
   EXPECT_EQ("", entry->value());
 
-  entry = table_.LookupEntry(2);
-  EXPECT_EQ(":method", entry->name());
-  EXPECT_EQ("GET", entry->value());
+  entry = table_.LookupEntry(1);
+  EXPECT_EQ(":path", entry->name());
+  EXPECT_EQ("/", entry->value());
 
-  entry = table_.LookupEntry(61);
-  EXPECT_EQ("www-authenticate", entry->name());
-  EXPECT_EQ("", entry->value());
+  // 98 is the last entry.
+  entry = table_.LookupEntry(98);
+  EXPECT_EQ("x-frame-options", entry->name());
+  EXPECT_EQ("sameorigin", entry->value());
 
-  entry = table_.LookupEntry(62);
+  assert(QUIC_ARRAYSIZE(kQpackStaticTable) == 99);
+  entry = table_.LookupEntry(99);
   EXPECT_FALSE(entry);
 }
 
@@ -39,38 +44,38 @@
   QpackHeaderTable::MatchType matchtype =
       table_.FindHeaderField(":method", "GET", &index);
   EXPECT_EQ(QpackHeaderTable::MatchType::kNameAndValue, matchtype);
-  EXPECT_EQ(2u, index);
+  EXPECT_EQ(17u, index);
 
   matchtype = table_.FindHeaderField(":method", "POST", &index);
   EXPECT_EQ(QpackHeaderTable::MatchType::kNameAndValue, matchtype);
-  EXPECT_EQ(3u, index);
+  EXPECT_EQ(20u, index);
 
-  matchtype = table_.FindHeaderField(":method", "CONNECT", &index);
+  matchtype = table_.FindHeaderField(":method", "TRACE", &index);
   EXPECT_EQ(QpackHeaderTable::MatchType::kName, matchtype);
-  EXPECT_EQ(2u, index);
+  EXPECT_EQ(15u, index);
 
   // A header name that has a single entry with non-empty value.
   matchtype =
-      table_.FindHeaderField("accept-encoding", "gzip, deflate", &index);
+      table_.FindHeaderField("accept-encoding", "gzip, deflate, br", &index);
   EXPECT_EQ(QpackHeaderTable::MatchType::kNameAndValue, matchtype);
-  EXPECT_EQ(16u, index);
+  EXPECT_EQ(31u, index);
 
-  matchtype = table_.FindHeaderField("accept-encoding", "brotli", &index);
+  matchtype = table_.FindHeaderField("accept-encoding", "compress", &index);
   EXPECT_EQ(QpackHeaderTable::MatchType::kName, matchtype);
-  EXPECT_EQ(16u, index);
+  EXPECT_EQ(31u, index);
 
   matchtype = table_.FindHeaderField("accept-encoding", "", &index);
   EXPECT_EQ(QpackHeaderTable::MatchType::kName, matchtype);
-  EXPECT_EQ(16u, index);
+  EXPECT_EQ(31u, index);
 
   // A header name that has a single entry with empty value.
-  matchtype = table_.FindHeaderField("cache-control", "", &index);
+  matchtype = table_.FindHeaderField("location", "", &index);
   EXPECT_EQ(QpackHeaderTable::MatchType::kNameAndValue, matchtype);
-  EXPECT_EQ(24u, index);
+  EXPECT_EQ(12u, index);
 
-  matchtype = table_.FindHeaderField("cache-control", "foo", &index);
+  matchtype = table_.FindHeaderField("location", "foo", &index);
   EXPECT_EQ(QpackHeaderTable::MatchType::kName, matchtype);
-  EXPECT_EQ(24u, index);
+  EXPECT_EQ(12u, index);
 
   // No matching header name.
   matchtype = table_.FindHeaderField("foo", "", &index);
diff --git a/net/third_party/quic/core/qpack/qpack_static_table.cc b/net/third_party/quic/core/qpack/qpack_static_table.cc
new file mode 100644
index 0000000..87d3c231
--- /dev/null
+++ b/net/third_party/quic/core/qpack/qpack_static_table.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quic/core/qpack/qpack_static_table.h"
+#include "net/third_party/quic/platform/api/quic_arraysize.h"
+#include "net/third_party/quic/platform/api/quic_logging.h"
+#include "net/third_party/quic/platform/api/quic_ptr_util.h"
+
+namespace quic {
+
+// The "constructor" for a QpackStaticEntry that computes the lengths at
+// compile time.
+#define STATIC_ENTRY(name, value) \
+  { name, QUIC_ARRAYSIZE(name) - 1, value, QUIC_ARRAYSIZE(value) - 1 }
+
+const QpackStaticEntry kQpackStaticTable[] = {
+    STATIC_ENTRY(":authority", ""),                                     // 0
+    STATIC_ENTRY(":path", "/"),                                         // 1
+    STATIC_ENTRY("age", "0"),                                           // 2
+    STATIC_ENTRY("content-disposition", ""),                            // 3
+    STATIC_ENTRY("content-length", "0"),                                // 4
+    STATIC_ENTRY("cookie", ""),                                         // 5
+    STATIC_ENTRY("date", ""),                                           // 6
+    STATIC_ENTRY("etag", ""),                                           // 7
+    STATIC_ENTRY("if-modified-since", ""),                              // 8
+    STATIC_ENTRY("if-none-match", ""),                                  // 9
+    STATIC_ENTRY("last-modified", ""),                                  // 10
+    STATIC_ENTRY("link", ""),                                           // 11
+    STATIC_ENTRY("location", ""),                                       // 12
+    STATIC_ENTRY("referer", ""),                                        // 13
+    STATIC_ENTRY("set-cookie", ""),                                     // 14
+    STATIC_ENTRY(":method", "CONNECT"),                                 // 15
+    STATIC_ENTRY(":method", "DELETE"),                                  // 16
+    STATIC_ENTRY(":method", "GET"),                                     // 17
+    STATIC_ENTRY(":method", "HEAD"),                                    // 18
+    STATIC_ENTRY(":method", "OPTIONS"),                                 // 19
+    STATIC_ENTRY(":method", "POST"),                                    // 20
+    STATIC_ENTRY(":method", "PUT"),                                     // 21
+    STATIC_ENTRY(":scheme", "http"),                                    // 22
+    STATIC_ENTRY(":scheme", "https"),                                   // 23
+    STATIC_ENTRY(":status", "103"),                                     // 24
+    STATIC_ENTRY(":status", "200"),                                     // 25
+    STATIC_ENTRY(":status", "304"),                                     // 26
+    STATIC_ENTRY(":status", "404"),                                     // 27
+    STATIC_ENTRY(":status", "503"),                                     // 28
+    STATIC_ENTRY("accept", "*/*"),                                      // 29
+    STATIC_ENTRY("accept", "application/dns-message"),                  // 30
+    STATIC_ENTRY("accept-encoding", "gzip, deflate, br"),               // 31
+    STATIC_ENTRY("accept-ranges", "bytes"),                             // 32
+    STATIC_ENTRY("access-control-allow-headers", "cache-control"),      // 33
+    STATIC_ENTRY("access-control-allow-headers", "content-type"),       // 35
+    STATIC_ENTRY("access-control-allow-origin", "*"),                   // 35
+    STATIC_ENTRY("cache-control", "max-age=0"),                         // 36
+    STATIC_ENTRY("cache-control", "max-age=2592000"),                   // 37
+    STATIC_ENTRY("cache-control", "max-age=604800"),                    // 38
+    STATIC_ENTRY("cache-control", "no-cache"),                          // 39
+    STATIC_ENTRY("cache-control", "no-store"),                          // 40
+    STATIC_ENTRY("cache-control", "public, max-age=31536000"),          // 41
+    STATIC_ENTRY("content-encoding", "br"),                             // 42
+    STATIC_ENTRY("content-encoding", "gzip"),                           // 43
+    STATIC_ENTRY("content-type", "application/dns-message"),            // 44
+    STATIC_ENTRY("content-type", "application/javascript"),             // 45
+    STATIC_ENTRY("content-type", "application/json"),                   // 46
+    STATIC_ENTRY("content-type", "application/x-www-form-urlencoded"),  // 47
+    STATIC_ENTRY("content-type", "image/gif"),                          // 48
+    STATIC_ENTRY("content-type", "image/jpeg"),                         // 49
+    STATIC_ENTRY("content-type", "image/png"),                          // 50
+    STATIC_ENTRY("content-type", "text/css"),                           // 51
+    STATIC_ENTRY("content-type", "text/html; charset=utf-8"),           // 52
+    STATIC_ENTRY("content-type", "text/plain"),                         // 53
+    STATIC_ENTRY("content-type", "text/plain;charset=utf-8"),           // 54
+    STATIC_ENTRY("range", "bytes=0-"),                                  // 55
+    STATIC_ENTRY("strict-transport-security", "max-age=31536000"),      // 56
+    STATIC_ENTRY("strict-transport-security",
+                 "max-age=31536000; includesubdomains"),  // 57
+    STATIC_ENTRY("strict-transport-security",
+                 "max-age=31536000; includesubdomains; preload"),        // 58
+    STATIC_ENTRY("vary", "accept-encoding"),                             // 59
+    STATIC_ENTRY("vary", "origin"),                                      // 60
+    STATIC_ENTRY("x-content-type-options", "nosniff"),                   // 61
+    STATIC_ENTRY("x-xss-protection", "1; mode=block"),                   // 62
+    STATIC_ENTRY(":status", "100"),                                      // 63
+    STATIC_ENTRY(":status", "204"),                                      // 64
+    STATIC_ENTRY(":status", "206"),                                      // 65
+    STATIC_ENTRY(":status", "302"),                                      // 66
+    STATIC_ENTRY(":status", "400"),                                      // 67
+    STATIC_ENTRY(":status", "403"),                                      // 68
+    STATIC_ENTRY(":status", "421"),                                      // 69
+    STATIC_ENTRY(":status", "425"),                                      // 70
+    STATIC_ENTRY(":status", "500"),                                      // 71
+    STATIC_ENTRY("accept-language", ""),                                 // 72
+    STATIC_ENTRY("access-control-allow-credentials", "FALSE"),           // 73
+    STATIC_ENTRY("access-control-allow-credentials", "TRUE"),            // 74
+    STATIC_ENTRY("access-control-allow-headers", "*"),                   // 75
+    STATIC_ENTRY("access-control-allow-methods", "get"),                 // 76
+    STATIC_ENTRY("access-control-allow-methods", "get, post, options"),  // 77
+    STATIC_ENTRY("access-control-allow-methods", "options"),             // 78
+    STATIC_ENTRY("access-control-expose-headers", "content-length"),     // 79
+    STATIC_ENTRY("access-control-request-headers", "content-type"),      // 80
+    STATIC_ENTRY("access-control-request-method", "get"),                // 81
+    STATIC_ENTRY("access-control-request-method", "post"),               // 82
+    STATIC_ENTRY("alt-svc", "clear"),                                    // 83
+    STATIC_ENTRY("authorization", ""),                                   // 84
+    STATIC_ENTRY(
+        "content-security-policy",
+        "script-src 'none'; object-src 'none'; base-uri 'none'"),  // 85
+    STATIC_ENTRY("early-data", "1"),                               // 86
+    STATIC_ENTRY("expect-ct", ""),                                 // 87
+    STATIC_ENTRY("forwarded", ""),                                 // 88
+    STATIC_ENTRY("if-range", ""),                                  // 89
+    STATIC_ENTRY("origin", ""),                                    // 90
+    STATIC_ENTRY("purpose", "prefetch"),                           // 91
+    STATIC_ENTRY("server", ""),                                    // 92
+    STATIC_ENTRY("timing-allow-origin", "*"),                      // 93
+    STATIC_ENTRY("upgrade-insecure-requests", "1"),                // 94
+    STATIC_ENTRY("user-agent", ""),                                // 95
+    STATIC_ENTRY("x-forwarded-for", ""),                           // 96
+    STATIC_ENTRY("x-frame-options", "deny"),                       // 97
+    STATIC_ENTRY("x-frame-options", "sameorigin"),                 // 98
+};
+
+#undef STATIC_ENTRY
+
+namespace {
+
+QpackStaticTable* InitializeSharedStaticTable() {
+  auto shared_static_table = new QpackStaticTable();
+  shared_static_table->Initialize(kQpackStaticTable,
+                                  QUIC_ARRAYSIZE(kQpackStaticTable));
+  CHECK(shared_static_table->IsInitialized());
+  return shared_static_table;
+}
+
+}  // namespace
+
+const QpackStaticTable& ObtainQpackStaticTable() {
+  static QpackStaticTable* shared_static_table = InitializeSharedStaticTable();
+  return *shared_static_table;
+}
+
+}  // namespace quic
diff --git a/net/third_party/quic/core/qpack/qpack_static_table.h b/net/third_party/quic/core/qpack/qpack_static_table.h
new file mode 100644
index 0000000..2ce27635
--- /dev/null
+++ b/net/third_party/quic/core/qpack/qpack_static_table.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_THIRD_PARTY_QUIC_CORE_QPACK_QPACK_STATIC_TABLE_H_
+#define NET_THIRD_PARTY_QUIC_CORE_QPACK_QPACK_STATIC_TABLE_H_
+
+#include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/spdy/core/hpack/hpack_constants.h"
+#include "net/third_party/spdy/core/hpack/hpack_static_table.h"
+
+namespace quic {
+
+using QpackStaticEntry = spdy::HpackStaticEntry;
+using QpackStaticTable = spdy::HpackStaticTable;
+
+// QPACK static table defined at
+// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#static-table.
+QUIC_EXPORT_PRIVATE extern const QpackStaticEntry kQpackStaticTable[99];
+
+// Returns a QpackStaticTable instance initialized with kQpackStaticTable.
+// The instance is read-only, has static lifetime, and is safe to share amoung
+// threads. This function is thread-safe.
+QUIC_EXPORT_PRIVATE const QpackStaticTable& ObtainQpackStaticTable();
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_CORE_QPACK_QPACK_STATIC_TABLE_H_
diff --git a/net/third_party/quic/core/qpack/qpack_static_table_test.cc b/net/third_party/quic/core/qpack/qpack_static_table_test.cc
new file mode 100644
index 0000000..7bcecaed
--- /dev/null
+++ b/net/third_party/quic/core/qpack/qpack_static_table_test.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quic/core/qpack/qpack_static_table.h"
+
+#include <set>
+
+#include "net/third_party/quic/platform/api/quic_arraysize.h"
+#include "net/third_party/quic/platform/api/quic_string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace quic {
+
+namespace test {
+
+namespace {
+
+// Check that an initialized instance has the right number of entries.
+TEST(QpackStaticTableTest, Initialize) {
+  QpackStaticTable table;
+  EXPECT_FALSE(table.IsInitialized());
+
+  table.Initialize(kQpackStaticTable, QUIC_ARRAYSIZE(kQpackStaticTable));
+  EXPECT_TRUE(table.IsInitialized());
+
+  auto static_entries = table.GetStaticEntries();
+  EXPECT_EQ(QUIC_ARRAYSIZE(kQpackStaticTable), static_entries.size());
+
+  auto static_index = table.GetStaticIndex();
+  EXPECT_EQ(QUIC_ARRAYSIZE(kQpackStaticTable), static_index.size());
+
+  auto static_name_index = table.GetStaticNameIndex();
+  std::set<QuicStringPiece> names;
+  for (auto entry : static_index) {
+    names.insert(entry->name());
+  }
+  EXPECT_EQ(names.size(), static_name_index.size());
+}
+
+// Test that ObtainQpackStaticTable returns the same instance every time.
+TEST(QpackStaticTableTest, IsSingleton) {
+  const QpackStaticTable* static_table_one = &ObtainQpackStaticTable();
+  const QpackStaticTable* static_table_two = &ObtainQpackStaticTable();
+  EXPECT_EQ(static_table_one, static_table_two);
+}
+
+}  // namespace
+
+}  // namespace test
+
+}  // namespace quic
diff --git a/net/third_party/quic/core/quic_connection.cc b/net/third_party/quic/core/quic_connection.cc
index 1e3f680..2ccb844 100644
--- a/net/third_party/quic/core/quic_connection.cc
+++ b/net/third_party/quic/core/quic_connection.cc
@@ -801,7 +801,7 @@
     return false;
   }
 
-  // Initialize the current packet content stats.
+  // Initialize the current packet content state.
   current_packet_content_ = NO_FRAMES_RECEIVED;
   is_current_packet_connectivity_probing_ = false;
   current_effective_peer_migration_type_ = NO_CHANGE;
@@ -1156,10 +1156,26 @@
 }
 
 bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
+  // Save the path challenge's payload, for later use in generating the
+  // response.
+  received_path_challenge_payloads_.push_back(frame.data_buffer);
+
+  // For VERSION 99 we define a "Padded PATH CHALLENGE" to be the same thing
+  // as a PADDED PING -- it will start a connectivity check and prevent
+  // connection migration. Insofar as the connectivity check and connection
+  // migration are concerned, logically the PATH CHALLENGE is the same as the
+  // PING, so as a stopgap, tell the FSM that determines whether we have a
+  // Padded PING or not that we received a PING.
+  UpdatePacketContent(FIRST_FRAME_IS_PING);
   return true;
 }
 
 bool QuicConnection::OnPathResponseFrame(const QuicPathResponseFrame& frame) {
+  if (transmitted_connectivity_probe_payload_ != frame.data_buffer) {
+    // Is not for the probe we sent, ignore it.
+    return true;
+  }
+  UpdatePacketContent(FIRST_FRAME_IS_PING);
   return true;
 }
 
@@ -1315,6 +1331,8 @@
     visitor_->OnConnectivityProbeReceived(last_packet_destination_address_,
                                           last_packet_source_address_);
   } else if (IsCurrentPacketConnectivityProbing()) {
+    // This node is not a client (is a server) AND the received packet was
+    // connectivity-probing, send an appropriate response.
     QUIC_DVLOG(1) << ENDPOINT << "Received a connectivity probing packet for "
                   << last_header_.destination_connection_id
                   << " from ip:port: " << last_packet_source_address_.ToString()
@@ -1323,6 +1341,21 @@
     visitor_->OnConnectivityProbeReceived(last_packet_destination_address_,
                                           last_packet_source_address_);
   } else {
+    // This node is not a client (is a server) AND the received packet was
+    // NOT connectivity-probing. If the packet had PATH CHALLENGES, send
+    // appropriate RESPONSE. Then deal with possible peer migration.
+    if (transport_version() == QUIC_VERSION_99 &&
+        !received_path_challenge_payloads_.empty()) {
+      // If a PATH CHALLENGE was in a "Padded PING (or PATH CHALLENGE)"
+      // then it is taken care of above. This handles the case where a PATH
+      // CHALLENGE appeared someplace else (eg, the peer randomly added a PATH
+      // CHALLENGE frame to some other packet.
+      // There was at least one PATH CHALLENGE in the received packet,
+      // Generate the required PATH RESPONSE.
+      SendGenericPathProbePacket(nullptr, last_packet_source_address_,
+                                 /* is_response= */ true);
+    }
+
     if (last_header_.packet_number ==
         received_packet_manager_.GetLargestObserved()) {
       direct_peer_address_ = last_packet_source_address_;
@@ -2978,6 +3011,20 @@
 bool QuicConnection::SendConnectivityProbingPacket(
     QuicPacketWriter* probing_writer,
     const QuicSocketAddress& peer_address) {
+  return SendGenericPathProbePacket(probing_writer, peer_address,
+                                    /* is_response= */ false);
+}
+
+void QuicConnection::SendConnectivityProbingResponsePacket(
+    const QuicSocketAddress& peer_address) {
+  SendGenericPathProbePacket(nullptr, peer_address,
+                             /* is_response= */ true);
+}
+
+bool QuicConnection::SendGenericPathProbePacket(
+    QuicPacketWriter* probing_writer,
+    const QuicSocketAddress& peer_address,
+    bool is_response) {
   DCHECK(peer_address.IsInitialized());
   if (!connected_) {
     QUIC_BUG << "Not sending connectivity probing packet as connection is "
@@ -2985,14 +3032,15 @@
     return false;
   }
   if (perspective_ == Perspective::IS_SERVER && probing_writer == nullptr) {
-    // Server can use default packet writer to write probing packet.
+    // Server can use default packet writer to write packet.
     probing_writer = writer_;
   }
   DCHECK(probing_writer);
 
   if (probing_writer->IsWriteBlocked()) {
-    QUIC_DLOG(INFO) << ENDPOINT
-                    << "Writer blocked when send connectivity probing packet.";
+    QUIC_DLOG(INFO)
+        << ENDPOINT
+        << "Writer blocked when sending connectivity probing packet.";
     if (probing_writer == writer_) {
       // Visitor should not be write blocked if the probing writer is not the
       // default packet writer.
@@ -3001,11 +3049,42 @@
     return true;
   }
 
-  QUIC_DLOG(INFO) << ENDPOINT << "Sending connectivity probing packet for "
-                  << "connection_id = " << connection_id_;
+  QUIC_DLOG(INFO) << ENDPOINT
+                  << "Sending path probe packet for connection_id = "
+                  << connection_id_;
 
-  OwningSerializedPacketPointer probing_packet(
-      packet_generator_.SerializeConnectivityProbingPacket());
+  OwningSerializedPacketPointer probing_packet;
+  if (transport_version() != QUIC_VERSION_99) {
+    // Non-IETF QUIC, generate a padded ping regardless of whether this is a
+    // request or a response.
+    probing_packet = packet_generator_.SerializeConnectivityProbingPacket();
+  } else {
+    if (is_response) {
+      // Respond using IETF QUIC PATH_RESPONSE frame
+      if (IsCurrentPacketConnectivityProbing()) {
+        // Pad the response if the request was a google connectivity probe
+        // (padded).
+        probing_packet =
+            packet_generator_.SerializePathResponseConnectivityProbingPacket(
+                received_path_challenge_payloads_, /* is_padded = */ true);
+        received_path_challenge_payloads_.clear();
+      } else {
+        // Do not pad the response if the path challenge was not a google
+        // connectivity probe.
+        probing_packet =
+            packet_generator_.SerializePathResponseConnectivityProbingPacket(
+                received_path_challenge_payloads_,
+                /* is_padded = */ false);
+        received_path_challenge_payloads_.clear();
+      }
+    } else {
+      // Request using IETF QUIC PATH_CHALLENGE frame
+      probing_packet =
+          packet_generator_.SerializePathChallengeConnectivityProbingPacket(
+              &transmitted_connectivity_probe_payload_);
+    }
+  }
+
   DCHECK_EQ(IsRetransmittable(*probing_packet), NO_RETRANSMITTABLE_DATA);
 
   const QuicTime packet_send_time = clock_->Now();
@@ -3215,19 +3294,23 @@
     }
   }
 
-  if (type == SECOND_FRAME_IS_PADDING) {
-    if (current_packet_content_ == FIRST_FRAME_IS_PING) {
-      current_packet_content_ = SECOND_FRAME_IS_PADDING;
-      if (perspective_ == Perspective::IS_SERVER) {
-        is_current_packet_connectivity_probing_ =
-            current_effective_peer_migration_type_ != NO_CHANGE;
-      } else {
-        is_current_packet_connectivity_probing_ =
-            (last_packet_source_address_ != peer_address_) ||
-            (last_packet_destination_address_ != self_address_);
-      }
-      return;
+  // In Google QUIC we look for a packet with just a PING and PADDING.
+  // For IETF QUIC, the packet must consist of just a PATH_CHALLENGE frame,
+  // followed by PADDING. If the condition is met, mark things as
+  // connectivity-probing, causing later processing to generate the correct
+  // response.
+  if (type == SECOND_FRAME_IS_PADDING &&
+      current_packet_content_ == FIRST_FRAME_IS_PING) {
+    current_packet_content_ = SECOND_FRAME_IS_PADDING;
+    if (perspective_ == Perspective::IS_SERVER) {
+      is_current_packet_connectivity_probing_ =
+          current_effective_peer_migration_type_ != NO_CHANGE;
+    } else {
+      is_current_packet_connectivity_probing_ =
+          (last_packet_source_address_ != peer_address_) ||
+          (last_packet_destination_address_ != self_address_);
     }
+    return;
   }
 
   current_packet_content_ = NOT_PADDED_PING;
diff --git a/net/third_party/quic/core/quic_connection.h b/net/third_party/quic/core/quic_connection.h
index 51b1d98..a586cd4 100644
--- a/net/third_party/quic/core/quic_connection.h
+++ b/net/third_party/quic/core/quic_connection.h
@@ -701,11 +701,19 @@
   // Sends a connectivity probing packet to |peer_address| with
   // |probing_writer|. If |probing_writer| is nullptr, will use default
   // packet writer to write the packet. Returns true if subsequent packets can
-  // be written to the probing writer.
+  // be written to the probing writer. If connection is V99, a padded IETF QUIC
+  // PATH_CHALLENGE packet is transmitted; if not V99, a Google QUIC padded PING
+  // packet is transmitted.
   virtual bool SendConnectivityProbingPacket(
       QuicPacketWriter* probing_writer,
       const QuicSocketAddress& peer_address);
 
+  // Sends response to a connectivity probe. Sends either a Padded Ping
+  // or an IETF PATH_RESPONSE based on the version of the connection.
+  // Is the counterpart to SendConnectivityProbingPacket().
+  virtual void SendConnectivityProbingResponsePacket(
+      const QuicSocketAddress& peer_address);
+
   // Sends an MTU discovery packet of size |mtu_discovery_target_| and updates
   // the MTU discovery alarm.
   void DiscoverMtu();
@@ -888,6 +896,9 @@
 
   enum PacketContent : uint8_t {
     NO_FRAMES_RECEIVED,
+    // TODO(fkastenholz): Change name when we get rid of padded ping/
+    // pre-version-99.
+    // Also PATH CHALLENGE and PATH RESPONSE.
     FIRST_FRAME_IS_PING,
     SECOND_FRAME_IS_PADDING,
     NOT_PADDED_PING,  // Set if the packet is not {PING, PADDING}.
@@ -999,7 +1010,7 @@
   void CheckIfApplicationLimited();
 
   // Sets |current_packet_content_| to |type| if applicable. And
-  // starts effective peer miration if current packet is confirmed not a
+  // starts effective peer migration if current packet is confirmed not a
   // connectivity probe and |current_effective_peer_migration_type_| indicates
   // effective peer address change.
   void UpdatePacketContent(PacketContent type);
@@ -1019,6 +1030,14 @@
   // Updates the release time into the future.
   void UpdateReleaseTimeIntoFuture();
 
+  // Sends generic path probe packet to the peer. If we are not IETF QUIC, will
+  // always send a padded ping, regardless of whether this is a request or
+  // response. If version 99/ietf quic, will send a PATH_RESPONSE if
+  // |is_response| is true, a PATH_CHALLENGE if not.
+  bool SendGenericPathProbePacket(QuicPacketWriter* probing_writer,
+                                  const QuicSocketAddress& peer_address,
+                                  bool is_response);
+
   QuicFramer framer_;
 
   // Contents received in the current packet, especially used to identify
@@ -1029,6 +1048,7 @@
   // true as soon as |current_packet_content_| is set to
   // SECOND_FRAME_IS_PADDING.
   bool is_current_packet_connectivity_probing_;
+
   // Caches the current effective peer migration type if a effective peer
   // migration might be initiated. As soon as the current packet is confirmed
   // not a connectivity probe, effective peer migration will start.
@@ -1340,6 +1360,18 @@
 
   // Latched value of quic_reloadable_flag_quic_decrypt_packets_on_key_change.
   const bool decrypt_packets_on_key_change_;
+
+  // Payload of most recently transmitted QUIC_VERSION_99 connectivity
+  // probe packet (the PATH_CHALLENGE payload). This implementation transmits
+  // only one PATH_CHALLENGE per connectivity probe, so only one
+  // QuicPathFrameBuffer is needed.
+  QuicPathFrameBuffer transmitted_connectivity_probe_payload_;
+
+  // Payloads that were received in the most recent probe. This needs to be a
+  // Deque because the peer might no be using this implementation, and others
+  // might send a packet with more than one PATH_CHALLENGE, so all need to be
+  // saved and responded to.
+  QuicDeque<QuicPathFrameBuffer> received_path_challenge_payloads_;
 };
 
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_connection_test.cc b/net/third_party/quic/core/quic_connection_test.cc
index b05726c5..87eb696b 100644
--- a/net/third_party/quic/core/quic_connection_test.cc
+++ b/net/third_party/quic/core/quic_connection_test.cc
@@ -436,6 +436,14 @@
     return framer_.padding_frames();
   }
 
+  const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const {
+    return framer_.path_challenge_frames();
+  }
+
+  const std::vector<QuicPathResponseFrame>& path_response_frames() const {
+    return framer_.path_response_frames();
+  }
+
   size_t last_packet_size() { return last_packet_size_; }
 
   const QuicPacketHeader& last_packet_header() const {
@@ -873,7 +881,7 @@
 
     EXPECT_CALL(*loss_algorithm_, GetLossTimeout())
         .WillRepeatedly(Return(QuicTime::Zero()));
-    EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+    EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
         .Times(AnyNumber());
   }
 
@@ -1134,6 +1142,18 @@
     return ConstructPacket(header, frames);
   }
 
+  OwningSerializedPacketPointer ConstructProbingPacket() {
+    if (version().transport_version == QUIC_VERSION_99) {
+      QuicPathFrameBuffer payload = {
+          {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
+      return QuicPacketCreatorPeer::
+          SerializePathChallengeConnectivityProbingPacket(&peer_creator_,
+                                                          &payload);
+    }
+    return QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
+        &peer_creator_);
+  }
+
   std::unique_ptr<QuicPacket> ConstructClosePacket(QuicPacketNumber number) {
     QuicPacketHeader header;
     // Set connection_id to peer's in memory representation as this connection
@@ -1540,11 +1560,19 @@
   EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
   EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(0);
 
-  // Process a padded PING packet with no peer address change on server side
-  // will be ignored.
-  OwningSerializedPacketPointer probing_packet(
-      QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
-          &peer_creator_));
+  // Process a padded PING or PATH CHALLENGE packet with no peer address change
+  // on server side will be ignored.
+  OwningSerializedPacketPointer probing_packet;
+  if (version().transport_version == QUIC_VERSION_99) {
+    QuicPathFrameBuffer payload = {
+        {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
+    probing_packet =
+        QuicPacketCreatorPeer::SerializePathChallengeConnectivityProbingPacket(
+            &peer_creator_, &payload);
+  } else {
+    probing_packet = QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
+        &peer_creator_);
+  }
   std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
@@ -1640,9 +1668,7 @@
   const QuicSocketAddress kNewPeerAddress =
       QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
 
-  OwningSerializedPacketPointer probing_packet(
-      QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
-          &peer_creator_));
+  OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
   std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
@@ -1699,9 +1725,7 @@
   const QuicSocketAddress kNewPeerAddress =
       QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
 
-  OwningSerializedPacketPointer probing_packet(
-      QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
-          &peer_creator_));
+  OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
   std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
@@ -1745,9 +1769,7 @@
   const QuicSocketAddress kNewPeerAddress =
       QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
 
-  OwningSerializedPacketPointer probing_packet(
-      QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
-          &peer_creator_));
+  OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
   std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
@@ -1793,9 +1815,7 @@
   EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
   EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1);
 
-  OwningSerializedPacketPointer probing_packet(
-      QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
-          &peer_creator_));
+  OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
   std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
@@ -1837,9 +1857,7 @@
   const QuicSocketAddress kNewSelfAddress =
       QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
 
-  OwningSerializedPacketPointer probing_packet(
-      QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
-          &peer_creator_));
+  OwningSerializedPacketPointer probing_packet = ConstructProbingPacket();
   std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
       QuicEncryptedPacket(probing_packet->encrypted_buffer,
                           probing_packet->encrypted_length),
@@ -2153,8 +2171,8 @@
   // First nack triggers early retransmit.
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(original, kMaxPacketSize));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   QuicPacketNumber retransmission;
   // Packet 1 is short header for IETF QUIC because the encryption level
@@ -2172,7 +2190,7 @@
 
   QuicAckFrame frame2 = ConstructAckFrame(retransmission, original);
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
   ProcessAckPacket(&frame2);
 
   // Now if the peer sends an ack which still reports the retransmitted packet
@@ -2186,7 +2204,8 @@
   EXPECT_EQ(1u, writer_->stream_frames().size());
 
   // No more packet loss for the rest of the test.
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _)).Times(AnyNumber());
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .Times(AnyNumber());
   ProcessAckPacket(&frame2);
   EXPECT_CALL(*send_algorithm_,
               OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA));
@@ -2777,8 +2796,8 @@
   QuicAckFrame nack_two = ConstructAckFrame(3, 2);
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(2, kMaxPacketSize));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
   EXPECT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(creator_));
@@ -2845,7 +2864,7 @@
   // Lose a packet and ensure it does not trigger retransmission.
   QuicAckFrame nack_two = ConstructAckFrame(last_packet, last_packet - 1);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
   ProcessAckPacket(&nack_two);
@@ -2866,8 +2885,8 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(last_packet - 1, kMaxPacketSize));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
   ProcessAckPacket(&nack_two);
@@ -2954,7 +2973,7 @@
   // Lose a packet which will trigger a pending retransmission.
   QuicAckFrame ack = ConstructAckFrame(last_packet, last_packet - 1);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
   ProcessAckPacket(&ack);
@@ -2989,8 +3008,8 @@
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(last_packet - 1, kMaxPacketSize));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
   ProcessAckPacket(&ack);
@@ -3026,14 +3045,14 @@
 
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(2, kMaxPacketSize));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   ProcessAckPacket(&nack_two);
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
 
   // Now, ack the previous transmission.
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(false, _, _, _, _));
   QuicAckFrame ack_all = InitAckFrame(3);
   ProcessAckPacket(&ack_all);
@@ -3062,8 +3081,8 @@
   // The first nack should retransmit the largest observed packet.
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(original, kMaxPacketSize));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   // Packet 1 is short header for IETF QUIC because the encryption level
   // switched to ENCRYPTION_FORWARD_SECURE in SendStreamDataToPeer.
@@ -3245,8 +3264,8 @@
   for (int i = 1; i < 15; ++i) {
     lost_packets.push_back(LostPacket(i, kMaxPacketSize));
   }
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   if (connection_.session_decides_what_to_write()) {
     EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
@@ -5806,8 +5825,8 @@
   QuicAckFrame ack = ConstructAckFrame(2, 1);
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(1, kMaxPacketSize));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   ProcessAckPacket(&ack);
   EXPECT_EQ(1u, writer_->frame_count());
@@ -5817,7 +5836,7 @@
   // Now ack the retransmission, which will both raise the high water mark
   // and see if there is more data to send.
   ack = ConstructAckFrame(3, 1);
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   ProcessAckPacket(&ack);
 
@@ -5828,7 +5847,7 @@
 
   // Send the same ack, but send both data and an ack together.
   ack = ConstructAckFrame(3, 1);
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
   EXPECT_CALL(visitor_, OnCanWrite())
       .WillOnce(IgnoreResult(InvokeWithoutArgs(
           &connection_, &TestConnection::EnsureWritableAndSendStreamData5)));
@@ -6268,8 +6287,8 @@
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(1, kMaxPacketSize));
   lost_packets.push_back(LostPacket(3, kMaxPacketSize));
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
-      .WillOnce(SetArgPointee<4>(lost_packets));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
+      .WillOnce(SetArgPointee<5>(lost_packets));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   if (!connection_.session_decides_what_to_write()) {
     EXPECT_CALL(visitor_, OnCanWrite());
@@ -6491,7 +6510,7 @@
 
   // Process an ack and the send alarm will be set to the new 5ms delay.
   QuicAckFrame ack = InitAckFrame(1);
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true));
   ProcessAckPacket(&ack);
@@ -7048,7 +7067,7 @@
   // Acknowledge all packets sent, except for the last one.
   QuicAckFrame ack = InitAckFrame(
       connection_.sent_packet_manager().GetLargestSentPacket() - 1);
-  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
 
   // Ensure that since we no longer have retransmittable bytes in flight, this
@@ -7412,6 +7431,51 @@
                              connection_.GetLargestMessagePayload() + 1)));
 }
 
+// Test to check that the path challenge/path response logic works
+// correctly. This test is only for version-99
+TEST_P(QuicConnectionTest, PathChallengeResponse) {
+  if (connection_.version().transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  // First check if we can probe from server to client and back
+  set_perspective(Perspective::IS_SERVER);
+  QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+
+  // Create and send the probe request (PATH_CHALLENGE frame).
+  // SendConnectivityProbingPacket ends up calling
+  // TestPacketWriter::WritePacket() which in turns receives and parses the
+  // packet by calling framer_.ProcessPacket() -- which in turn calls
+  // SimpleQuicFramer::OnPathChallengeFrame(). SimpleQuicFramer saves
+  // the packet in writer_->path_challenge_frames()
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+  connection_.SendConnectivityProbingPacket(writer_.get(),
+                                            connection_.peer_address());
+  // Save the random contents of the challenge for later comparison to the
+  // response.
+  QuicPathFrameBuffer challenge_data =
+      writer_->path_challenge_frames().front().data_buffer;
+
+  // Normally, QuicConnection::OnPathChallengeFrame and OnPaddingFrame would be
+  // called and it will perform actions to ensure that the rest of the protocol
+  // is performed (specifically, call UpdatePacketContent to say that this is a
+  // path challenge so that when QuicConnection::OnPacketComplete is called
+  // (again, out of the framer), the response is generated).  Simulate those
+  // calls so that the right internal state is set up for generating
+  // the response.
+  EXPECT_TRUE(connection_.OnPathChallengeFrame(
+      writer_->path_challenge_frames().front()));
+  EXPECT_TRUE(connection_.OnPaddingFrame(writer_->padding_frames().front()));
+  // Cause the response to be created and sent. Result is that the response
+  // should be stashed in writer's path_response_frames.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+  connection_.SendConnectivityProbingResponsePacket(connection_.peer_address());
+
+  // The final check is to ensure that the random data in the response matches
+  // the random data from the challenge.
+  EXPECT_EQ(0, memcmp(&challenge_data,
+                      &(writer_->path_response_frames().front().data_buffer),
+                      sizeof(challenge_data)));
+}
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_constants.h b/net/third_party/quic/core/quic_constants.h
index 3e88798..0d398aaf 100644
--- a/net/third_party/quic/core/quic_constants.h
+++ b/net/third_party/quic/core/quic_constants.h
@@ -220,6 +220,9 @@
 // Maximum length allowed for the token in a NEW_TOKEN frame.
 const size_t kMaxNewTokenTokenLength = 0xffff;
 
+// Used to represent an invalid packet number.
+const QuicPacketNumber kInvalidPacketNumber = 0;
+
 }  // namespace quic
 
 #endif  // NET_THIRD_PARTY_QUIC_CORE_QUIC_CONSTANTS_H_
diff --git a/net/third_party/quic/core/quic_dispatcher.cc b/net/third_party/quic/core/quic_dispatcher.cc
index 9123edbc..ff16c8ce 100644
--- a/net/third_party/quic/core/quic_dispatcher.cc
+++ b/net/third_party/quic/core/quic_dispatcher.cc
@@ -489,7 +489,6 @@
   }
 
   // initial packet number of 0 is always invalid.
-  const int kInvalidPacketNumber = 0;
   if (header.packet_number == kInvalidPacketNumber) {
     return kFateTimeWait;
   }
diff --git a/net/third_party/quic/core/quic_dispatcher_test.cc b/net/third_party/quic/core/quic_dispatcher_test.cc
index def0939b..983e977b 100644
--- a/net/third_party/quic/core/quic_dispatcher_test.cc
+++ b/net/third_party/quic/core/quic_dispatcher_test.cc
@@ -638,12 +638,13 @@
 }
 
 TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_35, false);
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, true);
+  SetQuicReloadableFlag(quic_enable_version_46, true);
   SetQuicFlag(&FLAGS_quic_enable_version_99, true);
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
@@ -696,6 +697,39 @@
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
                 PACKET_4BYTE_PACKET_NUMBER, 1);
 
+  // Turn off version 46.
+  SetQuicReloadableFlag(quic_enable_version_46, false);
+  ++connection_id;
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
+                                              QuicStringPiece("hq")))
+      .Times(0);
+  ProcessPacket(client_address, connection_id, true,
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
+                SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
+                PACKET_4BYTE_PACKET_NUMBER, 1);
+
+  // Turn on version 46.
+  SetQuicReloadableFlag(quic_enable_version_46, true);
+  ++connection_id;
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
+                                              QuicStringPiece("hq")))
+      .WillOnce(testing::Return(CreateSession(
+          dispatcher_.get(), config_, connection_id, client_address,
+          &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+  EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+              ProcessUdpPacket(_, _, _))
+      .WillOnce(WithArg<2>(
+          Invoke([this, connection_id](const QuicEncryptedPacket& packet) {
+            ValidatePacket(connection_id, packet);
+          })));
+  EXPECT_CALL(*dispatcher_,
+              ShouldCreateOrBufferPacketForConnection(connection_id));
+  ProcessPacket(client_address, connection_id, true,
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
+                SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
+                PACKET_4BYTE_PACKET_NUMBER, 1);
+
   // Turn off version 45.
   SetQuicReloadableFlag(quic_enable_version_45, false);
   ++connection_id;
diff --git a/net/third_party/quic/core/quic_framer.cc b/net/third_party/quic/core/quic_framer.cc
index db71600..48545c5 100644
--- a/net/third_party/quic/core/quic_framer.cc
+++ b/net/third_party/quic/core/quic_framer.cc
@@ -967,6 +967,115 @@
   return writer.length();
 }
 
+size_t QuicFramer::BuildPaddedPathChallengePacket(
+    const QuicPacketHeader& header,
+    char* buffer,
+    size_t packet_length,
+    QuicPathFrameBuffer* payload,
+    QuicRandom* randomizer) {
+  QuicDataWriter writer(packet_length, buffer, endianness());
+  DCHECK_EQ(version_.transport_version, QUIC_VERSION_99)
+      << "Attempt to build a PATH_CHALLENGE Connectivity Probing packet and "
+         "not doing IETF QUIC";
+
+  if (!AppendPacketHeader(header, &writer)) {
+    QUIC_BUG << "AppendPacketHeader failed";
+    return 0;
+  }
+
+  // Write a PATH_CHALLENGE frame, which has a random 8-byte payload
+  randomizer->RandBytes(payload->data(), payload->size());
+
+  QuicPathChallengeFrame path_challenge_frame(0, *payload);
+  if (!AppendTypeByte(QuicFrame(&path_challenge_frame),
+                      /* last_frame_in_packet = */ false, &writer)) {
+    QUIC_BUG
+        << "AppendTypeByte failed for PATH_CHALLENGE frame in probing packet";
+    return 0;
+  }
+
+  if (!AppendPathChallengeFrame(path_challenge_frame, &writer)) {
+    QUIC_BUG << "AppendPathChallengeFrame failed for PATH_CHALLENGE frame in "
+                "probing packet";
+    return 0;
+  }
+
+  // Add padding to the rest of the packet in order to assess Path MTU
+  // characteristics.
+  QuicPaddingFrame padding_frame;
+  if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) {
+    QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet";
+    return 0;
+  }
+  if (!AppendPaddingFrame(padding_frame, &writer)) {
+    QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes
+             << " failed";
+    return 0;
+  }
+
+  return writer.length();
+}
+
+size_t QuicFramer::BuildPathResponsePacket(
+    const QuicPacketHeader& header,
+    char* buffer,
+    size_t packet_length,
+    const QuicDeque<QuicPathFrameBuffer>& payloads,
+    const bool is_padded) {
+  if (payloads.empty()) {
+    QUIC_BUG
+        << "Attempt to generate connectivity response with no request payloads";
+    return 0;
+  }
+
+  QuicDataWriter writer(packet_length, buffer, endianness());
+
+  DCHECK_EQ(version_.transport_version, QUIC_VERSION_99)
+      << "Attempt to build a PATH_RESPONSE Connectivity Probing packet and "
+         "not doing IETF QUIC";
+
+  if (!AppendPacketHeader(header, &writer)) {
+    QUIC_BUG << "AppendPacketHeader failed";
+    return 0;
+  }
+
+  // Write a set of PATH_RESPONSE frames to a single packet, each with the
+  // 8-byte payload of the corresponding PATH_REQUEST frame from a single
+  // received packet.
+  for (const QuicPathFrameBuffer& payload : payloads) {
+    // Note that the control frame ID can be 0 since this is not retransmitted.
+    QuicPathResponseFrame path_response_frame(0, payload);
+
+    if (!AppendTypeByte(QuicFrame(&path_response_frame), false, &writer)) {
+      QUIC_BUG
+          << "AppendTypeByte failed for PATH_RESPONSE frame in probing packet";
+      return 0;
+    }
+
+    if (!AppendPathResponseFrame(path_response_frame, &writer)) {
+      QUIC_BUG << "AppendPathChallengeFrame failed for PATH_CHALLENGE frame in "
+                  "probing packet";
+      return 0;
+    }
+  }
+
+  if (is_padded) {
+    // Add padding to the rest of the packet in order to assess Path MTU
+    // characteristics.
+    QuicPaddingFrame padding_frame;
+    if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) {
+      QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet";
+      return 0;
+    }
+    if (!AppendPaddingFrame(padding_frame, &writer)) {
+      QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes
+               << " failed";
+      return 0;
+    }
+  }
+  return writer.length();
+}
+
 // static
 std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildPublicResetPacket(
     const QuicPublicResetPacket& packet) {
diff --git a/net/third_party/quic/core/quic_framer.h b/net/third_party/quic/core/quic_framer.h
index 3e2f385..bbfe6a6 100644
--- a/net/third_party/quic/core/quic_framer.h
+++ b/net/third_party/quic/core/quic_framer.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "net/third_party/quic/core/crypto/quic_decrypter.h"
 #include "net/third_party/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quic/core/crypto/quic_random.h"
 #include "net/third_party/quic/core/quic_packets.h"
 #include "net/third_party/quic/platform/api/quic_endian.h"
 #include "net/third_party/quic/platform/api/quic_export.h"
@@ -365,6 +366,24 @@
                                         char* buffer,
                                         size_t packet_length);
 
+  // Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also
+  // fills the packet with padding.
+  size_t BuildPaddedPathChallengePacket(const QuicPacketHeader& header,
+                                        char* buffer,
+                                        size_t packet_length,
+                                        QuicPathFrameBuffer* payload,
+                                        QuicRandom* randomizer);
+
+  // Serialize a probing response packet that uses IETF QUIC's PATH RESPONSE
+  // frame. Also fills the packet with padding if |is_padded| is
+  // true. |payloads| is always emptied, even if the packet can not be
+  // successfully built.
+  size_t BuildPathResponsePacket(const QuicPacketHeader& header,
+                                 char* buffer,
+                                 size_t packet_length,
+                                 const QuicDeque<QuicPathFrameBuffer>& payloads,
+                                 const bool is_padded);
+
   // Returns a new public reset packet.
   static std::unique_ptr<QuicEncryptedPacket> BuildPublicResetPacket(
       const QuicPublicResetPacket& packet);
diff --git a/net/third_party/quic/core/quic_framer_test.cc b/net/third_party/quic/core/quic_framer_test.cc
index 04d53624..e696015b 100644
--- a/net/third_party/quic/core/quic_framer_test.cc
+++ b/net/third_party/quic/core/quic_framer_test.cc
@@ -7987,6 +7987,266 @@
                                       data.length(), AsChars(p), packet_size);
 }
 
+// Test that the path challenge connectivity probing packet is serialized
+// correctly as a padded PATH CHALLENGE packet.
+TEST_P(QuicFramerTest, BuildPaddedPathChallengePacket) {
+  if (framer_.transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload;
+
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // Path Challenge Frame type
+    0x0e,
+    // 8 "random" bytes, MockRandom makes lots of r's
+    'r', 'r', 'r', 'r', 'r', 'r', 'r', 'r',
+    // frame type (padding frame)
+    0x00,
+    0x00, 0x00, 0x00, 0x00
+  };
+  // clang-format on
+
+  std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
+  MockRandom randomizer;
+
+  size_t length = framer_.BuildPaddedPathChallengePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), &payload, &randomizer);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+
+  // Payload has the random bytes that were generated. Copy them into packet,
+  // above, before checking that the generated packet is correct.
+  EXPECT_EQ(kQuicPathFrameBufferSize, payload.size());
+
+  QuicPacket data(buffer.release(), length, true,
+                  header.destination_connection_id_length,
+                  header.source_connection_id_length, header.version_flag,
+                  header.nonce != nullptr, header.packet_number_length);
+
+  test::CompareCharArraysWithHexError("constructed packet", data.data(),
+                                      data.length(), AsChars(packet),
+                                      QUIC_ARRAYSIZE(packet));
+}
+
+// Several tests that the path response connectivity probing packet is
+// serialized correctly as either a padded and unpadded PATH RESPONSE
+// packet. Also generates packets with 1 and 3 PATH_RESPONSES in them to
+// exercised the single- and multiple- payload cases.
+TEST_P(QuicFramerTest, BuildPathResponsePacket1ResponseUnpadded) {
+  if (framer_.transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload0 = {
+      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
+
+  // Build 1 PATH RESPONSE, not padded
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // Path Challenge Frame type
+    0x0f,
+    // 8 "random" bytes
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+  };
+  // clang-format on
+  std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
+  QuicDeque<QuicPathFrameBuffer> payloads;
+  payloads.push_back(payload0);
+  size_t length = framer_.BuildPathResponsePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
+      /*is_padded=*/false);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+  QuicPacket data(buffer.release(), length, true,
+                  header.destination_connection_id_length,
+                  header.source_connection_id_length, header.version_flag,
+                  header.nonce != nullptr, header.packet_number_length);
+
+  test::CompareCharArraysWithHexError("constructed packet", data.data(),
+                                      data.length(), AsChars(packet),
+                                      QUIC_ARRAYSIZE(packet));
+}
+
+TEST_P(QuicFramerTest, BuildPathResponsePacket1ResponsePadded) {
+  if (framer_.transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload0 = {
+      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
+
+  // Build 1 PATH RESPONSE, padded
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // Path Challenge Frame type
+    0x0f,
+    // 8 "random" bytes
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    // Padding type and pad
+    0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  // clang-format on
+  std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
+  QuicDeque<QuicPathFrameBuffer> payloads;
+  payloads.push_back(payload0);
+  size_t length = framer_.BuildPathResponsePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
+      /*is_padded=*/true);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+  QuicPacket data(buffer.release(), length, true,
+                  header.destination_connection_id_length,
+                  header.source_connection_id_length, header.version_flag,
+                  header.nonce != nullptr, header.packet_number_length);
+
+  test::CompareCharArraysWithHexError("constructed packet", data.data(),
+                                      data.length(), AsChars(packet),
+                                      QUIC_ARRAYSIZE(packet));
+}
+
+TEST_P(QuicFramerTest, BuildPathResponsePacket3ResponsesUnpadded) {
+  if (framer_.transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload0 = {
+      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
+  QuicPathFrameBuffer payload1 = {
+      {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}};
+  QuicPathFrameBuffer payload2 = {
+      {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}};
+
+  // Build one packet with 3 PATH RESPONSES, no padding
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // 3 path challenge frames (type byte and payload)
+    0x0f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    0x0f, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+    0x0f, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+  };
+  // clang-format on
+
+  std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
+  QuicDeque<QuicPathFrameBuffer> payloads;
+  payloads.push_back(payload0);
+  payloads.push_back(payload1);
+  payloads.push_back(payload2);
+  size_t length = framer_.BuildPathResponsePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
+      /*is_padded=*/false);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+  QuicPacket data(buffer.release(), length, true,
+                  header.destination_connection_id_length,
+                  header.source_connection_id_length, header.version_flag,
+                  header.nonce != nullptr, header.packet_number_length);
+
+  test::CompareCharArraysWithHexError("constructed packet", data.data(),
+                                      data.length(), AsChars(packet),
+                                      QUIC_ARRAYSIZE(packet));
+}
+
+TEST_P(QuicFramerTest, BuildPathResponsePacket3ResponsesPadded) {
+  if (framer_.transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  QuicPacketHeader header;
+  header.destination_connection_id = kConnectionId;
+  header.reset_flag = false;
+  header.version_flag = false;
+  header.packet_number = kPacketNumber;
+  QuicPathFrameBuffer payload0 = {
+      {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}};
+  QuicPathFrameBuffer payload1 = {
+      {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}};
+  QuicPathFrameBuffer payload2 = {
+      {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}};
+
+  // Build one packet with 3 PATH RESPONSES, with padding
+  // clang-format off
+  unsigned char packet[] = {
+    // type (short header, 4 byte packet number)
+    0x32,
+    // connection_id
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+    // packet number
+    0x12, 0x34, 0x56, 0x78,
+
+    // 3 path challenge frames (type byte and payload)
+    0x0f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    0x0f, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+    0x0f, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    // Padding
+    0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  // clang-format on
+
+  std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
+  QuicDeque<QuicPathFrameBuffer> payloads;
+  payloads.push_back(payload0);
+  payloads.push_back(payload1);
+  payloads.push_back(payload2);
+  size_t length = framer_.BuildPathResponsePacket(
+      header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads,
+      /*is_padded=*/true);
+  EXPECT_EQ(length, QUIC_ARRAYSIZE(packet));
+  QuicPacket data(buffer.release(), length, true,
+                  header.destination_connection_id_length,
+                  header.source_connection_id_length, header.version_flag,
+                  header.nonce != nullptr, header.packet_number_length);
+
+  test::CompareCharArraysWithHexError("constructed packet", data.data(),
+                                      data.length(), AsChars(packet),
+                                      QUIC_ARRAYSIZE(packet));
+}
+
 // Test that the MTU discovery packet is serialized correctly as a PING packet.
 TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
   QuicPacketHeader header;
diff --git a/net/third_party/quic/core/quic_packet_creator.cc b/net/third_party/quic/core/quic_packet_creator.cc
index 13882f4..8518c93 100644
--- a/net/third_party/quic/core/quic_packet_creator.cc
+++ b/net/third_party/quic/core/quic_packet_creator.cc
@@ -537,6 +537,8 @@
 
 OwningSerializedPacketPointer
 QuicPacketCreator::SerializeConnectivityProbingPacket() {
+  QUIC_BUG_IF(framer_->transport_version() == QUIC_VERSION_99)
+      << "Must not be version 99 to serialize padded ping connectivity probe";
   QuicPacketHeader header;
   // FillPacketHeader increments packet_number_.
   FillPacketHeader(&header);
@@ -562,6 +564,72 @@
   return serialize_packet;
 }
 
+OwningSerializedPacketPointer
+QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket(
+    QuicPathFrameBuffer* payload) {
+  QUIC_BUG_IF(framer_->transport_version() != QUIC_VERSION_99)
+      << "Must be version 99 to serialize path challenge connectivity probe, "
+         "is version "
+      << framer_->transport_version();
+  QuicPacketHeader header;
+  // FillPacketHeader increments packet_number_.
+  FillPacketHeader(&header);
+
+  std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
+  size_t length = framer_->BuildPaddedPathChallengePacket(
+      header, buffer.get(), max_plaintext_size_, payload,
+      QuicRandom::GetInstance());
+  DCHECK(length);
+
+  const size_t encrypted_length = framer_->EncryptInPlace(
+      packet_.encryption_level, packet_.packet_number,
+      GetStartOfEncryptedData(framer_->transport_version(), header), length,
+      kMaxPacketSize, buffer.get());
+  DCHECK(encrypted_length);
+
+  OwningSerializedPacketPointer serialize_packet(new SerializedPacket(
+      header.packet_number, header.packet_number_length, buffer.release(),
+      encrypted_length, /*has_ack=*/false, /*has_stop_waiting=*/false));
+
+  serialize_packet->encryption_level = packet_.encryption_level;
+  serialize_packet->transmission_type = NOT_RETRANSMISSION;
+
+  return serialize_packet;
+}
+
+OwningSerializedPacketPointer
+QuicPacketCreator::SerializePathResponseConnectivityProbingPacket(
+    const QuicDeque<QuicPathFrameBuffer>& payloads,
+    const bool is_padded) {
+  QUIC_BUG_IF(framer_->transport_version() != QUIC_VERSION_99)
+      << "Must be version 99 to serialize path response connectivity probe, is "
+         "version "
+      << framer_->transport_version();
+  QuicPacketHeader header;
+  // FillPacketHeader increments packet_number_.
+  FillPacketHeader(&header);
+
+  std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]);
+  size_t length = framer_->BuildPathResponsePacket(
+      header, buffer.get(), max_plaintext_size_, payloads, is_padded);
+  DCHECK(length);
+
+  const size_t encrypted_length = framer_->EncryptInPlace(
+      packet_.encryption_level, packet_.packet_number,
+      GetStartOfEncryptedData(framer_->transport_version(), header), length,
+      kMaxPacketSize, buffer.get());
+  DCHECK(encrypted_length);
+
+  OwningSerializedPacketPointer serialize_packet(new SerializedPacket(
+      header.packet_number, header.packet_number_length, buffer.release(),
+      encrypted_length, /*has_ack=*/false, /*has_stop_waiting=*/false));
+
+  serialize_packet->encryption_level = packet_.encryption_level;
+  serialize_packet->transmission_type = NOT_RETRANSMISSION;
+
+  return serialize_packet;
+}
+
 // TODO(b/74062209): Make this a public method of framer?
 SerializedPacket QuicPacketCreator::NoPacket() {
   return SerializedPacket(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false,
diff --git a/net/third_party/quic/core/quic_packet_creator.h b/net/third_party/quic/core/quic_packet_creator.h
index 0530787..523fcbd 100644
--- a/net/third_party/quic/core/quic_packet_creator.h
+++ b/net/third_party/quic/core/quic_packet_creator.h
@@ -168,9 +168,23 @@
       bool ietf_quic,
       const ParsedQuicVersionVector& supported_versions);
 
-  // Creates a connectivity probing packet.
+  // Creates a connectivity probing packet for versions prior to version 99.
   OwningSerializedPacketPointer SerializeConnectivityProbingPacket();
 
+  // Create connectivity probing request and response packets using PATH
+  // CHALLENGE and PATH RESPONSE frames, respectively, for version 99/IETF QUIC.
+  // SerializePathChallengeConnectivityProbingPacket will pad the packet to be
+  // MTU bytes long.
+  OwningSerializedPacketPointer SerializePathChallengeConnectivityProbingPacket(
+      QuicPathFrameBuffer* payload);
+
+  // If |is_padded| is true then SerializePathResponseConnectivityProbingPacket
+  // will pad the packet to be MTU bytes long, else it will not pad the packet.
+  // |payloads| is cleared.
+  OwningSerializedPacketPointer SerializePathResponseConnectivityProbingPacket(
+      const QuicDeque<QuicPathFrameBuffer>& payloads,
+      const bool is_padded);
+
   // Returns a dummy packet that is valid but contains no useful information.
   static SerializedPacket NoPacket();
 
diff --git a/net/third_party/quic/core/quic_packet_creator_test.cc b/net/third_party/quic/core/quic_packet_creator_test.cc
index 509f48c..8c452b34 100644
--- a/net/third_party/quic/core/quic_packet_creator_test.cc
+++ b/net/third_party/quic/core/quic_packet_creator_test.cc
@@ -733,8 +733,15 @@
 
     creator_.set_encryption_level(level);
 
-    OwningSerializedPacketPointer encrypted(
-        creator_.SerializeConnectivityProbingPacket());
+    OwningSerializedPacketPointer encrypted;
+    if (GetParam().version.transport_version == QUIC_VERSION_99) {
+      QuicPathFrameBuffer payload = {
+          {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
+      encrypted =
+          creator_.SerializePathChallengeConnectivityProbingPacket(&payload);
+    } else {
+      encrypted = creator_.SerializeConnectivityProbingPacket();
+    }
     {
       InSequence s;
       EXPECT_CALL(framer_visitor_, OnPacket());
@@ -742,7 +749,43 @@
       EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
       EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
       EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
-      EXPECT_CALL(framer_visitor_, OnPingFrame(_));
+      if (GetParam().version.transport_version == QUIC_VERSION_99) {
+        EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_));
+        EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+      } else {
+        EXPECT_CALL(framer_visitor_, OnPingFrame(_));
+        EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+      }
+      EXPECT_CALL(framer_visitor_, OnPacketComplete());
+    }
+    // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER);
+    server_framer_.ProcessPacket(QuicEncryptedPacket(
+        encrypted->encrypted_buffer, encrypted->encrypted_length));
+  }
+}
+
+TEST_P(QuicPacketCreatorTest, SerializePathChallengeProbePacket) {
+  if (GetParam().version.transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  QuicPathFrameBuffer payload = {
+      {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
+
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    EncryptionLevel level = static_cast<EncryptionLevel>(i);
+
+    creator_.set_encryption_level(level);
+
+    OwningSerializedPacketPointer encrypted(
+        creator_.SerializePathChallengeConnectivityProbingPacket(&payload));
+    {
+      InSequence s;
+      EXPECT_CALL(framer_visitor_, OnPacket());
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+      EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+      EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+      EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_));
       EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
       EXPECT_CALL(framer_visitor_, OnPacketComplete());
     }
@@ -752,6 +795,221 @@
   }
 }
 
+TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) {
+  if (GetParam().version.transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  QuicPathFrameBuffer payload0 = {
+      {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
+
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    EncryptionLevel level = static_cast<EncryptionLevel>(i);
+    creator_.set_encryption_level(level);
+
+    QuicDeque<QuicPathFrameBuffer> payloads;
+    payloads.push_back(payload0);
+
+    OwningSerializedPacketPointer encrypted(
+        creator_.SerializePathResponseConnectivityProbingPacket(payloads,
+                                                                true));
+    {
+      InSequence s;
+      EXPECT_CALL(framer_visitor_, OnPacket());
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+      EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+      EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+      EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_));
+      EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+      EXPECT_CALL(framer_visitor_, OnPacketComplete());
+    }
+    server_framer_.ProcessPacket(QuicEncryptedPacket(
+        encrypted->encrypted_buffer, encrypted->encrypted_length));
+  }
+}
+
+TEST_P(QuicPacketCreatorTest,
+       SerializePathResponseProbePacket1PayloadUnPadded) {
+  if (GetParam().version.transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  QuicPathFrameBuffer payload0 = {
+      {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
+
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    EncryptionLevel level = static_cast<EncryptionLevel>(i);
+    creator_.set_encryption_level(level);
+
+    QuicDeque<QuicPathFrameBuffer> payloads;
+    payloads.push_back(payload0);
+
+    OwningSerializedPacketPointer encrypted(
+        creator_.SerializePathResponseConnectivityProbingPacket(payloads,
+                                                                false));
+    {
+      InSequence s;
+      EXPECT_CALL(framer_visitor_, OnPacket());
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+      EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+      EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+      EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_));
+      EXPECT_CALL(framer_visitor_, OnPacketComplete());
+    }
+    server_framer_.ProcessPacket(QuicEncryptedPacket(
+        encrypted->encrypted_buffer, encrypted->encrypted_length));
+  }
+}
+
+TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) {
+  if (GetParam().version.transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  QuicPathFrameBuffer payload0 = {
+      {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
+  QuicPathFrameBuffer payload1 = {
+      {0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde}};
+
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    EncryptionLevel level = static_cast<EncryptionLevel>(i);
+    creator_.set_encryption_level(level);
+
+    QuicDeque<QuicPathFrameBuffer> payloads;
+    payloads.push_back(payload0);
+    payloads.push_back(payload1);
+
+    OwningSerializedPacketPointer encrypted(
+        creator_.SerializePathResponseConnectivityProbingPacket(payloads,
+                                                                true));
+    {
+      InSequence s;
+      EXPECT_CALL(framer_visitor_, OnPacket());
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+      EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+      EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+      EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2);
+      EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+      EXPECT_CALL(framer_visitor_, OnPacketComplete());
+    }
+    server_framer_.ProcessPacket(QuicEncryptedPacket(
+        encrypted->encrypted_buffer, encrypted->encrypted_length));
+  }
+}
+
+TEST_P(QuicPacketCreatorTest,
+       SerializePathResponseProbePacket2PayloadsUnPadded) {
+  if (GetParam().version.transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  QuicPathFrameBuffer payload0 = {
+      {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
+  QuicPathFrameBuffer payload1 = {
+      {0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde}};
+
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    EncryptionLevel level = static_cast<EncryptionLevel>(i);
+    creator_.set_encryption_level(level);
+
+    QuicDeque<QuicPathFrameBuffer> payloads;
+    payloads.push_back(payload0);
+    payloads.push_back(payload1);
+
+    OwningSerializedPacketPointer encrypted(
+        creator_.SerializePathResponseConnectivityProbingPacket(payloads,
+                                                                false));
+    {
+      InSequence s;
+      EXPECT_CALL(framer_visitor_, OnPacket());
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+      EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+      EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+      EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2);
+      EXPECT_CALL(framer_visitor_, OnPacketComplete());
+    }
+    server_framer_.ProcessPacket(QuicEncryptedPacket(
+        encrypted->encrypted_buffer, encrypted->encrypted_length));
+  }
+}
+
+TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) {
+  if (GetParam().version.transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  QuicPathFrameBuffer payload0 = {
+      {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
+  QuicPathFrameBuffer payload1 = {
+      {0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde}};
+  QuicPathFrameBuffer payload2 = {
+      {0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde, 0xad}};
+
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    EncryptionLevel level = static_cast<EncryptionLevel>(i);
+    creator_.set_encryption_level(level);
+
+    QuicDeque<QuicPathFrameBuffer> payloads;
+    payloads.push_back(payload0);
+    payloads.push_back(payload1);
+    payloads.push_back(payload2);
+
+    OwningSerializedPacketPointer encrypted(
+        creator_.SerializePathResponseConnectivityProbingPacket(payloads,
+                                                                true));
+    {
+      InSequence s;
+      EXPECT_CALL(framer_visitor_, OnPacket());
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+      EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+      EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+      EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+      EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3);
+      EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+      EXPECT_CALL(framer_visitor_, OnPacketComplete());
+    }
+    server_framer_.ProcessPacket(QuicEncryptedPacket(
+        encrypted->encrypted_buffer, encrypted->encrypted_length));
+  }
+}
+
+TEST_P(QuicPacketCreatorTest,
+       SerializePathResponseProbePacket3PayloadsUnpadded) {
+  if (GetParam().version.transport_version != QUIC_VERSION_99) {
+    return;
+  }
+  QuicPathFrameBuffer payload0 = {
+      {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}};
+  QuicPathFrameBuffer payload1 = {
+      {0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde}};
+  QuicPathFrameBuffer payload2 = {
+      {0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde, 0xad}};
+
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+    EncryptionLevel level = static_cast<EncryptionLevel>(i);
+    creator_.set_encryption_level(level);
+
+    QuicDeque<QuicPathFrameBuffer> payloads;
+    payloads.push_back(payload0);
+    payloads.push_back(payload1);
+    payloads.push_back(payload2);
+
+    OwningSerializedPacketPointer encrypted(
+        creator_.SerializePathResponseConnectivityProbingPacket(payloads,
+                                                                false));
+    InSequence s;
+    EXPECT_CALL(framer_visitor_, OnPacket());
+    EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+    EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+    EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+    EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+    EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3);
+    EXPECT_CALL(framer_visitor_, OnPacketComplete());
+
+    server_framer_.ProcessPacket(QuicEncryptedPacket(
+        encrypted->encrypted_buffer, encrypted->encrypted_length));
+  }
+}
+
 TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
   if (GetParam().version.transport_version > QUIC_VERSION_43) {
     EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
diff --git a/net/third_party/quic/core/quic_packet_generator.cc b/net/third_party/quic/core/quic_packet_generator.cc
index 0eb39f58..c997864 100644
--- a/net/third_party/quic/core/quic_packet_generator.cc
+++ b/net/third_party/quic/core/quic_packet_generator.cc
@@ -322,6 +322,21 @@
   return packet_creator_.SerializeConnectivityProbingPacket();
 }
 
+OwningSerializedPacketPointer
+QuicPacketGenerator::SerializePathChallengeConnectivityProbingPacket(
+    QuicPathFrameBuffer* payload) {
+  return packet_creator_.SerializePathChallengeConnectivityProbingPacket(
+      payload);
+}
+
+OwningSerializedPacketPointer
+QuicPacketGenerator::SerializePathResponseConnectivityProbingPacket(
+    const QuicDeque<QuicPathFrameBuffer>& payloads,
+    const bool is_padded) {
+  return packet_creator_.SerializePathResponseConnectivityProbingPacket(
+      payloads, is_padded);
+}
+
 void QuicPacketGenerator::ReserializeAllFrames(
     const QuicPendingRetransmission& retransmission,
     char* buffer,
diff --git a/net/third_party/quic/core/quic_packet_generator.h b/net/third_party/quic/core/quic_packet_generator.h
index 30708df..1892d7e 100644
--- a/net/third_party/quic/core/quic_packet_generator.h
+++ b/net/third_party/quic/core/quic_packet_generator.h
@@ -145,6 +145,20 @@
   // Creates a connectivity probing packet.
   OwningSerializedPacketPointer SerializeConnectivityProbingPacket();
 
+  // Create connectivity probing request and response packets using PATH
+  // CHALLENGE and PATH RESPONSE frames, respectively.
+  // SerializePathChallengeConnectivityProbingPacket will pad the packet to be
+  // MTU bytes long.
+  OwningSerializedPacketPointer SerializePathChallengeConnectivityProbingPacket(
+      QuicPathFrameBuffer* payload);
+
+  // If |is_padded| is true then SerializePathResponseConnectivityProbingPacket
+  // will pad the packet to be MTU bytes long, else it will not pad the packet.
+  // |payloads| is cleared.
+  OwningSerializedPacketPointer SerializePathResponseConnectivityProbingPacket(
+      const QuicDeque<QuicPathFrameBuffer>& payloads,
+      const bool is_padded);
+
   // Re-serializes frames with the original packet's packet number length.
   // Used for retransmitting packets to ensure they aren't too long.
   void ReserializeAllFrames(const QuicPendingRetransmission& retransmission,
diff --git a/net/third_party/quic/core/quic_packet_generator_test.cc b/net/third_party/quic/core/quic_packet_generator_test.cc
index 4f81098..30fa742 100644
--- a/net/third_party/quic/core/quic_packet_generator_test.cc
+++ b/net/third_party/quic/core/quic_packet_generator_test.cc
@@ -983,14 +983,25 @@
 TEST_F(QuicPacketGeneratorTest, GenerateConnectivityProbingPacket) {
   delegate_.SetCanWriteAnything();
 
-  OwningSerializedPacketPointer probing_packet(
-      generator_.SerializeConnectivityProbingPacket());
+  OwningSerializedPacketPointer probing_packet;
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    QuicPathFrameBuffer payload = {
+        {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
+    probing_packet =
+        generator_.SerializePathChallengeConnectivityProbingPacket(&payload);
+  } else {
+    probing_packet = generator_.SerializeConnectivityProbingPacket();
+  }
 
   ASSERT_TRUE(simple_framer_.ProcessPacket(QuicEncryptedPacket(
       probing_packet->encrypted_buffer, probing_packet->encrypted_length)));
 
   EXPECT_EQ(2u, simple_framer_.num_frames());
-  EXPECT_EQ(1u, simple_framer_.ping_frames().size());
+  if (framer_.transport_version() == QUIC_VERSION_99) {
+    EXPECT_EQ(1u, simple_framer_.path_challenge_frames().size());
+  } else {
+    EXPECT_EQ(1u, simple_framer_.ping_frames().size());
+  }
   EXPECT_EQ(1u, simple_framer_.padding_frames().size());
 }
 
diff --git a/net/third_party/quic/core/quic_packet_reader.cc b/net/third_party/quic/core/quic_packet_reader.cc
index 039311d..d7115ea 100644
--- a/net/third_party/quic/core/quic_packet_reader.cc
+++ b/net/third_party/quic/core/quic_packet_reader.cc
@@ -16,6 +16,8 @@
 #include "net/third_party/quic/core/quic_process_packet_interface.h"
 #include "net/third_party/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quic/platform/api/quic_flag_utils.h"
+#include "net/third_party/quic/platform/api/quic_flags.h"
 #include "net/third_party/quic/platform/api/quic_logging.h"
 #include "net/third_party/quic/platform/api/quic_socket_address.h"
 #include "net/third_party/quic/platform/impl/quic_socket_utils.h"
@@ -131,9 +133,16 @@
     int ttl = 0;
     bool has_ttl =
         QuicSocketUtils::GetTtlFromMsghdr(&mmsg_hdr_[i].msg_hdr, &ttl);
+    char* headers = nullptr;
+    size_t headers_length = 0;
+    if (GetQuicReloadableFlag(quic_get_recv_headers)) {
+      QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_get_recv_headers, 1, 3);
+      QuicSocketUtils::GetPacketHeadersFromMsghdr(&mmsg_hdr_[i].msg_hdr,
+                                                  &headers, &headers_length);
+    }
     QuicReceivedPacket packet(reinterpret_cast<char*>(packets_[i].iov.iov_base),
                               mmsg_hdr_[i].msg_len, timestamp, false, ttl,
-                              has_ttl);
+                              has_ttl, headers, headers_length, false);
     QuicSocketAddress server_address(server_ip, port);
     processor->ProcessPacket(server_address, client_address, packet);
   }
diff --git a/net/third_party/quic/core/quic_packets.cc b/net/third_party/quic/core/quic_packets.cc
index d5f35d1..4b956a9 100644
--- a/net/third_party/quic/core/quic_packets.cc
+++ b/net/third_party/quic/core/quic_packets.cc
@@ -186,17 +186,21 @@
 QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
                                        size_t length,
                                        QuicTime receipt_time)
-    : QuicEncryptedPacket(buffer, length),
-      receipt_time_(receipt_time),
-      ttl_(0) {}
+    : QuicReceivedPacket(buffer,
+                         length,
+                         receipt_time,
+                         false /* owns_buffer */) {}
 
 QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
                                        size_t length,
                                        QuicTime receipt_time,
                                        bool owns_buffer)
-    : QuicEncryptedPacket(buffer, length, owns_buffer),
-      receipt_time_(receipt_time),
-      ttl_(0) {}
+    : QuicReceivedPacket(buffer,
+                         length,
+                         receipt_time,
+                         owns_buffer,
+                         0 /* ttl */,
+                         true /* ttl_valid */) {}
 
 QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
                                        size_t length,
@@ -204,13 +208,49 @@
                                        bool owns_buffer,
                                        int ttl,
                                        bool ttl_valid)
+    : quic::QuicReceivedPacket(buffer,
+                               length,
+                               receipt_time,
+                               owns_buffer,
+                               ttl,
+                               ttl_valid,
+                               nullptr /* packet_headers */,
+                               0 /* headers_length */,
+                               false /* owns_header_buffer */) {}
+
+QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
+                                       size_t length,
+                                       QuicTime receipt_time,
+                                       bool owns_buffer,
+                                       int ttl,
+                                       bool ttl_valid,
+                                       char* packet_headers,
+                                       size_t headers_length,
+                                       bool owns_header_buffer)
     : QuicEncryptedPacket(buffer, length, owns_buffer),
       receipt_time_(receipt_time),
-      ttl_(ttl_valid ? ttl : -1) {}
+      ttl_(ttl_valid ? ttl : -1),
+      packet_headers_(packet_headers),
+      headers_length_(headers_length),
+      owns_header_buffer_(owns_header_buffer) {}
+
+QuicReceivedPacket::~QuicReceivedPacket() {
+  if (owns_header_buffer_) {
+    delete[] static_cast<char*>(packet_headers_);
+  }
+}
 
 std::unique_ptr<QuicReceivedPacket> QuicReceivedPacket::Clone() const {
   char* buffer = new char[this->length()];
   memcpy(buffer, this->data(), this->length());
+  if (this->packet_headers()) {
+    char* headers_buffer = new char[this->headers_length()];
+    memcpy(headers_buffer, this->packet_headers(), this->headers_length());
+    return QuicMakeUnique<QuicReceivedPacket>(
+        buffer, this->length(), receipt_time(), true, ttl(), ttl() >= 0,
+        headers_buffer, this->headers_length(), true);
+  }
+
   return QuicMakeUnique<QuicReceivedPacket>(
       buffer, this->length(), receipt_time(), true, ttl(), ttl() >= 0);
 }
diff --git a/net/third_party/quic/core/quic_packets.h b/net/third_party/quic/core/quic_packets.h
index c0285b1..d4877ad8 100644
--- a/net/third_party/quic/core/quic_packets.h
+++ b/net/third_party/quic/core/quic_packets.h
@@ -210,6 +210,16 @@
                      bool owns_buffer,
                      int ttl,
                      bool ttl_valid);
+  QuicReceivedPacket(const char* buffer,
+                     size_t length,
+                     QuicTime receipt_time,
+                     bool owns_buffer,
+                     int ttl,
+                     bool ttl_valid,
+                     char* packet_headers,
+                     size_t headers_length,
+                     bool owns_header_buffer);
+  ~QuicReceivedPacket();
   QuicReceivedPacket(const QuicReceivedPacket&) = delete;
   QuicReceivedPacket& operator=(const QuicReceivedPacket&) = delete;
 
@@ -222,6 +232,12 @@
   // This is the TTL of the packet, assuming ttl_vaild_ is true.
   int ttl() const { return ttl_; }
 
+  // Start of packet headers.
+  char* packet_headers() const { return packet_headers_; }
+
+  // Length of packet headers.
+  int headers_length() const { return headers_length_; }
+
   // By default, gtest prints the raw bytes of an object. The bool data
   // member (in the base class QuicData) causes this object to have padding
   // bytes, which causes the default gtest object printer to read
@@ -233,6 +249,12 @@
  private:
   const QuicTime receipt_time_;
   int ttl_;
+  // Points to the start of packet headers.
+  char* packet_headers_;
+  // Length of packet headers.
+  int headers_length_;
+  // Whether owns the buffer for packet headers.
+  bool owns_header_buffer_;
 };
 
 struct QUIC_EXPORT_PRIVATE SerializedPacket {
diff --git a/net/third_party/quic/core/quic_sent_packet_manager.cc b/net/third_party/quic/core/quic_sent_packet_manager.cc
index 75775fb..fa82d55 100644
--- a/net/third_party/quic/core/quic_sent_packet_manager.cc
+++ b/net/third_party/quic/core/quic_sent_packet_manager.cc
@@ -811,7 +811,8 @@
     largest_newly_acked_ = packets_acked_.back().packet_number;
   }
   loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
-                                largest_newly_acked_, &packets_lost_);
+                                largest_newly_acked_, packets_acked_,
+                                &packets_lost_);
   for (const LostPacket& packet : packets_lost_) {
     ++stats_->packets_lost;
     if (debug_delegate_ != nullptr) {
diff --git a/net/third_party/quic/core/quic_sent_packet_manager.h b/net/third_party/quic/core/quic_sent_packet_manager.h
index 0ce986b..bfabcfa5 100644
--- a/net/third_party/quic/core/quic_sent_packet_manager.h
+++ b/net/third_party/quic/core/quic_sent_packet_manager.h
@@ -344,6 +344,12 @@
   // pacing sender at |send_algorithm_|. Can be called any number of times.
   void SetSendAlgorithm(CongestionControlType congestion_control_type);
 
+  // Sets the send algorithm to |send_algorithm| and points the pacing sender at
+  // |send_algorithm_|. Takes ownership of |send_algorithm|. Can be called any
+  // number of times.
+  // Setting the send algorithm once the connection is underway is dangerous.
+  void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm);
+
  private:
   friend class test::QuicConnectionPeer;
   friend class test::QuicSentPacketManagerPeer;
@@ -462,11 +468,6 @@
   void RecordSpuriousRetransmissions(const QuicTransmissionInfo& info,
                                      QuicPacketNumber acked_packet_number);
 
-  // Sets the send algorithm to |send_algorithm| and points the pacing sender at
-  // |send_algorithm_|. Takes ownership of |send_algorithm|. Can be called any
-  // number of times.
-  void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm);
-
   // Sets the initial RTT of the connection.
   void SetInitialRtt(QuicTime::Delta rtt);
 
diff --git a/net/third_party/quic/core/quic_sent_packet_manager_test.cc b/net/third_party/quic/core/quic_sent_packet_manager_test.cc
index a8d9d17..41a73bd 100644
--- a/net/third_party/quic/core/quic_sent_packet_manager_test.cc
+++ b/net/third_party/quic/core/quic_sent_packet_manager_test.cc
@@ -650,7 +650,7 @@
   // so no call on OnSpuriousRetransmission is expected.
   {
     ExpectAck(1);
-    EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+    EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
     manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now());
     manager_.OnAckRange(1, 2);
     EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
@@ -661,7 +661,7 @@
   // Ack 4, which causes 3 to be retransmitted.
   {
     ExpectAck(4);
-    EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+    EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
     manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now());
     manager_.OnAckRange(4, 5);
     manager_.OnAckRange(1, 2);
@@ -673,7 +673,7 @@
   {
     QuicPacketNumber acked[] = {3};
     ExpectAcksAndLosses(false, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
-    EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+    EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
     EXPECT_CALL(*loss_algorithm, SpuriousRetransmitDetected(_, _, _, 5));
     manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now());
     manager_.OnAckRange(3, 5);
@@ -684,7 +684,7 @@
       // 5 will cause 5 be considered as a spurious retransmission as no new
       // data gets acked.
       ExpectAck(5);
-      EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+      EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
       EXPECT_CALL(notifier_, OnFrameAcked(_, _)).WillOnce(Return(false));
       manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now());
       manager_.OnAckRange(3, 6);
@@ -1911,7 +1911,7 @@
   // Handle an ack which causes the loss algorithm to be evaluated and
   // set the loss timeout.
   ExpectAck(2);
-  EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
   manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now());
   manager_.OnAckRange(2, 3);
   EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
@@ -1923,7 +1923,7 @@
 
   // Fire the retransmission timeout and ensure the loss detection algorithm
   // is invoked.
-  EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+  EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _, _));
   manager_.OnRetransmissionTimeout();
 }
 
diff --git a/net/third_party/quic/core/quic_session.cc b/net/third_party/quic/core/quic_session.cc
index 805ed21b..f4dd8bb2 100644
--- a/net/third_party/quic/core/quic_session.cc
+++ b/net/third_party/quic/core/quic_session.cc
@@ -74,6 +74,7 @@
                        nullptr),
       currently_writing_stream_id_(0),
       largest_static_stream_id_(0),
+      is_handshake_confirmed_(false),
       goaway_sent_(false),
       goaway_received_(false),
       faster_get_stream_(GetQuicReloadableFlag(quic_session_faster_get_stream)),
@@ -258,7 +259,7 @@
   if (perspective() == Perspective::IS_SERVER) {
     // Server only sends back a connectivity probe after received a
     // connectivity probe from a new peer address.
-    connection_->SendConnectivityProbingPacket(nullptr, peer_address);
+    connection_->SendConnectivityProbingResponsePacket(peer_address);
   }
 }
 
@@ -622,6 +623,10 @@
 }
 
 bool QuicSession::IsEncryptionEstablished() const {
+  // Once the handshake is confirmed, it never becomes un-confirmed.
+  if (is_handshake_confirmed_) {
+    return true;
+  }
   return GetCryptoStream()->encryption_established();
 }
 
@@ -794,6 +799,11 @@
       // Discard originally encrypted packets, since they can't be decrypted by
       // the peer.
       NeuterUnencryptedData();
+      if (GetQuicReloadableFlag(quic_optimize_encryption_established)) {
+        QUIC_FLAG_COUNT(
+            quic_reloadable_flag_quic_optimize_encryption_established);
+        is_handshake_confirmed_ = true;
+      }
       break;
 
     default:
@@ -1240,7 +1250,7 @@
 }
 
 bool QuicSession::HasUnackedCryptoData() const {
-  const QuicStream* crypto_stream = GetCryptoStream();
+  const QuicCryptoStream* crypto_stream = GetCryptoStream();
   if (crypto_stream->IsWaitingForAcks()) {
     return true;
   }
diff --git a/net/third_party/quic/core/quic_session.h b/net/third_party/quic/core/quic_session.h
index 66afeec..810f7641 100644
--- a/net/third_party/quic/core/quic_session.h
+++ b/net/third_party/quic/core/quic_session.h
@@ -575,6 +575,9 @@
   // The largest stream id in |static_stream_map_|.
   QuicStreamId largest_static_stream_id_;
 
+  // Cached value of whether the crypto handshake has been confirmed.
+  bool is_handshake_confirmed_;
+
   // Whether a GoAway has been sent.
   bool goaway_sent_;
 
diff --git a/net/third_party/quic/core/quic_session_test.cc b/net/third_party/quic/core/quic_session_test.cc
index 828ce566..12e866aa 100644
--- a/net/third_party/quic/core/quic_session_test.cc
+++ b/net/third_party/quic/core/quic_session_test.cc
@@ -244,6 +244,30 @@
 };
 
 class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> {
+ public:
+  // CheckMultiPathResponse validates that a written packet
+  // contains both expected path responses.
+  WriteResult CheckMultiPathResponse(const char* buffer,
+                                     size_t buf_len,
+                                     const QuicIpAddress& self_address,
+                                     const QuicSocketAddress& peer_address,
+                                     PerPacketOptions* options) {
+    QuicEncryptedPacket packet(buffer, buf_len);
+    // The packet should look like:
+    //  fd513039 39052a00  00000000 00000000  *.Q099.*.........*
+    //  0001fe62 a4c3d138  0ba93f42 82ec0f00  *...b...8..?B....*
+    //  01020304 0506070f  08090a0b 0c0d0e0f  *...
+    // The two PATH RESPONSE frames should be at offset
+    // 30 in the packet. We expect to see
+    //   0x0f 0 1 2 3 4 5 6 7
+    // and
+    //   0x0f 8 9 10 11 12 13 14 15
+    const unsigned char expected[] = {0x0f, 0, 1, 2,  3,  4,  5,  6,  7,
+                                      0x0f, 8, 9, 10, 11, 12, 13, 14, 15};
+    EXPECT_EQ(0, memcmp((buffer + 30), expected, sizeof(expected)));
+    return WriteResult(WRITE_STATUS_OK, 0);
+  }
+
  protected:
   explicit QuicSessionTestBase(Perspective perspective)
       : connection_(
@@ -788,7 +812,7 @@
 
 // Test that server session will send a connectivity probe in response to a
 // connectivity probe on the same path.
-TEST_P(QuicSessionTestServer, ServerReplyToConnecitivityProbe) {
+TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) {
   QuicSocketAddress old_peer_address =
       QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort);
   EXPECT_EQ(old_peer_address, session_.peer_address());
@@ -800,16 +824,53 @@
       QuicConnectionPeer::GetWriter(session_.connection()));
   EXPECT_CALL(*writer, WritePacket(_, _, _, new_peer_address, _))
       .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
-  EXPECT_CALL(*connection_,
-              SendConnectivityProbingPacket(nullptr, new_peer_address))
-      .WillOnce(
-          Invoke(connection_,
-                 &MockQuicConnection::ReallySendConnectivityProbingPacket));
+  EXPECT_CALL(*connection_, SendConnectivityProbingResponsePacket(_))
+      .WillOnce(Invoke(
+          connection_,
+          &MockQuicConnection::ReallySendConnectivityProbingResponsePacket));
+  if (transport_version() == QUIC_VERSION_99) {
+    // Need to explicitly do this to emulate the reception of a PathChallenge,
+    // which stores its payload for use in generating the response.
+    connection_->OnPathChallengeFrame(
+        QuicPathChallengeFrame(0, {{0, 1, 2, 3, 4, 5, 6, 7}}));
+  }
   session_.OnConnectivityProbeReceived(session_.self_address(),
                                        new_peer_address);
   EXPECT_EQ(old_peer_address, session_.peer_address());
 }
 
+// Same as above, but check that if there are two PATH_CHALLENGE frames in the
+// packet, the response has both of them AND we do not do migration.  This for
+// V99 only.
+TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbes) {
+  if (transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+  QuicSocketAddress old_peer_address =
+      QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort);
+  EXPECT_EQ(old_peer_address, session_.peer_address());
+
+  MockPacketWriter* writer = static_cast<MockPacketWriter*>(
+      QuicConnectionPeer::GetWriter(session_.connection()));
+  // CheckMultiPathResponse validates that the written packet
+  // contains both path responses.
+  EXPECT_CALL(*writer, WritePacket(_, _, _, old_peer_address, _))
+      .WillOnce(Invoke(this, &QuicSessionTestServer::CheckMultiPathResponse));
+
+  EXPECT_CALL(*connection_, SendConnectivityProbingResponsePacket(_))
+      .WillOnce(Invoke(
+          connection_,
+          &MockQuicConnection::ReallySendConnectivityProbingResponsePacket));
+  // Need to explicitly do this to emulate the reception of a PathChallenge,
+  // which stores its payload for use in generating the response.
+  connection_->OnPathChallengeFrame(
+      QuicPathChallengeFrame(0, {{0, 1, 2, 3, 4, 5, 6, 7}}));
+  connection_->OnPathChallengeFrame(
+      QuicPathChallengeFrame(0, {{8, 9, 10, 11, 12, 13, 14, 15}}));
+  session_.OnConnectivityProbeReceived(session_.self_address(),
+                                       old_peer_address);
+}
+
 TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) {
   EXPECT_EQ(kInitialIdleTimeoutSecs + 3,
             QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
diff --git a/net/third_party/quic/core/quic_version_manager.cc b/net/third_party/quic/core/quic_version_manager.cc
index a2a14c5..70498a1 100644
--- a/net/third_party/quic/core/quic_version_manager.cc
+++ b/net/third_party/quic/core/quic_version_manager.cc
@@ -15,6 +15,7 @@
 QuicVersionManager::QuicVersionManager(
     ParsedQuicVersionVector supported_versions)
     : enable_version_99_(GetQuicFlag(FLAGS_quic_enable_version_99)),
+      enable_version_46_(GetQuicReloadableFlag(quic_enable_version_46)),
       enable_version_45_(GetQuicReloadableFlag(quic_enable_version_45)),
       enable_version_44_(GetQuicReloadableFlag(quic_enable_version_44)),
       enable_version_43_(GetQuicReloadableFlag(quic_enable_version_43)),
@@ -38,11 +39,13 @@
 
 void QuicVersionManager::MaybeRefilterSupportedVersions() {
   if (enable_version_99_ != GetQuicFlag(FLAGS_quic_enable_version_99) ||
+      enable_version_46_ != GetQuicReloadableFlag(quic_enable_version_46) ||
       enable_version_45_ != GetQuicReloadableFlag(quic_enable_version_45) ||
       enable_version_44_ != GetQuicReloadableFlag(quic_enable_version_44) ||
       enable_version_43_ != GetQuicReloadableFlag(quic_enable_version_43) ||
       disable_version_35_ != GetQuicReloadableFlag(quic_disable_version_35)) {
     enable_version_99_ = GetQuicFlag(FLAGS_quic_enable_version_99);
+    enable_version_46_ = GetQuicReloadableFlag(quic_enable_version_46);
     enable_version_45_ = GetQuicReloadableFlag(quic_enable_version_45);
     enable_version_44_ = GetQuicReloadableFlag(quic_enable_version_44);
     enable_version_43_ = GetQuicReloadableFlag(quic_enable_version_43);
diff --git a/net/third_party/quic/core/quic_version_manager.h b/net/third_party/quic/core/quic_version_manager.h
index 903fac3..a230c731 100644
--- a/net/third_party/quic/core/quic_version_manager.h
+++ b/net/third_party/quic/core/quic_version_manager.h
@@ -37,6 +37,8 @@
  private:
   // FLAGS_quic_enable_version_99
   bool enable_version_99_;
+  // FLAGS_quic_reloadable_flag_quic_enable_version_46
+  bool enable_version_46_;
   // FLAGS_quic_reloadable_flag_quic_enable_version_45
   bool enable_version_45_;
   // FLAGS_quic_reloadable_flag_quic_enable_version_44
diff --git a/net/third_party/quic/core/quic_version_manager_test.cc b/net/third_party/quic/core/quic_version_manager_test.cc
index 8724dab6..6002861 100644
--- a/net/third_party/quic/core/quic_version_manager_test.cc
+++ b/net/third_party/quic/core/quic_version_manager_test.cc
@@ -16,9 +16,10 @@
 class QuicVersionManagerTest : public QuicTest {};
 
 TEST_F(QuicVersionManagerTest, QuicVersionManager) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
                 "Supported versions out of sync");
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
+  SetQuicReloadableFlag(quic_enable_version_46, false);
   SetQuicReloadableFlag(quic_enable_version_45, false);
   SetQuicReloadableFlag(quic_enable_version_44, false);
   SetQuicReloadableFlag(quic_enable_version_43, false);
@@ -51,12 +52,19 @@
                                         QUIC_VERSION_35}),
             manager.GetSupportedTransportVersions());
 
-  SetQuicFlag(&FLAGS_quic_enable_version_99, true);
-  EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_45,
+  SetQuicReloadableFlag(quic_enable_version_46, true);
+  EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_46, QUIC_VERSION_45,
                                         QUIC_VERSION_44, QUIC_VERSION_43,
                                         QUIC_VERSION_39, QUIC_VERSION_35}),
             manager.GetSupportedTransportVersions());
 
+  SetQuicFlag(&FLAGS_quic_enable_version_99, true);
+  EXPECT_EQ(
+      QuicTransportVersionVector(
+          {QUIC_VERSION_99, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
+           QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}),
+      manager.GetSupportedTransportVersions());
+
   // Ensure that all versions are now supported.
   EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()),
             manager.GetSupportedTransportVersions());
diff --git a/net/third_party/quic/core/quic_versions.cc b/net/third_party/quic/core/quic_versions.cc
index 4247021..e82679b6 100644
--- a/net/third_party/quic/core/quic_versions.cc
+++ b/net/third_party/quic/core/quic_versions.cc
@@ -64,6 +64,8 @@
       return MakeVersionLabel(proto, '0', '4', '4');
     case QUIC_VERSION_45:
       return MakeVersionLabel(proto, '0', '4', '5');
+    case QUIC_VERSION_46:
+      return MakeVersionLabel(proto, '0', '4', '6');
     case QUIC_VERSION_99:
       return MakeVersionLabel(proto, '0', '9', '9');
     default:
@@ -157,6 +159,14 @@
   for (ParsedQuicVersion version : versions) {
     if (version.transport_version == QUIC_VERSION_99) {
       if (GetQuicFlag(FLAGS_quic_enable_version_99) &&
+          GetQuicReloadableFlag(quic_enable_version_46) &&
+          GetQuicReloadableFlag(quic_enable_version_45) &&
+          GetQuicReloadableFlag(quic_enable_version_44) &&
+          GetQuicReloadableFlag(quic_enable_version_43)) {
+        filtered_versions.push_back(version);
+      }
+    } else if (version.transport_version == QUIC_VERSION_46) {
+      if (GetQuicReloadableFlag(quic_enable_version_46) &&
           GetQuicReloadableFlag(quic_enable_version_45) &&
           GetQuicReloadableFlag(quic_enable_version_44) &&
           GetQuicReloadableFlag(quic_enable_version_43)) {
@@ -275,6 +285,7 @@
     RETURN_STRING_LITERAL(QUIC_VERSION_43);
     RETURN_STRING_LITERAL(QUIC_VERSION_44);
     RETURN_STRING_LITERAL(QUIC_VERSION_45);
+    RETURN_STRING_LITERAL(QUIC_VERSION_46);
     RETURN_STRING_LITERAL(QUIC_VERSION_99);
     default:
       return "QUIC_VERSION_UNSUPPORTED";
diff --git a/net/third_party/quic/core/quic_versions.h b/net/third_party/quic/core/quic_versions.h
index 4c3cf15..22a613ad 100644
--- a/net/third_party/quic/core/quic_versions.h
+++ b/net/third_party/quic/core/quic_versions.h
@@ -101,6 +101,7 @@
                          // server.
   QUIC_VERSION_44 = 44,  // Use IETF header format.
   QUIC_VERSION_45 = 45,  // Added MESSAGE frame.
+  QUIC_VERSION_46 = 46,  // Use CRYPTO frames for QuicCryptoStreams.
   QUIC_VERSION_99 = 99,  // Dumping ground for IETF QUIC changes which are not
                          // yet ready for production.
 };
@@ -161,7 +162,7 @@
 //
 // See go/new-quic-version for more details on how to roll out new versions.
 static const QuicTransportVersion kSupportedTransportVersions[] = {
-    QUIC_VERSION_99, QUIC_VERSION_45, QUIC_VERSION_44,
+    QUIC_VERSION_99, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
     QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
 
 // This vector contains all crypto handshake protocols that are supported.
diff --git a/net/third_party/quic/core/quic_versions_test.cc b/net/third_party/quic/core/quic_versions_test.cc
index 596def5..3ad9bbab 100644
--- a/net/third_party/quic/core/quic_versions_test.cc
+++ b/net/third_party/quic/core/quic_versions_test.cc
@@ -140,6 +140,8 @@
             ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '4')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
             ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '5')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
+            ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '6')));
 
   // Test a TLS version:
   FLAGS_quic_supports_tls_handshake = true;
@@ -153,26 +155,22 @@
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_45),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
 
   FLAGS_quic_supports_tls_handshake = false;
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '5')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '7')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '8')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '1')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '2')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
 }
 
 TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
@@ -191,6 +189,9 @@
   EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '5'),
             CreateQuicVersionLabel(
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45)));
+  EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '6'),
+            CreateQuicVersionLabel(
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)));
 
   // Test a TLS version:
   FLAGS_quic_supports_tls_handshake = true;
@@ -209,26 +210,23 @@
   EXPECT_EQ(MakeVersionLabel('T', '0', '4', '5'),
             CreateQuicVersionLabel(
                 ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_45)));
+  EXPECT_EQ(MakeVersionLabel('T', '0', '4', '6'),
+            CreateQuicVersionLabel(
+                ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46)));
 
   FLAGS_quic_supports_tls_handshake = false;
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '5')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '7')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '8')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '1')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
-            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '2')));
-  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6')));
 }
 
 TEST_F(QuicVersionsTest, QuicVersionLabelToString) {
@@ -316,13 +314,14 @@
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, true);
+  SetQuicReloadableFlag(quic_enable_version_46, true);
   SetQuicFlag(&FLAGS_quic_enable_version_99, true);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
     parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
   }
   QuicTransportVersionVector expected_versions = {
-      QUIC_VERSION_99, QUIC_VERSION_45, QUIC_VERSION_44,
+      QUIC_VERSION_99, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
       QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
   ParsedQuicVersionVector expected_parsed_versions;
   for (QuicTransportVersion version : expected_versions) {
@@ -340,6 +339,32 @@
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, true);
+  SetQuicReloadableFlag(quic_enable_version_46, true);
+  SetQuicFlag(&FLAGS_quic_enable_version_99, false);
+  ParsedQuicVersionVector parsed_versions;
+  for (QuicTransportVersion version : all_versions) {
+    parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+  QuicTransportVersionVector expected_versions = {
+      QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44,
+      QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35};
+  ParsedQuicVersionVector expected_parsed_versions;
+  for (QuicTransportVersion version : expected_versions) {
+    expected_parsed_versions.push_back(
+        ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+
+  ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions));
+  ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
+}
+
+TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo46) {
+  QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  SetQuicReloadableFlag(quic_disable_version_35, false);
+  SetQuicReloadableFlag(quic_enable_version_43, true);
+  SetQuicReloadableFlag(quic_enable_version_44, true);
+  SetQuicReloadableFlag(quic_enable_version_45, true);
+  SetQuicReloadableFlag(quic_enable_version_46, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -364,6 +389,7 @@
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, true);
   SetQuicReloadableFlag(quic_enable_version_45, false);
+  SetQuicReloadableFlag(quic_enable_version_46, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -387,6 +413,7 @@
   SetQuicReloadableFlag(quic_enable_version_43, true);
   SetQuicReloadableFlag(quic_enable_version_44, false);
   SetQuicReloadableFlag(quic_enable_version_45, false);
+  SetQuicReloadableFlag(quic_enable_version_46, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -410,6 +437,7 @@
   SetQuicReloadableFlag(quic_enable_version_43, false);
   SetQuicReloadableFlag(quic_enable_version_44, false);
   SetQuicReloadableFlag(quic_enable_version_45, false);
+  SetQuicReloadableFlag(quic_enable_version_46, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -433,6 +461,7 @@
   SetQuicReloadableFlag(quic_enable_version_43, false);
   SetQuicReloadableFlag(quic_enable_version_44, false);
   SetQuicReloadableFlag(quic_enable_version_45, false);
+  SetQuicReloadableFlag(quic_enable_version_46, false);
   SetQuicFlag(&FLAGS_quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -489,13 +518,14 @@
 // yet a typo was made in doing the #defines and it was caught
 // only in some test far removed from here... Better safe than sorry.
 TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
                 "Supported versions out of sync");
   EXPECT_EQ(QUIC_VERSION_35, 35);
   EXPECT_EQ(QUIC_VERSION_39, 39);
   EXPECT_EQ(QUIC_VERSION_43, 43);
   EXPECT_EQ(QUIC_VERSION_44, 44);
   EXPECT_EQ(QUIC_VERSION_45, 45);
+  EXPECT_EQ(QUIC_VERSION_46, 46);
   EXPECT_EQ(QUIC_VERSION_99, 99);
 }
 }  // namespace
diff --git a/net/third_party/quic/quartc/quartc_factory.cc b/net/third_party/quic/quartc/quartc_factory.cc
index 0718999..7eec675 100644
--- a/net/third_party/quic/quartc/quartc_factory.cc
+++ b/net/third_party/quic/quartc/quartc_factory.cc
@@ -5,6 +5,7 @@
 #include "net/third_party/quic/quartc/quartc_factory.h"
 
 #include "net/third_party/quic/core/crypto/quic_random.h"
+#include "net/third_party/quic/platform/api/quic_goog_cc_sender.h"
 #include "net/third_party/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quic/platform/api/quic_socket_address.h"
 #include "net/third_party/quic/quartc/quartc_session.h"
@@ -55,8 +56,31 @@
   // Enable time-based loss detection.
   copt.push_back(kTIME);
 
-  // Use BBR for congestion control.
-  copt.push_back(kTBBR);
+  switch (quartc_session_config.congestion_control_type) {
+    case kBBR:
+      copt.push_back(kTBBR);
+      break;
+    case kGoogCC: {
+      QuicSentPacketManager& sent_packet_manager =
+          quic_connection->sent_packet_manager();
+      SendAlgorithmInterface* sender = CreateGoogCcSender(
+          clock_, sent_packet_manager.GetRttStats(),
+          &sent_packet_manager.unacked_packets(), GetRandomGenerator(),
+          /*stats=*/nullptr, sent_packet_manager.initial_congestion_window(),
+          kDefaultMaxCongestionWindowPackets);
+      sent_packet_manager.SetSendAlgorithm(sender);
+      break;
+    }
+    case kCubicBytes:
+      QUIC_LOG(FATAL) << "kCubicBytes is not supported";
+      break;
+    case kRenoBytes:
+      QUIC_LOG(FATAL) << "kRenoBytes is not supported";
+      break;
+    case kPCC:
+      QUIC_LOG(FATAL) << "kPCC is not supported";
+      break;
+  }
 
   // Note: flag settings have no effect for Exoblaze builds since
   // SetQuicReloadableFlag() gets stubbed out.
diff --git a/net/third_party/quic/quartc/quartc_factory.h b/net/third_party/quic/quartc/quartc_factory.h
index c3f1fcf9cc..ab40858 100644
--- a/net/third_party/quic/quartc/quartc_factory.h
+++ b/net/third_party/quic/quartc/quartc_factory.h
@@ -47,6 +47,10 @@
       QuicTime::Delta::Zero();
   QuicTime::Delta max_time_before_crypto_handshake = QuicTime::Delta::Zero();
   QuicTime::Delta idle_network_timeout = QuicTime::Delta::Zero();
+
+  // Congestion control type used for this session.  Only BBR and GoogCC are
+  // supported.
+  CongestionControlType congestion_control_type = kBBR;
 };
 
 // Factory that creates instances of QuartcSession.  Implements the
diff --git a/net/third_party/quic/test_tools/quic_packet_creator_peer.cc b/net/third_party/quic/test_tools/quic_packet_creator_peer.cc
index 6c6823c..e1f4bde5 100644
--- a/net/third_party/quic/test_tools/quic_packet_creator_peer.cc
+++ b/net/third_party/quic/test_tools/quic_packet_creator_peer.cc
@@ -92,6 +92,14 @@
 }
 
 // static
+OwningSerializedPacketPointer
+QuicPacketCreatorPeer::SerializePathChallengeConnectivityProbingPacket(
+    QuicPacketCreator* creator,
+    QuicPathFrameBuffer* payload) {
+  return creator->SerializePathChallengeConnectivityProbingPacket(payload);
+}
+
+// static
 EncryptionLevel QuicPacketCreatorPeer::GetEncryptionLevel(
     QuicPacketCreator* creator) {
   return creator->packet_.encryption_level;
diff --git a/net/third_party/quic/test_tools/quic_packet_creator_peer.h b/net/third_party/quic/test_tools/quic_packet_creator_peer.h
index 35a4f869..655e8dd 100644
--- a/net/third_party/quic/test_tools/quic_packet_creator_peer.h
+++ b/net/third_party/quic/test_tools/quic_packet_creator_peer.h
@@ -43,6 +43,10 @@
                                              size_t buffer_len);
   static OwningSerializedPacketPointer SerializeConnectivityProbingPacket(
       QuicPacketCreator* creator);
+  static OwningSerializedPacketPointer
+  SerializePathChallengeConnectivityProbingPacket(QuicPacketCreator* creator,
+                                                  QuicPathFrameBuffer* payload);
+
   static EncryptionLevel GetEncryptionLevel(QuicPacketCreator* creator);
   static QuicFramer* framer(QuicPacketCreator* creator);
 };
diff --git a/net/third_party/quic/test_tools/quic_test_utils.h b/net/third_party/quic/test_tools/quic_test_utils.h
index 6336a77..e1d40e4 100644
--- a/net/third_party/quic/test_tools/quic_test_utils.h
+++ b/net/third_party/quic/test_tools/quic_test_utils.h
@@ -480,6 +480,8 @@
   MOCK_METHOD2(SendWindowUpdate,
                void(QuicStreamId id, QuicStreamOffset byte_offset));
   MOCK_METHOD0(OnCanWrite, void());
+  MOCK_METHOD1(SendConnectivityProbingResponsePacket,
+               void(const QuicSocketAddress& peer_address));
   MOCK_METHOD2(SendConnectivityProbingPacket,
                bool(QuicPacketWriter* probing_writer,
                     const QuicSocketAddress& peer_address));
@@ -516,6 +518,12 @@
     return QuicConnection::SendConnectivityProbingPacket(probing_writer,
                                                          peer_address);
   }
+
+  void ReallySendConnectivityProbingResponsePacket(
+      const QuicSocketAddress& peer_address) {
+    QuicConnection::SendConnectivityProbingResponsePacket(peer_address);
+  }
+  MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame&));
 };
 
 class PacketSavingConnection : public MockQuicConnection {
@@ -875,11 +883,12 @@
   ~MockLossAlgorithm() override;
 
   MOCK_CONST_METHOD0(GetLossDetectionType, LossDetectionType());
-  MOCK_METHOD5(DetectLosses,
+  MOCK_METHOD6(DetectLosses,
                void(const QuicUnackedPacketMap& unacked_packets,
                     QuicTime time,
                     const RttStats& rtt_stats,
                     QuicPacketNumber largest_recently_acked,
+                    const AckedPacketVector& packets_acked,
                     LostPacketVector* packets_lost));
   MOCK_CONST_METHOD0(GetLossTimeout, QuicTime());
   MOCK_METHOD4(SpuriousRetransmitDetected,
diff --git a/net/third_party/quic/test_tools/simple_quic_framer.cc b/net/third_party/quic/test_tools/simple_quic_framer.cc
index f8ff820..4bd34385 100644
--- a/net/third_party/quic/test_tools/simple_quic_framer.cc
+++ b/net/third_party/quic/test_tools/simple_quic_framer.cc
@@ -226,6 +226,12 @@
   const std::vector<QuicPaddingFrame>& padding_frames() const {
     return padding_frames_;
   }
+  const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const {
+    return path_challenge_frames_;
+  }
+  const std::vector<QuicPathResponseFrame>& path_response_frames() const {
+    return path_response_frames_;
+  }
   const QuicVersionNegotiationPacket* version_negotiation_packet() const {
     return version_negotiation_packet_.get();
   }
@@ -301,6 +307,7 @@
 size_t SimpleQuicFramer::num_frames() const {
   return ack_frames().size() + goaway_frames().size() +
          rst_stream_frames().size() + stop_waiting_frames().size() +
+         path_challenge_frames().size() + path_response_frames().size() +
          stream_frames().size() + ping_frames().size() +
          connection_close_frames().size() + padding_frames().size();
 }
@@ -314,6 +321,15 @@
   return visitor_->stop_waiting_frames();
 }
 
+const std::vector<QuicPathChallengeFrame>&
+SimpleQuicFramer::path_challenge_frames() const {
+  return visitor_->path_challenge_frames();
+}
+const std::vector<QuicPathResponseFrame>&
+SimpleQuicFramer::path_response_frames() const {
+  return visitor_->path_response_frames();
+}
+
 const std::vector<QuicPingFrame>& SimpleQuicFramer::ping_frames() const {
   return visitor_->ping_frames();
 }
diff --git a/net/third_party/quic/test_tools/simple_quic_framer.h b/net/third_party/quic/test_tools/simple_quic_framer.h
index 466539a..b0a3029 100644
--- a/net/third_party/quic/test_tools/simple_quic_framer.h
+++ b/net/third_party/quic/test_tools/simple_quic_framer.h
@@ -39,6 +39,8 @@
   const std::vector<QuicAckFrame>& ack_frames() const;
   const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const;
   const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const;
+  const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const;
+  const std::vector<QuicPathResponseFrame>& path_response_frames() const;
   const std::vector<QuicPingFrame>& ping_frames() const;
   const std::vector<QuicMessageFrame>& message_frames() const;
   const std::vector<QuicWindowUpdateFrame>& window_update_frames() const;
diff --git a/sandbox/linux/PRESUBMIT.py b/sandbox/linux/PRESUBMIT.py
deleted file mode 100644
index d23105a..0000000
--- a/sandbox/linux/PRESUBMIT.py
+++ /dev/null
@@ -1,34 +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.
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This will add extra trybot coverage for non-default Android architectures
-  that have a history of breaking with Seccomp changes.
-  """
-  def affects_seccomp(f):
-    seccomp_paths = [
-        'bpf_dsl/',
-        'seccomp-bpf/',
-        'seccomp-bpf-helpers/',
-        'system_headers/',
-        'tests/'
-        ]
-    # If the file path contains any of the above fragments, it affects
-    # the Seccomp implementation.
-    affected_any = map(lambda sp: sp in f.LocalPath(), seccomp_paths)
-    return reduce(lambda a, b: a or b, affected_any)
-
-  if not change.AffectedFiles(file_filter=affects_seccomp):
-    return []
-
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-      cl,
-      [
-        'luci.chromium.try:android_arm64_dbg_recipe',
-        'master.tryserver.chromium.android:android_compile_x64_dbg',
-        'master.tryserver.chromium.android:android_compile_x86_dbg',
-      ],
-      'Automatically added Android multi-arch compile bots to run on CQ.')
diff --git a/services/media_session/public/cpp/test/BUILD.gn b/services/media_session/public/cpp/test/BUILD.gn
index 2b515f0..6760bea 100644
--- a/services/media_session/public/cpp/test/BUILD.gn
+++ b/services/media_session/public/cpp/test/BUILD.gn
@@ -8,6 +8,8 @@
   sources = [
     "audio_focus_test_util.cc",
     "audio_focus_test_util.h",
+    "test_media_controller.cc",
+    "test_media_controller.h",
   ]
 
   deps = [
diff --git a/services/media_session/public/cpp/test/test_media_controller.cc b/services/media_session/public/cpp/test/test_media_controller.cc
new file mode 100644
index 0000000..f00ead8
--- /dev/null
+++ b/services/media_session/public/cpp/test/test_media_controller.cc
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/media_session/public/cpp/test/test_media_controller.h"
+
+namespace media_session {
+namespace test {
+
+TestMediaController::TestMediaController() = default;
+
+TestMediaController::~TestMediaController() = default;
+
+mojom::MediaControllerPtr TestMediaController::CreateMediaControllerPtr() {
+  mojom::MediaControllerPtr ptr;
+  binding_.Bind(mojo::MakeRequest(&ptr));
+  return ptr;
+}
+
+void TestMediaController::ToggleSuspendResume() {
+  ++toggle_suspend_resume_count_;
+}
+
+}  // namespace test
+}  // namespace media_session
diff --git a/services/media_session/public/cpp/test/test_media_controller.h b/services/media_session/public/cpp/test/test_media_controller.h
new file mode 100644
index 0000000..a16cdb0
--- /dev/null
+++ b/services/media_session/public/cpp/test/test_media_controller.h
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_MEDIA_SESSION_PUBLIC_CPP_TEST_TEST_MEDIA_CONTROLLER_H_
+#define SERVICES_MEDIA_SESSION_PUBLIC_CPP_TEST_TEST_MEDIA_CONTROLLER_H_
+
+#include "base/component_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/media_session/public/mojom/media_controller.mojom.h"
+
+namespace media_session {
+namespace test {
+
+// Implements the MediaController mojo interface for tests.
+class COMPONENT_EXPORT(MEDIA_SESSION_TEST_SUPPORT_CPP) TestMediaController
+    : public mojom::MediaController {
+ public:
+  TestMediaController();
+  ~TestMediaController() override;
+
+  mojom::MediaControllerPtr CreateMediaControllerPtr();
+
+  // mojom::MediaController:
+  void Suspend() override {}
+  void Resume() override {}
+  void ToggleSuspendResume() override;
+
+  int toggle_suspend_resume_count() const {
+    return toggle_suspend_resume_count_;
+  }
+
+ private:
+  int toggle_suspend_resume_count_ = 0;
+
+  mojo::Binding<mojom::MediaController> binding_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(TestMediaController);
+};
+
+}  // namespace test
+}  // namespace media_session
+
+#endif  // SERVICES_MEDIA_SESSION_PUBLIC_CPP_TEST_TEST_MEDIA_CONTROLLER_H_
diff --git a/services/network/PRESUBMIT.py b/services/network/PRESUBMIT.py
deleted file mode 100644
index 6d06e99b..0000000
--- a/services/network/PRESUBMIT.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""Presubmit script for //services/network.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook adds extra try bots to the CL description in order to run network
-  service tests in addition to CQ try bots.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_mojo'
-    ],
-    'Automatically added network service trybots to run tests on CQ.')
-
diff --git a/services/shape_detection/PRESUBMIT.py b/services/shape_detection/PRESUBMIT.py
deleted file mode 100644
index 312daa8..0000000
--- a/services/shape_detection/PRESUBMIT.py
+++ /dev/null
@@ -1,25 +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.
-
-"""Top-level presubmit script for shape_detection.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-import re
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook adds an extra try bot list to the CL description in order to run
-  the Mac GPU and Windows 10 bots in addition to the usual CQ try bots.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win10_chromium_x64_rel_ng'
-    ],
-    'Automatically added optional Mac GPU and Windows 10 tests to run on CQ.')
diff --git a/services/viz/PRESUBMIT.py b/services/viz/PRESUBMIT.py
index f92af6d..babbf3f 100644
--- a/services/viz/PRESUBMIT.py
+++ b/services/viz/PRESUBMIT.py
@@ -14,21 +14,3 @@
   import presubmit_checks as ps
   white_list=(r'^services[\\/]viz[\\/].*\.(cc|h)$',)
   return ps.RunAllChecks(input_api, output_api, white_list)
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, on Android) in addition to the regular CQ try
-  bots. These tests don't yet run by default on
-  android_n5x_swarming_rel, but viz changes need to run them.
-
-  When adding/removing tests here, ensure that both gpu/PRESUBMIT.py and
-  ui/gl/PRESUBMIT.py are updated.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
diff --git a/services/ws/window_tree.h b/services/ws/window_tree.h
index 9a0308d..a7d704ff1 100644
--- a/services/ws/window_tree.h
+++ b/services/ws/window_tree.h
@@ -67,6 +67,17 @@
       public aura::WindowObserver,
       public aura::client::CaptureClientObserver {
  public:
+  enum class ConnectionType {
+    // This client is the result of an embedding, InitForEmbed() was called.
+    kEmbedding,
+
+    // This client is not the result of an embedding. More specifically
+    // InitFromFactory() was called. Generally this means the client first
+    // connected to mojom::WindowTreeFactory and then called
+    // mojom::WindowTreeFactory::CreateWindowTree().
+    kOther,
+  };
+
   WindowTree(WindowService* window_service,
              ClientSpecificId client_id,
              mojom::WindowTreeClient* client,
@@ -123,6 +134,8 @@
 
   const std::string& client_name() const { return client_name_; }
 
+  ConnectionType connection_type() const { return connection_type_; }
+
   // Returns true if at a compositor frame sink has been created for at least
   // one of the roots.
   bool HasAtLeastOneRootWithCompositorFrameSink();
@@ -149,17 +162,6 @@
 
   using ClientRoots = std::vector<std::unique_ptr<ClientRoot>>;
 
-  enum class ConnectionType {
-    // This client is the result of an embedding, InitForEmbed() was called.
-    kEmbedding,
-
-    // This client is not the result of an embedding. More specifically
-    // InitFromFactory() was called. Generally this means the client first
-    // connected to mojom::WindowTreeFactory and then called
-    // mojom::WindowTreeFactory::CreateWindowTree().
-    kOther,
-  };
-
   enum class DeleteClientRootReason {
     // The window is being destroyed.
     kDeleted,
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 3cc94edf..b74b250 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -3647,6 +3647,25 @@
       },
       {
         "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/mac_window_server_killers.browser_tests.filter",
+          "--gtest_shuffle"
+        ],
+        "experiment_percentage": 25,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "none",
+              "os": "Mac-10.13",
+              "pool": "Chrome-quarantine"
+            }
+          ],
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
           "--enable-features=WebUIPolymer2",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer2_browser_tests.filter"
         ],
diff --git a/testing/buildbot/filters/PRESUBMIT.py b/testing/buildbot/filters/PRESUBMIT.py
index a95deab2..18ece598ac 100644
--- a/testing/buildbot/filters/PRESUBMIT.py
+++ b/testing/buildbot/filters/PRESUBMIT.py
@@ -83,21 +83,3 @@
 
 def CheckChangeOnCommit(input_api, output_api):
   return CommonChecks(input_api, output_api)
-
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook adds extra try bots to the CL description in order to run network
-  service tests in addition to CQ try bots.
-  """
-  def affects_gn_checker(f):
-    return 'mojo.fyi.network_' in f.LocalPath()
-  if not change.AffectedFiles(file_filter=affects_gn_checker):
-    return []
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_mojo'
-    ],
-    'Automatically added network service trybots to run tests on CQ.')
diff --git a/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter b/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
index 7bd74ca..8ef69a3 100644
--- a/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
@@ -276,12 +276,9 @@
 -AppWindowApiTest.OnRestoredEvent
 -BrowserActionApiTest.BrowserActionPopupWithIframe
 -FirstRunUIBrowserTest.ModalWindowDoesNotBlock
--LauncherPlatformAppBrowserTest.AltNumberAppsTabbing
 -LauncherPlatformAppBrowserTest.PackagedAppClickBehaviorInMinimizeMode
 -LoginWebDialogTest.CannotMinimize
 -LoginWebDialogTest.CloseDialogByAccelerator
--ShelfAppBrowserTest.AltNumberTabsTabbing
--ShelfAppBrowserTestNoDefaultBrowser.AltNumberBrowserTabbing
 -ShelfAppBrowserTestNoDefaultBrowser.BrowserShortcutLauncherItemController
 
 # Excluded from Mash because pointer events from EventGenerator aren't seen.
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
index bee645528..9ebf0d0 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.browser_tests.filter
@@ -51,9 +51,6 @@
 -PDFExtensionTest.*
 -PDFExtensionHitTestTest.*
 
-# ash::Shell access for LogoutConfirmationController
--DeviceLocalAccountTest.*
-
 # Fails: immersive_controller->IsRevealed() returns false.
 # http://crbug.com/791148
 -vZoomBubbleBrowserTest.*
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 7699be9..7492b130 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -108,6 +108,9 @@
 -DataReductionProxyFallbackBrowsertest.FallbackProxyUsedWhenBlockZeroHeaderSent
 -DataReductionProxyFallbackBrowsertest.FallbackProxyUsedWhenBypassHeaderSent
 -DataReductionProxyFallbackBrowsertest.NoProxyUsedWhenBlockOnceHeaderSent
+-DataReductionProxyWarmupURLBrowsertest.WarmupURLsFetchedForEachProxy/0
+-DataReductionProxyWarmupURLBrowsertest.WarmupURLsFetchedForEachProxy/1
+-DataReductionProxyWarmupURLBrowsertest.WarmupURLsFail/1
 
 # NOTE: if adding an exclusion for an existing failure (e.g. additional test for
 # feature X that is already not working), please add it beside the existing
diff --git a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
index 51bef1d..8776955 100644
--- a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
@@ -18,6 +18,7 @@
 -org.chromium.android_webview.test.AwContentsClientAutoLoginTest.testAutoLoginWithNullAccount
 
 # https://crbug.com/893563
+-org.chromium.android_webview.test.AwContentsClientFullScreenTest.testExitFullscreenEndsIfAppInvokesCallbackFromOnHideCustomView
 -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testFullscreenNotSupported_video
 -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testFullscreenNotSupported_videoInsideDiv
 -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testOnShowCustomViewAndPlayWithHtmlControl_video
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 69589a4..ec423e84 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -75,7 +75,6 @@
       'mac-views-rel', # https://crbug.com/828031
       # chromium.mac
       'Mac10.10 Tests', # https://crbug.com/828031
-      'Mac10.13 Tests', # https://crbug.com/828031
       # chromium.memory
       'Linux TSan Tests',  # https://crbug.com/368525
       'Mac ASan 64 Tests (1)', # https://crbug.com/828031
@@ -133,6 +132,23 @@
           ],
         },
       },
+      'Mac10.13 Tests': {
+        # A subset of tests seem to cause WindowServer deaths on VMs.
+        # crbug.com/828031 et al.
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/mac_window_server_killers.browser_tests.filter',
+          '--gtest_shuffle',
+        ],
+        'experiment_percentage': 25,
+        'swarming': {
+          'dimension_sets': [
+            {
+              'pool': 'Chrome-quarantine',
+              'gpu': 'none',
+            },
+          ],
+        },
+      },
       'Mac10.13 Tests (dbg)': {
         # A subset of tests seem to cause WindowServer deaths on VMs.
         # crbug.com/828031 et al.
diff --git a/testing/trigger_scripts/PRESUBMIT.py b/testing/trigger_scripts/PRESUBMIT.py
index 17e0e44..17dba62 100644
--- a/testing/trigger_scripts/PRESUBMIT.py
+++ b/testing/trigger_scripts/PRESUBMIT.py
@@ -22,26 +22,3 @@
 
 def CheckChangeOnCommit(input_api, output_api):
   return CommonChecks(input_api, output_api)
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, the WebGL 2.0 conformance tests) in addition
-  to the regular CQ try bots. This test suite is too large to run
-  against all Chromium commits, but should be run against changes
-  likely to affect these tests. The trigger_multiple_dimensions script
-  is used on the chromium.gpu.fyi waterfall and associated optional
-  tryservers, so it's desired to run extra tests when modifying these
-  scripts.
-  """
-  del change # for pylint
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_optional_gpu_tests_rel',
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win_optional_gpu_tests_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 3de53c9..fd89ab0 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1379,31 +1379,6 @@
             ]
         }
     ],
-    "DataReductionProxyRobustConnection": [
-        {
-            "platforms": [
-                "android",
-                "windows",
-                "mac",
-                "chromeos",
-                "linux"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "params": {
-                        "bypass_missing_via_disabled": "true",
-                        "warmup_fetch_callback_enabled": "true",
-                        "warmup_url_fetch_init_http_rtt_multiplier": "12",
-                        "warmup_url_fetch_min_timeout_seconds": "30"
-                    },
-                    "enable_features": [
-                        "DataReductionProxyRobustConnection"
-                    ]
-                }
-            ]
-        }
-    ],
     "DataReductionProxyServerExperiments": [
         {
             "platforms": [
@@ -2176,8 +2151,7 @@
     "ImprovedRecoveryComponent": [
         {
             "platforms": [
-                "windows",
-                "mac"
+                "windows"
             ],
             "experiments": [
                 {
@@ -2438,6 +2412,28 @@
             ]
         }
     ],
+    "LookalikeUrlNavigationSuggestions": [
+        {
+            "platforms": [
+                "linux",
+                "mac",
+                "windows",
+                "android",
+                "chromeos"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_V2",
+                    "params": {
+                        "metrics_only": "true"
+                    },
+                    "enable_features": [
+                        "LookalikeUrlNavigationSuggestions"
+                    ]
+                }
+            ]
+        }
+    ],
     "LowPriorityIframes2": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/PRESUBMIT.py b/third_party/WebKit/LayoutTests/FlagExpectations/PRESUBMIT.py
deleted file mode 100644
index aef2c4f..0000000
--- a/third_party/WebKit/LayoutTests/FlagExpectations/PRESUBMIT.py
+++ /dev/null
@@ -1,26 +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.
-"""Presubmit script for //third_party/WebKit/LayoutTests/FlagExpectations.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook adds extra try bots to the CL description in order to run network
-  service tests in addition to CQ try bots.
-  """
-  def affects_gn_checker(f):
-    return 'enable-features=NetworkService' in f.LocalPath()
-  if not change.AffectedFiles(file_filter=affects_gn_checker):
-    return []
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_mojo'
-    ],
-    'Automatically added network service trybots to run tests on CQ.')
-
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index e23714f2..07b9d94 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -168,9 +168,6 @@
 
 # Display locking, currently only available via a virtual test.
 crbug.com/882663 display-lock [ Skip ]
-crbug.com/882663 virtual/display-lock/display-lock/acquire-callback-throws.html [ Failure ]
-crbug.com/882663 virtual/display-lock/display-lock/multiple-schedules-recursive.html [ Failure ]
-crbug.com/882663 virtual/display-lock/display-lock/simple-schedule-2.html [ Failure ]
 
 # Sheriff 2018/05/25
 crbug.com/846747 http/tests/navigation/navigation-interrupted-by-fragment.html  [ Pass Timeout ]
@@ -3859,8 +3856,7 @@
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-quirks-mode.html [ Pass Crash ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-standards-mode.html [ Pass Crash Failure ]
 
-# Worker/SharedWorker are not exposed in WorkerGlobalScope.
-crbug.com/850662 external/wpt/workers/baseurl/alpha/worker-in-worker.html [ Failure ]
+# SharedWorker are not exposed in WorkerGlobalScope.
 crbug.com/850662 external/wpt/workers/baseurl/alpha/sharedworker-in-worker.html [ Failure ]
 
 # crbug.com/861564 is ongoing for module dedicated workers.
@@ -3888,7 +3884,6 @@
 crbug.com/655458 external/wpt/workers/constructors/Worker/unresolvable-url.html [ Failure ]
 crbug.com/655458 external/wpt/workers/semantics/interface-objects/004.html [ Failure ]
 crbug.com/655458 external/wpt/workers/interfaces/WorkerUtils/importScripts/004.html [ Failure ]
-crbug.com/655458 external/wpt/workers/Worker_ErrorEvent_error.htm [ Failure ]
 crbug.com/655458 external/wpt/workers/semantics/reporting-errors/002.html [ Failure ]
 crbug.com/655458 external/wpt/workers/semantics/reporting-errors/001.html [ Failure ]
 crbug.com/655458 external/wpt/workers/semantics/run-a-worker/003.html [ Failure ]
@@ -5308,7 +5303,6 @@
 crbug.com/887659 animations/animationworklet/animator-with-options.html [ Failure ]
 crbug.com/887659 animations/animationworklet/worklet-animation-currentTime.html [ Failure ]
 crbug.com/887659 animations/animationworklet/worklet-animation-local-time-after-duration.html [ Failure ]
-crbug.com/887659 animations/animationworklet/worklet-animation-local-time-undefined.html [ Failure ]
 
 # Sheriff 2018-09-25
 crbug.com/888609 [ Mac ] http/tests/devtools/coverage/gutter-css.js [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index d8390c69..3c18b46 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -688,7 +688,6 @@
     "prefix": "video-surface-layer",
     "base": "media",
     "args": ["--enable-features=UseSurfaceLayerForVideo",
-             "--enable-features=UseSurfaceLayerForVideoMS",
              "--enable-display-compositor-pixel-dump"]
   },
   {
diff --git a/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-style-update.html b/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-style-update.html
index e7e73b68..d6af3000 100644
--- a/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-style-update.html
+++ b/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-style-update.html
@@ -47,10 +47,6 @@
 
   window.animStartTime = performance.now();
 
-  // TODO(crbug.com/756539): The expected values are based on assumption that
-  // worklet produced local time values are plumbed to main thread. This is
-  // currently not the case and 0 is used instead. As a result the expectation
-  // for the following checks to fail.
   const expectedValues = [
     // [time, element-id, property, expected-value, tolerance]
     [0.2, "box", "opacity",     0.5, 0.05],
diff --git a/third_party/WebKit/LayoutTests/compositing/composited-replaced-subpixel-location-expected.html b/third_party/WebKit/LayoutTests/compositing/composited-replaced-subpixel-location-expected.html
new file mode 100644
index 0000000..5110454
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/composited-replaced-subpixel-location-expected.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<style>
+img {
+  width: 40.4px;
+  height: 30.3px;
+}
+</style>
+<div>
+Passes if each image is at the exact same location when they are composited or not.
+</div>
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
diff --git a/third_party/WebKit/LayoutTests/compositing/composited-replaced-subpixel-location.html b/third_party/WebKit/LayoutTests/compositing/composited-replaced-subpixel-location.html
new file mode 100644
index 0000000..5bb7f456
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/composited-replaced-subpixel-location.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<style>
+img {
+  width: 40.4px;
+  height: 30.3px;
+  will-change: transform;
+}
+</style>
+<div>
+Passes if each image is at the exact same location when they are composited or not.
+</div>
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
+<img src="../images/resources/blue-100.png">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/get-databases.any.js b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/get-databases.any.js
new file mode 100644
index 0000000..99b7ae7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/get-databases.any.js
@@ -0,0 +1,50 @@
+// META: script=support.js
+
+async_test( async function(t) {
+  let made_database_check = t.step_func(async function() {
+    let idb_databases_promise = await indexedDB.databases();
+    assert_true(
+      idb_databases_promise.some(
+          e => e.name == "TestDatabase" && e.version == 1),
+      "Call to databases() did not find database.");
+    t.done();
+  });
+  delete_then_open(t, "TestDatabase", ()=>{}, made_database_check);
+}, "Report one database test.");
+
+async_test( function(t) {
+  let done_making_databases_callback = t.step_func(async function() {
+    let idb_databases_promise = await indexedDB.databases();
+    assert_true(
+      idb_databases_promise.some(
+          e => e.name == "TestDatabase1" && e.version == 1),
+      "Call to databases() did not find database.");
+    assert_true(
+      idb_databases_promise.some(
+          e => e.name == "TestDatabase2" && e.version == 1),
+      "Call to databases() did not find database.");
+    assert_true(
+      idb_databases_promise.some(
+          e => e.name == "TestDatabase3" && e.version == 1),
+      "Call to databases() did not find database.");
+    t.done();
+  });
+  let make_databases_barrier = create_barrier(done_making_databases_callback);
+  delete_then_open(t, "TestDatabase1", ()=>{}, make_databases_barrier(t));
+  delete_then_open(t, "TestDatabase2", ()=>{}, make_databases_barrier(t));
+  delete_then_open(t, "TestDatabase3", ()=>{}, make_databases_barrier(t));
+}, "Report multiple databases test.");
+
+async_test( function(t) {
+  let delete_request = indexedDB.deleteDatabase("NonExistentDatabase");
+  delete_request.onsuccess = t.step_func(async function() {
+    let idb_databases_promise = await indexedDB.databases();
+    assert_false(
+      idb_databases_promise.some(
+          e => e.name == "NonExistentDatabase"),
+      "Call to databases() found excluded database.");
+    t.done();
+  });
+}, "Don't report nonexistant databases test.");
+
+done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/support.js b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/support.js
index 5edbdac..9b3b922 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/support.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/support.js
@@ -192,3 +192,49 @@
     pin = false;
   };
 }
+
+/**
+ * Ensures that indexeddb database specified by db_name is deleted, and then
+ * opens a connection to that database.
+ *
+ * @param t: the testing script state
+ * @param db_name: name of database to delete then create
+ * @param upgrade_func: function to be called if db_name needs upgrading
+ * @param body_func: function to be called upon successful deletion
+ *    and creation of db_name
+ */
+function delete_then_open(t, db_name, upgrade_func, body_func) {
+  var delete_request = indexedDB.deleteDatabase(db_name);
+  delete_request.onerror = t.unreached_func('deleteDatabase should not fail');
+  delete_request.onsuccess = t.step_func(function(e) {
+    var open_request = indexedDB.open(db_name);
+    open_request.onupgradeneeded = t.step_func(function() {
+      upgrade_func(t, open_request.result, open_request);
+    });
+    open_request.onsuccess = t.step_func(function() {
+      body_func(t, open_request.result);
+    });
+  });
+}
+
+/**
+ * Creates a barrier that one calls
+ *
+ * @param callback: function to be called after barrier is passed
+ */
+function create_barrier(callback) {
+  var count = 0;
+  var called = false;
+  return function(t) {
+    assert_false(called, "Barrier already used.");
+    ++count;
+    return t.step_func(function() {
+      --count;
+      if (count === 0) {
+        assert_false(called, "Barrier already used.");
+        called = true;
+        callback();
+      }
+    });
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-with-virtual-authenticator.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-with-virtual-authenticator.html
index 366442a..2bebfae 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-with-virtual-authenticator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-with-virtual-authenticator.html
@@ -41,6 +41,13 @@
     navigator.credentials.create({ publicKey : customMakeCredOptions}));
 }, "navigator.credentials.create() with empty rpId returns SecurityError");
 
+promise_test(async t => {
+  var customMakeCredOptions = deepCopy(MAKE_CREDENTIAL_OPTIONS);
+  customMakeCredOptions.authenticatorSelection.requireResidentKey = true;
+  return promise_rejects(t, "NotSupportedError",
+    navigator.credentials.create({ publicKey : customMakeCredOptions}));
+}, "navigator.credentials.create() with resident keys is disabled");
+
 promise_test(t => {
   return navigator.credentials.test.clearAuthenticators();
 }, "Clean up testing environment.");
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html
index a355fdfe..9827d33 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html
@@ -120,9 +120,9 @@
   someOtherCredential.id = new TextEncoder().encode("someOtherCredential");
   delete customGetAssertionOptions.allowCredentials;
 
-  return promise_rejects(t, "InvalidStateError",
+  return promise_rejects(t, "NotSupportedError",
     navigator.credentials.get({ publicKey : customGetAssertionOptions}));
-}, "navigator.credentials.get() with empty allowCredentials returns InvalidStateError if the user has provided user presence");
+}, "navigator.credentials.get() with empty allowCredentials is disabled");
 
 promise_test(t => {
   return navigator.credentials.test.clearAuthenticators();
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
index 109690b..b2f831d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
@@ -43,9 +43,9 @@
   someOtherCredential.id = new TextEncoder().encode("someOtherCredential");
   delete customGetAssertionOptions.allowCredentials;
 
-  return promise_rejects(t, "InvalidStateError",
+  return promise_rejects(t, "NotSupportedError",
     navigator.credentials.get({ publicKey : customGetAssertionOptions}));
-}, "navigator.credentials.get() with empty allowCredentials returns InvalidStateError if the user has provided user presence");
+}, "navigator.credentials.get() with empty allowCredentials returns NotSupportedError");
 
 promise_test(t => {
   return navigator.credentials.test.clearAuthenticators();
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 06640ea3..9643754 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -562,6 +562,7 @@
     attribute @@toStringTag
     method cmp
     method constructor
+    method databases
     method deleteDatabase
     method open
 interface IDBIndex
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index 38ba282..159b494 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index d449764f..114d2bb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
index 8121507..eb2b3fe 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index 3705a80..2fd54b9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
index 0139e80..6f52b5e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 2ae6c7be..32effc7c 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -504,6 +504,7 @@
 [Worker]     attribute @@toStringTag
 [Worker]     method cmp
 [Worker]     method constructor
+[Worker]     method databases
 [Worker]     method deleteDatabase
 [Worker]     method open
 [Worker] interface IDBIndex
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 905c9d26..b9da9aa 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3891,6 +3891,7 @@
     attribute @@toStringTag
     method cmp
     method constructor
+    method databases
     method deleteDatabase
     method open
 interface IDBIndex
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index 8af9142..48307484 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -499,6 +499,7 @@
 [Worker]     attribute @@toStringTag
 [Worker]     method cmp
 [Worker]     method constructor
+[Worker]     method databases
 [Worker]     method deleteDatabase
 [Worker]     method open
 [Worker] interface IDBIndex
diff --git a/third_party/WebKit/PRESUBMIT.py b/third_party/WebKit/PRESUBMIT.py
index d0ee5c1..c3cdaa7 100644
--- a/third_party/WebKit/PRESUBMIT.py
+++ b/third_party/WebKit/PRESUBMIT.py
@@ -70,90 +70,3 @@
     results.extend(input_api.canned_checks.CheckChangeHasDescription(
         input_api, output_api))
     return results
-
-
-def _ArePaintOrCompositingDirectoriesModified(change):  # pylint: disable=C0103
-    """Checks whether CL has changes to paint or compositing directories."""
-    paint_or_compositing_paths = [
-        os.path.join('third_party', 'WebKit', 'LayoutTests', 'FlagExpectations',
-                     'enable-slimming-paint-v2'),
-        os.path.join('third_party', 'WebKit', 'LayoutTests', 'flag-specific',
-                     'enable-slimming-paint-v2'),
-        os.path.join('third_party', 'WebKit', 'LayoutTests', 'FlagExpectations',
-                     'enable-blink-gen-property-trees'),
-        os.path.join('third_party', 'WebKit', 'LayoutTests', 'flag-specific',
-                     'enable-blink-gen-property-trees'),
-    ]
-    for affected_file in change.AffectedFiles():
-        file_path = affected_file.LocalPath()
-        if any(x in file_path for x in paint_or_compositing_paths):
-            return True
-    return False
-
-
-def __ArePropertyTreeGenerationExpectationsModified(change):  # pylint: disable=C0103
-    """Checks whether CL has changes to paint or compositing directories."""
-    interesting_paths = [
-        os.path.join('third_party', 'WebKit', 'LayoutTests', 'FlagExpectations',
-                     'enable-blink-gen-property-trees'),
-        os.path.join('third_party', 'WebKit', 'LayoutTests', 'flag-specific',
-                     'enable-blink-gen-property-trees'),
-    ]
-    for affected_file in change.AffectedFiles():
-        file_path = affected_file.LocalPath()
-        if any(x in file_path for x in interesting_paths):
-            return True
-    return False
-
-
-def _AreLayoutNGDirectoriesModified(change):  # pylint: disable=C0103
-    """Checks whether CL has changes to a layout ng directory."""
-    layout_ng_paths = [
-        os.path.join('third_party', 'WebKit', 'LayoutTests', 'FlagExpectations',
-                     'enable-blink-features=LayoutNG'),
-        os.path.join('third_party', 'WebKit', 'LayoutTests', 'flag-specific',
-                     'enable-blink-features=LayoutNG'),
-    ]
-    for affected_file in change.AffectedFiles():
-        file_path = affected_file.LocalPath()
-        if any(x in file_path for x in layout_ng_paths):
-            return True
-    return False
-
-
-def PostUploadHook(cl, change, output_api):  # pylint: disable=C0103
-    """git cl upload will call this hook after the issue is created/modified.
-
-    This hook adds extra try bots to the CL description in order to run slimming
-    paint v2 tests or LayoutNG tests in addition to the CQ try bots if the
-    change contains changes in a relevant direcotry (see:
-    _ArePaintOrCompositingDirectoriesModified and
-    _AreLayoutNGDirectoriesModified). For more information about
-    slimming-paint-v2 tests see https://crbug.com/601275 and for information
-    about the LayoutNG tests see https://crbug.com/706183.
-    """
-    results = []
-    if _ArePaintOrCompositingDirectoriesModified(change):
-        results.extend(output_api.EnsureCQIncludeTrybotsAreAdded(
-            cl,
-            ['luci.chromium.try:'
-             'linux_layout_tests_slimming_paint_v2',
-             # TODO(kojii): Update linux_trusty_blink_rel to luci when migrated.
-             'master.tryserver.blink:linux_trusty_blink_rel'],
-            'Automatically added linux_layout_tests_slimming_paint_v2 and '
-            'linux_trusty_blink_rel to run on CQ due to changes in paint or '
-            'compositing directories.'))
-    if __ArePropertyTreeGenerationExpectationsModified(change):
-        results.extend(output_api.EnsureCQIncludeTrybotsAreAdded(
-            cl,
-            ['luci.chromium.try:linux-blink-gen-property-trees'],
-            'Automatically added linux-blink-gen-property-trees and '
-            'run on CQ due to changes in expectations'))
-    if _AreLayoutNGDirectoriesModified(change):
-        results.extend(output_api.EnsureCQIncludeTrybotsAreAdded(
-            cl,
-            ['luci.chromium.try:'
-             'linux_layout_tests_layout_ng'],
-            'Automatically added linux_layout_tests_layout_ng to run on CQ due '
-            'to changes in LayoutNG directories.'))
-    return results
diff --git a/third_party/WebKit/PRESUBMIT_test.py b/third_party/WebKit/PRESUBMIT_test.py
index 32a4ccb..80790cf 100755
--- a/third_party/WebKit/PRESUBMIT_test.py
+++ b/third_party/WebKit/PRESUBMIT_test.py
@@ -66,13 +66,9 @@
         """This verifies that CheckChangeOnUpload will skip calling
         check_blink_style.py if the affected file list is empty.
         """
-        diff_file_chromium1_h = ['some diff']
-        diff_file_chromium2_h = ['another diff']
         diff_file_layout_test_html = ['more diff']
         mock_input_api = MockInputApi()
         mock_input_api.files = [
-            MockAffectedFile('first_file_chromium.h', diff_file_chromium1_h),
-            MockAffectedFile('second_file_chromium.h', diff_file_chromium2_h),
             MockAffectedFile('LayoutTests/some_tests.html', diff_file_layout_test_html)
         ]
         # Access to a protected member _CheckStyle
diff --git a/third_party/blink/PRESUBMIT.py b/third_party/blink/PRESUBMIT.py
index 709a88d..a186e6b 100644
--- a/third_party/blink/PRESUBMIT.py
+++ b/third_party/blink/PRESUBMIT.py
@@ -193,81 +193,3 @@
     results.extend(input_api.canned_checks.CheckChangeHasDescription(
         input_api, output_api))
     return results
-
-
-def _ArePaintOrCompositingDirectoriesModified(change):  # pylint: disable=C0103
-    """Checks whether CL has changes to paint or compositing directories."""
-    paint_or_compositing_paths = [
-        os.path.join('third_party', 'blink', 'renderer', 'platform', 'graphics'),
-        os.path.join('third_party', 'blink', 'renderer', 'core', 'layout',
-                     'compositing'),
-        os.path.join('third_party', 'blink', 'renderer', 'core', 'svg'),
-        os.path.join('third_party', 'blink', 'renderer', 'core', 'paint'),
-        os.path.join('third_party', 'blink', 'web_tests', 'FlagExpectations',
-                     'enable-slimming-paint-v2'),
-        os.path.join('third_party', 'blink', 'web_tests', 'flag-specific',
-                     'enable-slimming-paint-v2'),
-        os.path.join('third_party', 'blink', 'web_tests', 'FlagExpectations',
-                     'enable-blink-gen-property-trees'),
-        os.path.join('third_party', 'blink', 'web_tests', 'flag-specific',
-                     'enable-blink-gen-property-trees'),
-    ]
-    for affected_file in change.AffectedFiles():
-        file_path = affected_file.LocalPath()
-        if any(x in file_path for x in paint_or_compositing_paths):
-            return True
-    return False
-
-
-def _AreLayoutNGDirectoriesModified(change):  # pylint: disable=C0103
-    """Checks whether CL has changes to a layout ng directory."""
-    layout_ng_paths = [
-        os.path.join('third_party', 'blink', 'renderer', 'core', 'editing'),
-        os.path.join('third_party', 'blink', 'renderer', 'core', 'layout',
-                     'ng'),
-        os.path.join('third_party', 'blink', 'renderer', 'core', 'paint',
-                     'ng'),
-        os.path.join('third_party', 'blink', 'renderer', 'platform', 'fonts',
-                     'shaping'),
-        os.path.join('third_party', 'blink', 'web_tests', 'FlagExpectations',
-                     'enable-blink-features=LayoutNG'),
-        os.path.join('third_party', 'blink', 'web_tests', 'flag-specific',
-                     'enable-blink-features=LayoutNG'),
-    ]
-    for affected_file in change.AffectedFiles():
-        file_path = affected_file.LocalPath()
-        if any(x in file_path for x in layout_ng_paths):
-            return True
-    return False
-
-
-def PostUploadHook(cl, change, output_api):  # pylint: disable=C0103
-    """git cl upload will call this hook after the issue is created/modified.
-
-    This hook adds extra try bots to the CL description in order to run slimming
-    paint v2 tests or LayoutNG tests in addition to the CQ try bots if the
-    change contains changes in a relevant direcotry (see:
-    _ArePaintOrCompositingDirectoriesModified and
-    _AreLayoutNGDirectoriesModified). For more information about
-    slimming-paint-v2 tests see https://crbug.com/601275 and for information
-    about the LayoutNG tests see https://crbug.com/706183.
-    """
-    results = []
-    if _ArePaintOrCompositingDirectoriesModified(change):
-        results.extend(output_api.EnsureCQIncludeTrybotsAreAdded(
-            cl,
-            ['luci.chromium.try:'
-             'linux_layout_tests_slimming_paint_v2',
-             # TODO(kojii): Update linux_trusty_blink_rel to luci when migrated.
-             'master.tryserver.blink:linux_trusty_blink_rel'],
-            'Automatically added linux_layout_tests_slimming_paint_v2 and '
-            'linux_trusty_blink_rel to run on CQ due to changes in paint or '
-            'compositing directories.'))
-    if _AreLayoutNGDirectoriesModified(change):
-        results.extend(output_api.EnsureCQIncludeTrybotsAreAdded(
-            cl,
-            ['luci.chromium.try:'
-             'linux_layout_tests_layout_ng'],
-            'Automatically added linux_layout_tests_layout_ng to run on CQ due '
-            'to changes in LayoutNG directories.'))
-    return results
diff --git a/third_party/blink/common/BUILD.gn b/third_party/blink/common/BUILD.gn
index ff4a589b6..4a9d87c 100644
--- a/third_party/blink/common/BUILD.gn
+++ b/third_party/blink/common/BUILD.gn
@@ -27,6 +27,7 @@
     "common_export.h",
     "device_memory/approximated_device_memory.cc",
     "dom_storage/session_storage_namespace_id.cc",
+    "download/download_stats.cc",
     "experiments/memory_ablation_experiment.cc",
     "feature_policy/feature_policy.cc",
     "features.cc",
diff --git a/third_party/blink/common/download/download_stats.cc b/third_party/blink/common/download/download_stats.cc
new file mode 100644
index 0000000..ca392a7e
--- /dev/null
+++ b/third_party/blink/common/download/download_stats.cc
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/common/download/download_stats.h"
+
+#include "base/metrics/histogram_macros.h"
+
+namespace blink {
+
+// static
+DownloadStats::FrameGesture DownloadStats::GetMetricsEnum(FrameType frame,
+                                                          GestureType gesture) {
+  switch (frame) {
+    case FrameType::kMainFrame:
+      return gesture == GestureType::kWithGesture
+                 ? FrameGesture::kMainFrameGesture
+                 : FrameGesture::kMainFrameNoGesture;
+    case FrameType::kSameOriginAdSubframe:
+      return gesture == GestureType::kWithGesture
+                 ? FrameGesture::kSameOriginAdSubframeGesture
+                 : FrameGesture::kSameOriginAdSubframeNoGesture;
+    case FrameType::kSameOriginNonAdSubframe:
+      return gesture == GestureType::kWithGesture
+                 ? FrameGesture::kSameOriginNonAdSubframeGesture
+                 : FrameGesture::kSameOriginNonAdSubframeNoGesture;
+    case FrameType::kCrossOriginAdSubframe:
+      return gesture == GestureType::kWithGesture
+                 ? FrameGesture::kCrossOriginAdSubframeGesture
+                 : FrameGesture::kCrossOriginAdSubframeNoGesture;
+    case FrameType::kCrossOriginNonAdSubframe:
+      return gesture == GestureType::kWithGesture
+                 ? FrameGesture::kCrossOriginNonAdSubframeGesture
+                 : FrameGesture::kCrossOriginNonAdSubframeNoGesture;
+  }
+}
+
+// static
+void DownloadStats::Record(FrameType frame, GestureType gesture) {
+  UMA_HISTOGRAM_ENUMERATION("Download.FrameGesture",
+                            GetMetricsEnum(frame, gesture));
+}
+
+}  // namespace blink
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 5acae75..85d3a0198 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -119,7 +119,6 @@
   sources = [
     "platform/blame_context.h",
     "platform/code_cache_loader.h",
-    "platform/cors_status.h",
     "platform/file_path_conversion.h",
     "platform/interface_provider.h",
     "platform/interface_registry.h",
@@ -139,6 +138,7 @@
     "platform/modules/indexeddb/web_idb_key_path.h",
     "platform/modules/indexeddb/web_idb_key_range.h",
     "platform/modules/indexeddb/web_idb_metadata.h",
+    "platform/modules/indexeddb/web_idb_name_and_version.h",
     "platform/modules/indexeddb/web_idb_observation.h",
     "platform/modules/indexeddb/web_idb_value.h",
     "platform/modules/installedapp/web_related_application.h",
@@ -164,7 +164,6 @@
     "platform/modules/remoteplayback/web_remote_playback_availability.h",
     "platform/modules/remoteplayback/web_remote_playback_client.h",
     "platform/modules/remoteplayback/web_remote_playback_state.h",
-    "platform/modules/screen_orientation/web_screen_orientation_enum_traits.h",
     "platform/modules/service_worker/web_service_worker_clients_info.h",
     "platform/modules/service_worker/web_service_worker_error.h",
     "platform/modules/service_worker/web_service_worker_network_provider.h",
@@ -243,7 +242,6 @@
     "platform/web_encrypted_media_request.h",
     "platform/web_encrypted_media_types.h",
     "platform/web_file_system_type.h",
-    "platform/web_file_utilities.h",
     "platform/web_float_point.h",
     "platform/web_float_point_3d.h",
     "platform/web_float_rect.h",
@@ -273,7 +271,6 @@
     "platform/web_intrinsic_sizing_info.h",
     "platform/web_isolated_world_ids.h",
     "platform/web_keyboard_event.h",
-    "platform/web_layer_scroll_client.h",
     "platform/web_layer_tree_view.h",
     "platform/web_loading_behavior_flag.h",
     "platform/web_localized_string.h",
@@ -387,8 +384,8 @@
     "web/blink.h",
     "web/mac/web_substring_util.h",
     "web/mac/web_substring_util.h",
-    "web/modules/password_manager/web_form_element_observer.h",
-    "web/modules/password_manager/web_form_element_observer_callback.h",
+    "web/modules/autofill/web_form_element_observer.h",
+    "web/modules/autofill/web_form_element_observer_callback.h",
     "web/modules/service_worker/web_service_worker_context_client.h",
     "web/modules/service_worker/web_service_worker_context_proxy.h",
     "web/web_active_fling_parameters.h",
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index ffb2907..c50207c 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -40,6 +40,7 @@
     "client_hints/client_hints.h",
     "device_memory/approximated_device_memory.h",
     "dom_storage/session_storage_namespace_id.h",
+    "download/download_stats.h",
     "experiments/memory_ablation_experiment.h",
     "feature_policy/feature_policy.h",
     "features.h",
diff --git a/third_party/blink/public/common/download/download_stats.h b/third_party/blink/public/common/download/download_stats.h
new file mode 100644
index 0000000..49b1137
--- /dev/null
+++ b/third_party/blink/public/common/download/download_stats.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_DOWNLOAD_DOWNLOAD_STATS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_DOWNLOAD_DOWNLOAD_STATS_H_
+
+#include "base/macros.h"
+#include "third_party/blink/common/common_export.h"
+
+namespace blink {
+
+class BLINK_COMMON_EXPORT DownloadStats {
+ public:
+  enum class FrameType {
+    kMainFrame,
+    kSameOriginAdSubframe,
+    kSameOriginNonAdSubframe,
+    kCrossOriginAdSubframe,
+    kCrossOriginNonAdSubframe,
+  };
+
+  enum class GestureType {
+    kWithoutGesture,
+    kWithGesture,
+  };
+
+  // Note that these values are reported in UMA. So entries should never be
+  // renumbered, and numeric values should never be reused.
+  enum class FrameGesture {
+    kMainFrameNoGesture = 0,
+    kMainFrameGesture = 1,
+    kSameOriginAdSubframeNoGesture = 2,
+    kSameOriginAdSubframeGesture = 3,
+    kSameOriginNonAdSubframeNoGesture = 4,
+    kSameOriginNonAdSubframeGesture = 5,
+    kCrossOriginAdSubframeNoGesture = 6,
+    kCrossOriginAdSubframeGesture = 7,
+    kCrossOriginNonAdSubframeNoGesture = 8,
+    kCrossOriginNonAdSubframeGesture = 9,
+    kMaxValue = kCrossOriginNonAdSubframeGesture,
+  };
+
+  static FrameGesture GetMetricsEnum(FrameType frame, GestureType gesture);
+
+  static void Record(FrameType frame, GestureType gesture);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DownloadStats);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_DOWNLOAD_DOWNLOAD_STATS_H_
diff --git a/third_party/blink/public/mojom/indexeddb/indexeddb.mojom b/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
index 8de66ed..552ffb44 100644
--- a/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
+++ b/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
@@ -131,6 +131,11 @@
   array<IDBObjectStoreMetadata> object_stores;
 };
 
+struct IDBNameAndVersion {
+  mojo_base.mojom.String16 name;
+  int64 version;
+};
+
 struct IDBIndexKeys {
   int64 index_id;
   array<IDBKey> index_keys;
@@ -188,6 +193,9 @@
 interface IDBCallbacks {
   Error(int32 code, mojo_base.mojom.String16 message);
 
+  // Factory::GetDatabaseInfo
+  SuccessNamesAndVersionsList(array<IDBNameAndVersion> value);
+
   // Factory::GetDatabaseNames
   SuccessStringList(array<mojo_base.mojom.String16> value);
 
@@ -345,6 +353,7 @@
 };
 
 interface IDBFactory {
+  GetDatabaseInfo(associated IDBCallbacks callbacks, url.mojom.Origin origin);
   GetDatabaseNames(associated IDBCallbacks callbacks, url.mojom.Origin origin);
   Open(associated IDBCallbacks callbacks,
        associated IDBDatabaseCallbacks database_callbacks,
diff --git a/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom b/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom
index 9a4e59a..405998d 100644
--- a/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom
+++ b/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom
@@ -30,6 +30,7 @@
   CREDENTIAL_NOT_RECOGNIZED,
   NOT_IMPLEMENTED,
   NOT_FOCUSED,
+  RESIDENT_CREDENTIALS_UNSUPPORTED,
   ANDROID_ALGORITHM_UNSUPPORTED,
   ANDROID_EMPTY_ALLOW_CREDENTIALS,
   ANDROID_NOT_SUPPORTED_ERROR,
diff --git a/third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h b/third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h
index df26944..8941609 100644
--- a/third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h
+++ b/third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h
@@ -37,6 +37,7 @@
 class WebIDBDatabaseError;
 class WebIDBKey;
 struct WebIDBMetadata;
+struct WebIDBNameAndVersion;
 class WebIDBValue;
 
 class WebIDBCallbacks {
@@ -45,6 +46,7 @@
 
   // Pointers transfer ownership.
   virtual void OnError(const WebIDBDatabaseError&) = 0;
+  virtual void OnSuccess(const WebVector<WebIDBNameAndVersion>&) = 0;
   virtual void OnSuccess(const WebVector<WebString>&) = 0;
   virtual void OnSuccess(WebIDBCursor*,
                          WebIDBKey,
diff --git a/third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h b/third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h
index 5739a5e..b99e5d8 100644
--- a/third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h
+++ b/third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h
@@ -47,6 +47,9 @@
  public:
   virtual ~WebIDBFactory() = default;
 
+  virtual void GetDatabaseInfo(WebIDBCallbacks*,
+                               const WebSecurityOrigin&,
+                               scoped_refptr<base::SingleThreadTaskRunner>) = 0;
   virtual void GetDatabaseNames(
       WebIDBCallbacks*,
       const WebSecurityOrigin&,
diff --git a/third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h b/third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h
new file mode 100644
index 0000000..6368c4aa
--- /dev/null
+++ b/third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h
@@ -0,0 +1,20 @@
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_NAME_AND_VERSION_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_NAME_AND_VERSION_H_
+
+#include "third_party/blink/public/platform/web_string.h"
+
+namespace blink {
+
+struct WebIDBNameAndVersion {
+  enum { kNoVersion = -1 };
+  WebString name;
+  int64_t version;
+
+  WebIDBNameAndVersion() : version(kNoVersion) {}
+  WebIDBNameAndVersion(WebString name, int64_t version)
+      : name(name), version(version) {}
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INDEXEDDB_WEB_IDB_NAME_AND_VERSION_H_
diff --git a/third_party/blink/public/platform/modules/webauthn/authenticator.mojom b/third_party/blink/public/platform/modules/webauthn/authenticator.mojom
index 1cb196d..8a35cfa 100644
--- a/third_party/blink/public/platform/modules/webauthn/authenticator.mojom
+++ b/third_party/blink/public/platform/modules/webauthn/authenticator.mojom
@@ -21,6 +21,7 @@
   CREDENTIAL_NOT_RECOGNIZED,
   NOT_IMPLEMENTED,
   NOT_FOCUSED,
+  RESIDENT_CREDENTIALS_UNSUPPORTED,
   USER_VERIFICATION_UNSUPPORTED,
   ALGORITHM_UNSUPPORTED,
   EMPTY_ALLOW_CREDENTIALS,
diff --git a/third_party/blink/public/platform/web_media_player.h b/third_party/blink/public/platform/web_media_player.h
index a1e82caf..131e916 100644
--- a/third_party/blink/public/platform/web_media_player.h
+++ b/third_party/blink/public/platform/web_media_player.h
@@ -125,6 +125,18 @@
     bool skipped = false;
   };
 
+  // Describes when we use SurfaceLayer for video instead of VideoLayer.
+  enum class SurfaceLayerMode {
+    // Always use VideoLayer
+    kNever,
+
+    // Use SurfaceLayer only when we switch to Picture-in-Picture.
+    kOnDemand,
+
+    // Always use SurfaceLayer for video.
+    kAlways,
+  };
+
   // Callback to get notified when the Picture-in-Picture window is opened.
   using PipWindowOpenedCallback = base::OnceCallback<void(const WebSize&)>;
   // Callback to get notified when Picture-in-Picture window is closed.
@@ -199,6 +211,8 @@
   virtual NetworkState GetNetworkState() const = 0;
   virtual ReadyState GetReadyState() const = 0;
 
+  virtual SurfaceLayerMode GetVideoSurfaceLayerMode() const = 0;
+
   // Returns an implementation-specific human readable error message, or an
   // empty string if no message is available. The message should begin with a
   // UA-specific-error-code (without any ':'), optionally followed by ': ' and
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.cc b/third_party/blink/renderer/core/css/css_primitive_value.cc
index f035707..d3a88cbf 100644
--- a/third_party/blink/renderer/core/css/css_primitive_value.cc
+++ b/third_party/blink/renderer/core/css/css_primitive_value.cc
@@ -27,7 +27,7 @@
 #include "third_party/blink/renderer/core/css/css_resolution_units.h"
 #include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
 #include "third_party/blink/renderer/core/css/css_value_pool.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 8a6ca92b..58a1697 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -1062,7 +1062,7 @@
       interpolable: true,
       field_group: "surround",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/platform/layout_unit.h"],
+      include_paths: ["third_party/blink/renderer/platform/geometry/layout_unit.h"],
       keywords: ["thin", "medium", "thick"],
       default_value: "LayoutUnit(3)",
       typedom_types: ["Keyword", "Length"],
@@ -1164,7 +1164,7 @@
       interpolable: true,
       field_group: "surround",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/platform/layout_unit.h"],
+      include_paths: ["third_party/blink/renderer/platform/geometry/layout_unit.h"],
       keywords: ["thin", "medium", "thick"],
       default_value: "LayoutUnit(3)",
       typedom_types: ["Keyword", "Length"],
@@ -1207,7 +1207,7 @@
       interpolable: true,
       field_group: "surround",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/platform/layout_unit.h"],
+      include_paths: ["third_party/blink/renderer/platform/geometry/layout_unit.h"],
       keywords: ["thin", "medium", "thick"],
       default_value: "LayoutUnit(3)",
       typedom_types: ["Keyword", "Length"],
@@ -1274,7 +1274,7 @@
       interpolable: true,
       field_group: "surround",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/platform/layout_unit.h"],
+      include_paths: ["third_party/blink/renderer/platform/geometry/layout_unit.h"],
       keywords: ["thin", "medium", "thick"],
       default_value: "LayoutUnit(3)",
       typedom_types: ["Keyword", "Length"],
@@ -2366,7 +2366,7 @@
       interpolable: true,
       field_group: "*",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/platform/layout_unit.h"],
+      include_paths: ["third_party/blink/renderer/platform/geometry/layout_unit.h"],
       default_value: "LayoutUnit(3)",
       type_name: "LayoutUnit",
       computed_style_custom_functions: ["initial", "getter", "setter"],
@@ -3567,7 +3567,7 @@
       interpolable: true,
       field_group: "*",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/platform/layout_unit.h"],
+      include_paths: ["third_party/blink/renderer/platform/geometry/layout_unit.h"],
       default_value: "LayoutUnit(3)",
       type_name: "LayoutUnit",
       computed_style_custom_functions: ["initial", "getter", "setter"],
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index fd35164e..dae1d10c 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -4,15 +4,114 @@
 
 #include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_display_lock_callback.h"
+#include "third_party/blink/renderer/platform/bindings/microtask.h"
 
 namespace blink {
 
-DisplayLockContext::~DisplayLockContext() {}
+DisplayLockContext::DisplayLockContext(ExecutionContext* context)
+    : ContextLifecycleObserver(context) {}
 
-void DisplayLockContext::Dispose() {}
+DisplayLockContext::~DisplayLockContext() {
+  DCHECK(!resolver_);
+  DCHECK(callbacks_.IsEmpty());
+}
+
+void DisplayLockContext::Trace(blink::Visitor* visitor) {
+  ScriptWrappable::Trace(visitor);
+  ContextLifecycleObserver::Trace(visitor);
+  visitor->Trace(callbacks_);
+  visitor->Trace(resolver_);
+}
+
+void DisplayLockContext::Dispose() {
+  RejectAndCleanUp();
+}
+
+void DisplayLockContext::ContextDestroyed(ExecutionContext*) {
+  RejectAndCleanUp();
+}
+
+bool DisplayLockContext::HasPendingActivity() const {
+  // If we don't have a task scheduled, then we should already be resolved.
+  // TODO(vmpstr): This should also be kept alive if we're doing co-operative
+  // work.
+  DCHECK(process_queue_task_scheduled_ || !resolver_);
+  return process_queue_task_scheduled_;
+}
+
+void DisplayLockContext::ScheduleTask(V8DisplayLockCallback* callback,
+                                      ScriptState* script_state) {
+  callbacks_.push_back(callback);
+  if (!resolver_) {
+    DCHECK(script_state);
+    resolver_ = ScriptPromiseResolver::Create(script_state);
+  }
+  if (!process_queue_task_scheduled_) {
+    DCHECK(GetExecutionContext());
+    DCHECK(GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI));
+    GetExecutionContext()
+        ->GetTaskRunner(TaskType::kMiscPlatformAPI)
+        ->PostTask(FROM_HERE, WTF::Bind(&DisplayLockContext::ProcessQueue,
+                                        WrapWeakPersistent(this)));
+    process_queue_task_scheduled_ = true;
+  }
+}
 
 void DisplayLockContext::schedule(V8DisplayLockCallback* callback) {
-  callback->InvokeAndReportException(nullptr, this);
+  ScheduleTask(callback);
+}
+
+void DisplayLockContext::ProcessQueue() {
+  // It's important to clear this before running the tasks, since the tasks can
+  // call ScheduleTask() which will re-schedule a PostTask() for us to continue
+  // the work.
+  process_queue_task_scheduled_ = false;
+
+  // We might have cleaned up already due to exeuction context being destroyed.
+  if (callbacks_.IsEmpty()) {
+    DCHECK(!resolver_);
+    return;
+  }
+
+  // Get a local copy of all the tasks we will run.
+  // TODO(vmpstr): This should possibly be subject to a budget instead.
+  HeapVector<Member<V8DisplayLockCallback>> callbacks;
+  callbacks.swap(callbacks_);
+
+  for (auto& callback : callbacks) {
+    DCHECK(callback);
+    {
+      // A re-implementation of InvokeAndReportException, in order for us to
+      // be able to query |try_catch| to determine whether or not we need to
+      // reject our promise.
+      v8::TryCatch try_catch(callback->GetIsolate());
+      try_catch.SetVerbose(true);
+
+      auto result = callback->Invoke(nullptr, this);
+      ALLOW_UNUSED_LOCAL(result);
+      if (try_catch.HasCaught()) {
+        RejectAndCleanUp();
+        return;
+      }
+    }
+    Microtask::PerformCheckpoint(callback->GetIsolate());
+  }
+
+  // TODO(vmpstr): This should be resolved after all of the co-operative work
+  // finishes, not here.
+  if (callbacks_.IsEmpty()) {
+    DCHECK(!process_queue_task_scheduled_);
+    resolver_->Resolve();
+    resolver_ = nullptr;
+  }
+}
+
+void DisplayLockContext::RejectAndCleanUp() {
+  if (resolver_) {
+    resolver_->Reject();
+    resolver_ = nullptr;
+  }
+  callbacks_.clear();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index 0d4087bf..cea2024 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -5,22 +5,65 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_CONTEXT_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_CONTEXT_H_
 
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
 namespace blink {
 
 class V8DisplayLockCallback;
-class CORE_EXPORT DisplayLockContext final : public ScriptWrappable {
+class CORE_EXPORT DisplayLockContext final
+    : public ScriptWrappable,
+      public ActiveScriptWrappable<DisplayLockContext>,
+      public ContextLifecycleObserver {
   DEFINE_WRAPPERTYPEINFO();
+  USING_GARBAGE_COLLECTED_MIXIN(DisplayLockContext);
 
  public:
-  DisplayLockContext() = default;
+  DisplayLockContext(ExecutionContext*);
   ~DisplayLockContext() override;
 
+  // GC Functions.
+  void Trace(blink::Visitor*) override;
   void Dispose();
 
+  // ContextLifecycleObserver overrides.
+  void ContextDestroyed(ExecutionContext*) override;
+  // ActiveScriptWrappable overrides. If there is an outstanding task scheduled
+  // to process the callback queue, then this return true.
+  // TODO(vmpstr): In the future this would also be true while we're doing
+  // co-operative work.
+  bool HasPendingActivity() const final;
+
+  // Schedules a new callback. If this is the first callback to be scheduled,
+  // then a valid ScriptState must be provided, which will be used to create a
+  // new ScriptPromiseResolver. In other cases, the ScriptState is ignored.
+  void ScheduleTask(V8DisplayLockCallback*, ScriptState* = nullptr);
+
+  // Returns true if the promise associated with this context was already
+  // resolved (or rejected).
+  bool IsResolved() const { return !resolver_; }
+
+  // Returns a ScriptPromise associated with this context.
+  ScriptPromise Promise() const {
+    DCHECK(resolver_);
+    return resolver_->Promise();
+  }
+
+  // JavaScript interface implementation.
   void schedule(V8DisplayLockCallback*);
+
+ private:
+  // Processes the current queue of callbacks.
+  void ProcessQueue();
+  // Rejects the associated promise if one exists, and clears the current queue.
+  // This effectively makes the context finalized.
+  void RejectAndCleanUp();
+
+  HeapVector<Member<V8DisplayLockCallback>> callbacks_;
+  Member<ScriptPromiseResolver> resolver_;
+  bool process_queue_task_scheduled_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.idl b/third_party/blink/renderer/core/display_lock/display_lock_context.idl
index 67171c7e..2820ade 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.idl
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.idl
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 [RuntimeEnabled=DisplayLocking] callback DisplayLockCallback = void(DisplayLockContext context);
-[RuntimeEnabled=DisplayLocking] interface DisplayLockContext {
+[RuntimeEnabled=DisplayLocking, ActiveScriptWrappable] interface DisplayLockContext {
   void schedule(DisplayLockCallback callback);
 };
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 559a245..851699a1 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3723,14 +3723,10 @@
 
 ScriptPromise Element::acquireDisplayLock(ScriptState* script_state,
                                           V8DisplayLockCallback* callback) {
-  // For now, just invoke the callback, and resolve the promise immediately.
-  // TODO(vmpstr): Finish implementation.
-  callback->InvokeAndReportException(nullptr, new DisplayLockContext);
-
-  auto* resolver = ScriptPromiseResolver::Create(script_state);
-  const auto& promise = resolver->Promise();
-  resolver->Resolve();
-  return promise;
+  auto* context =
+      EnsureElementRareData().EnsureDisplayLockContext(GetExecutionContext());
+  context->ScheduleTask(callback, script_state);
+  return context->Promise();
 }
 
 // Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
diff --git a/third_party/blink/renderer/core/dom/element_rare_data.cc b/third_party/blink/renderer/core/dom/element_rare_data.cc
index eb67c03..641ebf8 100644
--- a/third_party/blink/renderer/core/dom/element_rare_data.cc
+++ b/third_party/blink/renderer/core/dom/element_rare_data.cc
@@ -41,7 +41,7 @@
 struct SameSizeAsElementRareData : NodeRareData {
   IntSize scroll_offset;
   void* pointers_or_strings[5];
-  Member<void*> members[14];
+  Member<void*> members[15];
 };
 
 ElementRareData::ElementRareData(NodeRenderingData* node_layout_data)
@@ -102,6 +102,7 @@
   visitor->Trace(cssom_map_wrapper_);
   visitor->Trace(pseudo_element_data_);
   visitor->Trace(accessible_node_);
+  visitor->Trace(display_lock_context_);
   visitor->Trace(v0_custom_element_definition_);
   visitor->Trace(custom_element_definition_);
   visitor->Trace(intersection_observer_data_);
diff --git a/third_party/blink/renderer/core/dom/element_rare_data.h b/third_party/blink/renderer/core/dom/element_rare_data.h
index b73961b..76fb976 100644
--- a/third_party/blink/renderer/core/dom/element_rare_data.h
+++ b/third_party/blink/renderer/core/dom/element_rare_data.h
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/aom/accessible_node.h"
 #include "third_party/blink/renderer/core/css/cssom/inline_style_property_map.h"
 #include "third_party/blink/renderer/core/css/inline_css_style_declaration.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
 #include "third_party/blink/renderer/core/dom/attr.h"
 #include "third_party/blink/renderer/core/dom/dataset_dom_string_map.h"
 #include "third_party/blink/renderer/core/dom/dom_token_list.h"
@@ -187,6 +188,13 @@
   }
   ResizeObserverDataMap& EnsureResizeObserverData();
 
+  DisplayLockContext* EnsureDisplayLockContext(ExecutionContext* context) {
+    if (!display_lock_context_ || display_lock_context_->IsResolved()) {
+      display_lock_context_ = new DisplayLockContext(context);
+    }
+    return display_lock_context_.Get();
+  }
+
   const AtomicString& GetNonce() const { return nonce_; }
   void SetNonce(const AtomicString& nonce) { nonce_ = nonce; }
 
@@ -221,6 +229,8 @@
 
   TraceWrapperMember<AccessibleNode> accessible_node_;
 
+  Member<DisplayLockContext> display_lock_context_;
+
   explicit ElementRareData(NodeRenderingData*);
 };
 
diff --git a/third_party/blink/renderer/core/editing/selection_modifier.h b/third_party/blink/renderer/core/editing/selection_modifier.h
index 6d9ce42..13d61c5 100644
--- a/third_party/blink/renderer/core/editing/selection_modifier.h
+++ b/third_party/blink/renderer/core/editing/selection_modifier.h
@@ -31,7 +31,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/editing/selection_template.h"
 #include "third_party/blink/renderer/core/editing/visible_selection.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/frame/ad_tracker.cc b/third_party/blink/renderer/core/frame/ad_tracker.cc
index 75f95c5..3bc797d 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker.cc
+++ b/third_party/blink/renderer/core/frame/ad_tracker.cc
@@ -109,10 +109,12 @@
                                 const ResourceResponse& redirect_response,
                                 const FetchInitiatorInfo& initiator_info,
                                 ResourceType resource_type) {
-  // If the resource is not already marked as an ad, check if any executing
-  // script is an ad. If yes, mark this as an ad.
-  if (!request.IsAdResource() && IsAdScriptInStack())
+  // If the resource is not already marked as an ad, check if the document
+  // loading the resource is an ad or if any executing script is an ad.
+  if (!request.IsAdResource() &&
+      (IsKnownAdExecutionContext(execution_context) || IsAdScriptInStack())) {
     request.SetIsAdResource();
+  }
 
   // If it is a script marked as an ad and it's not in an ad context, append it
   // to the known ad script set. We don't need to keep track of ad scripts in ad
diff --git a/third_party/blink/renderer/core/frame/ad_tracker_test.cc b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
index 0bf2d21..c9572f0c 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker_test.cc
+++ b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
@@ -237,6 +237,37 @@
   EXPECT_TRUE(ad_tracker_->IsAdScriptInStack());
 }
 
+TEST_F(AdTrackerSimTest, AdResourceDetectedByContext) {
+  SimRequest ad_script("https://example.com/ad_script.js", "text/javascript");
+  SimRequest ad_frame("https://example.com/ad_frame.html", "text/html");
+  SimRequest foo_css("https://example.com/foo.css", "text/style");
+  ad_tracker_->SetAdSuffix("ad_script.js");
+
+  // Create an iframe that's considered an ad.
+  main_resource_->Complete("<body><script src='ad_script.js'></script></body>");
+  ad_script.Complete(R"SCRIPT(
+    frame = document.createElement("iframe");
+    frame.src="ad_frame.html";
+    document.body.appendChild(frame);
+    )SCRIPT");
+
+  // The child frame should be an ad subframe.
+  LocalFrame* child_frame =
+      ToLocalFrame(GetDocument().GetFrame()->Tree().FirstChild());
+  EXPECT_TRUE(child_frame->IsAdSubframe());
+
+  // Load a resource from the frame. It should be detected as an ad resource due
+  // to its context.
+  ad_frame.Complete(R"HTML(
+    <link rel="stylesheet" href="foo.css">
+    )HTML");
+
+  foo_css.Complete("");
+
+  EXPECT_TRUE(
+      ad_tracker_->RequestWithUrlTaggedAsAd("https://example.com/foo.css"));
+}
+
 // When inline script in an ad frame inserts an iframe into a non-ad frame, the
 // new frame should be considered an ad.
 TEST_F(AdTrackerSimTest, InlineAdScriptRunningInNonAdContext) {
diff --git a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
index a0e61ab..090bce5 100644
--- a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
+++ b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
@@ -42,6 +42,7 @@
     kDisabledBySystem,
     kDisabledByFeaturePolicy,
     kDisabledByAttribute,
+    kVideoLayerNotSupported,
   };
 
   // Enter Picture-in-Picture for a video element and resolve promise if any.
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc
index aa4f1c5..02e4301 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -24,11 +24,14 @@
 
 #include "third_party/blink/renderer/core/html/html_anchor_element.h"
 
+#include "base/metrics/histogram_macros.h"
+#include "third_party/blink/public/common/download/download_stats.h"
 #include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
 #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
 #include "third_party/blink/renderer/core/events/mouse_event.h"
+#include "third_party/blink/renderer/core/frame/ad_tracker.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
@@ -51,6 +54,28 @@
 
 namespace blink {
 
+namespace {
+
+void RecordDownloadMetrics(LocalFrame* frame) {
+  DownloadStats::FrameType frame_type =
+      frame->IsMainFrame()
+          ? DownloadStats::FrameType::kMainFrame
+          : frame->IsAdSubframe()
+                ? frame->IsCrossOriginSubframe()
+                      ? DownloadStats::FrameType::kCrossOriginAdSubframe
+                      : DownloadStats::FrameType::kSameOriginAdSubframe
+                : frame->IsCrossOriginSubframe()
+                      ? DownloadStats::FrameType::kCrossOriginNonAdSubframe
+                      : DownloadStats::FrameType::kSameOriginNonAdSubframe;
+  DownloadStats::GestureType gesture_type =
+      LocalFrame::HasTransientUserActivation(frame)
+          ? DownloadStats::GestureType::kWithGesture
+          : DownloadStats::GestureType::kWithoutGesture;
+  DownloadStats::Record(frame_type, gesture_type);
+}
+
+}  // namespace
+
 using namespace HTMLNames;
 
 HTMLAnchorElement::HTMLAnchorElement(const QualifiedName& tag_name,
@@ -385,6 +410,7 @@
     // the event is an alt-click or similar.
     if (NavigationPolicyFromEvent(&event) != kNavigationPolicyDownload &&
         GetDocument().GetSecurityOrigin()->CanReadContent(completed_url)) {
+      RecordDownloadMetrics(frame);
       request.SetSuggestedFilename(
           static_cast<String>(FastGetAttribute(downloadAttr)));
       request.SetRequestContext(mojom::RequestContextType::DOWNLOAD);
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index 3db572f..ceb6c03 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -731,6 +731,12 @@
   return !pip_custom_controls_.empty();
 }
 
+bool HTMLVideoElement::UsesSurfaceLayer() const {
+  return GetWebMediaPlayer() &&
+         GetWebMediaPlayer()->GetVideoSurfaceLayerMode() !=
+             WebMediaPlayer::SurfaceLayerMode::kNever;
+}
+
 void HTMLVideoElement::SetIsEffectivelyFullscreen(
     blink::WebFullscreenVideoStatus status) {
   is_effectively_fullscreen_ =
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.h b/third_party/blink/renderer/core/html/media/html_video_element.h
index 4b929950..eeeedce 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.h
+++ b/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -189,6 +189,7 @@
   const std::vector<PictureInPictureControlInfo>&
   GetPictureInPictureCustomControls() const;
   bool HasPictureInPictureCustomControls() const;
+  bool UsesSurfaceLayer() const;
 
   void SetIsEffectivelyFullscreen(blink::WebFullscreenVideoStatus);
 
diff --git a/third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h b/third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h
index d7888707..7008563d 100644
--- a/third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h
+++ b/third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h
@@ -28,7 +28,7 @@
 
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_block_flow.h b/third_party/blink/renderer/core/layout/api/line_layout_block_flow.h
index 5cd24511..95a06d1 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_block_flow.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/layout/api/line_layout_box.h"
 #include "third_party/blink/renderer/core/layout/floating_objects.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_box.h b/third_party/blink/renderer/core/layout/api/line_layout_box.h
index 49ec16eb..d288801 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_box.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_box.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/layout/api/line_layout_box_model.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_box_model.h b/third_party/blink/renderer/core/layout/api/line_layout_box_model.h
index e9ddcad..245aa79 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_box_model.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_box_model.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/layout/api/line_layout_item.h"
 #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_inline.h b/third_party/blink/renderer/core/layout/api/line_layout_inline.h
index 885fd9b..3099fb2d 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_inline.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_inline.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/layout/api/line_layout_box_model.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_item.h b/third_party/blink/renderer/core/layout/api/line_layout_item.h
index 15d4a51..799ea6f 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_item.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_item.h
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/core/layout/layout_text.h"
 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
 
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h"
 
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_text.h b/third_party/blink/renderer/core/layout/api/line_layout_text.h
index 5154d69..eb666a9 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_text.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_text.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/layout/api/line_layout_item.h"
 #include "third_party/blink/renderer/core/layout/layout_text.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h b/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h
index a419cf2e..de087cd 100644
--- a/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h
+++ b/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h
@@ -7,8 +7,8 @@
 
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h b/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h
index 7623897..120c688 100644
--- a/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h
+++ b/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h
@@ -7,8 +7,8 @@
 
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index e3390e9..b3c6b84e 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -39,7 +39,7 @@
 #include "third_party/blink/renderer/core/layout/order_iterator.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/geometry/layout_point.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/fragmentation_context.h b/third_party/blink/renderer/core/layout/fragmentation_context.h
index 014d8bf6..0b8b8ba 100644
--- a/third_party/blink/renderer/core/layout/fragmentation_context.h
+++ b/third_party/blink/renderer/core/layout/fragmentation_context.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/geometry/layout_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
index 33f9299..0b2bf5e 100644
--- a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
+++ b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
@@ -12,7 +12,7 @@
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
 #include "third_party/blink/renderer/core/style/grid_track_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/layout_analyzer.h b/third_party/blink/renderer/core/layout/layout_analyzer.h
index 7925e607..b417884 100644
--- a/third_party/blink/renderer/core/layout/layout_analyzer.h
+++ b/third_party/blink/renderer/core/layout/layout_analyzer.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 #include "base/macros.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/layout_theme.h b/third_party/blink/renderer/core/layout/layout_theme.h
index 61e2790d..d3b89e4 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.h
+++ b/third_party/blink/renderer/core/layout/layout_theme.h
@@ -26,8 +26,8 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/platform/fonts/font_selection_types.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 #include "third_party/blink/renderer/platform/scroll/scroll_types.h"
 #include "third_party/blink/renderer/platform/theme_types.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/core/layout/layout_tree_as_text.cc b/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
index ecf03de..bfd6e769 100644
--- a/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
@@ -60,7 +60,7 @@
 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/hex_number.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/core/layout/line/line_width.h b/third_party/blink/renderer/core/layout/line/line_width.h
index e3c5892..6ca5d07 100644
--- a/third_party/blink/renderer/core/layout/line/line_width.h
+++ b/third_party/blink/renderer/core/layout/line/line_width.h
@@ -31,7 +31,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LINE_LINE_WIDTH_H_
 
 #include "third_party/blink/renderer/core/layout/api/line_layout_block_flow.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/min_max_size.h b/third_party/blink/renderer/core/layout/min_max_size.h
index b8069c11..c3fdbde 100644
--- a/third_party/blink/renderer/core/layout/min_max_size.h
+++ b/third_party/blink/renderer/core/layout/min_max_size.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZE_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
index 0d8b68d..e138644 100644
--- a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_rect.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/ref_vector.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h b/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h
index cf853395..830ce49 100644
--- a/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h b/third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h
index 667d37f..2b91cf5 100644
--- a/third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h
index 1bfa71a..f20e112 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h
@@ -6,7 +6,7 @@
 #define NGBfcOffset_h
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_rect.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_rect.h
index a7855ad2..397a581 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_rect.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_rect.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
index 038ec75..4a128618 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h
index 0932dde..00d51ca 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h
@@ -6,7 +6,7 @@
 #define NGLogicalOffset_h
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h
index 773d33c9..fd0fdf0 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
index e46e7a7..ca07b8a 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
@@ -6,7 +6,7 @@
 #define NGMarginStrut_h
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_location.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_location.h
index 3ac884f..3a3ba0d 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_location.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_location.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h
index 9bb9c3a..8acb4de 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h
@@ -6,7 +6,7 @@
 #define NGPhysicalOffset_h
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h
index b894db5..b9604df8 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_rect.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_rect.h
index 3bd44db..179f98c 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_rect.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_rect.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_location.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h
index 784c5f6..0af87f7 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
 #include "third_party/blink/renderer/platform/geometry/layout_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_static_position.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_static_position.h
index 5db6c3fe..7bd2d6c 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_static_position.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_static_position.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h b/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h
index cfcd9a21..081a9d4 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h
@@ -6,7 +6,7 @@
 #define NGBaseline_h
 
 #include "third_party/blink/renderer/platform/fonts/font_baseline.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
index b49228cec..f237ca1d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/platform/fonts/font_baseline.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
index da38185..983cb4f 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 0d9575ff..b4ba1e7a 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -725,8 +725,8 @@
 #endif
 
     // Reset any state that may have been modified in a previous pass.
-    positioned_floats.resize(0);
-    unpositioned_floats_.resize(0);
+    positioned_floats.Shrink(0);
+    unpositioned_floats_.Shrink(0);
     container_builder_.Reset();
     exclusion_space = initial_exclusion_space;
 
@@ -876,7 +876,7 @@
       << "The floats BFC block offset should be known here";
 
   if (BreakToken() && BreakToken()->IgnoreFloats()) {
-    unpositioned_floats_.resize(0);
+    unpositioned_floats_.Shrink(0);
     return;
   }
 
@@ -896,7 +896,7 @@
                  ConstraintSpace(), exclusion_space, &positioned_floats);
 
   positioned_floats_.AppendVector(positioned_floats);
-  unpositioned_floats_.resize(0);
+  unpositioned_floats_.Shrink(0);
 }
 
 void NGInlineLayoutAlgorithm::BidiReorder() {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 8d9b0ff4..6a89933 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -733,7 +733,7 @@
       nullptr /* container_builder */, &empty_exclusion_space, 0u,
       line_opportunity, nullptr /* break_token */);
   do {
-    unpositioned_floats.resize(0);
+    unpositioned_floats.Shrink(0);
 
     NGLineInfo line_info;
     line_breaker.NextLine(&line_info);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
index 8ac5b57b..b14c65d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -127,8 +127,6 @@
 }
 
 scoped_refptr<NGLayoutResult> NGLineBoxFragmentBuilder::ToLineBoxFragment() {
-  DCHECK_EQ(offsets_.size(), children_.size());
-
   WritingMode line_writing_mode(ToLineWritingMode(GetWritingMode()));
   NGPhysicalSize physical_size = Size().ConvertToPhysical(line_writing_mode);
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h
index 7289666..d8d9eba3 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h
@@ -6,7 +6,7 @@
 #define NGLineHeightMetrics_h
 
 #include "third_party/blink/renderer/platform/fonts/font_baseline.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
index 22e207b4..3f120d1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/core/layout/min_max_size.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h b/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
index be8ea67..d87475d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
@@ -8,7 +8,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index ddbfb81..76f3a6f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -2089,7 +2089,7 @@
 
   AddPositionedFloats(positioned_floats);
 
-  unpositioned_floats_.resize(0);
+  unpositioned_floats_.Shrink(0);
 }
 
 template <class Vec>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index ae74ca3..d051cf7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -171,7 +171,7 @@
   // The descendant may be a "position: absolute" which contains a "position:
   // fixed" for example. (This fragment isn't the containing block for the
   // fixed descendant).
-  oof_positioned_candidates_.resize(0);
+  oof_positioned_candidates_.Shrink(0);
 }
 
 void NGContainerFragmentBuilder::MoveOutOfFlowDescendantCandidatesToDescendants(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index b6c8dcf..163f62d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -206,10 +206,6 @@
           child_offset(child_offset_arg),
           is_line_relative(true),
           line_direction(line_direction_arg) {}
-
-    // This constructor is not meant to be called, but required so we can use
-    // Vector::resize(0).
-    NGOutOfFlowPositionedCandidate() {}
   };
 
   NGContainerFragmentBuilder(scoped_refptr<const ComputedStyle>,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
index ffcc9b5..1513bdc 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float_vector.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_fragment.h
index 4c21a682..e02d39a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragment.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
index 830f416..7c97f0a9 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -156,7 +156,6 @@
 
   // A vector of child offsets. Initially set by AddChild().
   const OffsetVector& Offsets() const { return offsets_; }
-  OffsetVector& MutableOffsets() { return offsets_; }
 
   NGPhysicalFragment::NGBoxType BoxType() const;
   NGFragmentBuilder& SetBoxType(NGPhysicalFragment::NGBoxType box_type) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
index db556bf3..cfb23396 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index b9a51df..bf69167 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
 #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index c8305c58..416a2a57 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -13,8 +13,8 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/geometry/length.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
index b3ceaf3..0eafcdc 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
@@ -12,8 +12,8 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/geometry/calculation_value.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/geometry/length.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 
 namespace blink {
 namespace {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 6e3b88fd..1d6c685 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -74,7 +74,7 @@
     }
     // Sweep any descendants that might have been added.
     // This happens when an absolute container has a fixed child.
-    descendant_candidates.resize(0);
+    descendant_candidates.Shrink(0);
     container_builder_->GetAndClearOutOfFlowDescendantCandidates(
         &descendant_candidates, container_builder_->GetLayoutObject());
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h
index 989825d..2f38cb50 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h
@@ -33,10 +33,6 @@
       : node(node_param),
         static_position(static_position_param),
         inline_container(inline_container_param) {}
-
-  // This constructor is not meant to be called, but required so we can use
-  // Vector::resize(0).
-  NGOutOfFlowPositionedDescendant() : node(nullptr) {}
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index ece2440..a9eaf2ed 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -163,10 +163,9 @@
     builder->Append("\n");
 
     if (flags & NGPhysicalFragment::DumpSubtree) {
-      const auto& children = box->Children();
-      for (unsigned i = 0; i < children.size(); i++) {
-        AppendFragmentToString(children[i].get(), children[i].Offset(), builder,
-                               flags, indent + 2);
+      for (auto& child : box->Children()) {
+        AppendFragmentToString(child.get(), child.Offset(), builder, flags,
+                               indent + 2);
       }
     }
     return;
@@ -183,10 +182,9 @@
 
     if (flags & NGPhysicalFragment::DumpSubtree) {
       const auto* line_box = ToNGPhysicalLineBoxFragment(fragment);
-      const auto& children = line_box->Children();
-      for (unsigned i = 0; i < children.size(); i++) {
-        AppendFragmentToString(children[i].get(), children[i].Offset(), builder,
-                               flags, indent + 2);
+      for (auto& child : line_box->Children()) {
+        AppendFragmentToString(child.get(), child.Offset(), builder, flags,
+                               indent + 2);
       }
       return;
     }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h b/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h
index c319680..99d31649 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h
@@ -15,10 +15,6 @@
 
 // Contains the information necessary for copying back data to a FloatingObject.
 struct CORE_EXPORT NGPositionedFloat {
-  // This constructor is not meant to be called, but required so we can use
-  // Vector::resize(0).
-  NGPositionedFloat() {}
-
   NGPositionedFloat(scoped_refptr<NGLayoutResult> layout_result,
                     const NGBfcOffset& bfc_offset);
   ~NGPositionedFloat();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_space_utils.h b/third_party/blink/renderer/core/layout/ng/ng_space_utils.h
index 6641915..17774f6 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_space_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_space_utils.h
@@ -9,7 +9,7 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h b/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
index 8af38a8..c12ecdc 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
@@ -20,10 +20,6 @@
   DISALLOW_NEW();
 
  public:
-  // This constructor is not meant to be called, but required so we can use
-  // Vector::resize(0).
-  NGUnpositionedFloat() : node(nullptr) {}
-
   NGUnpositionedFloat(NGBlockNode node, const NGBlockBreakToken* token)
       : node(node), token(token) {}
 
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm.h b/third_party/blink/renderer/core/layout/table_layout_algorithm.h
index 184533a..6679dbf 100644
--- a/third_party/blink/renderer/core/layout/table_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/table_layout_algorithm.h
@@ -22,7 +22,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_TABLE_LAYOUT_ALGORITHM_H_
 
 #include "base/macros.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.h b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.h
index a55f6e32..0169f1e 100644
--- a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.h
+++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.h
@@ -22,8 +22,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_TABLE_LAYOUT_ALGORITHM_AUTO_H_
 
 #include "third_party/blink/renderer/core/layout/table_layout_algorithm.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/geometry/length.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
index 66cba73d..c6cfd51 100644
--- a/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
+++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
@@ -26,7 +26,7 @@
 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
 #include "third_party/blink/renderer/core/layout/layout_table_col.h"
 #include "third_party/blink/renderer/core/layout/layout_table_section.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 /*
   The text below is from the CSS 2.1 specs.
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.h b/third_party/blink/renderer/core/layout/text_autosizer.h
index 2940200..f67f5c32 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.h
+++ b/third_party/blink/renderer/core/layout/text_autosizer.h
@@ -35,8 +35,8 @@
 #include <memory>
 #include "base/macros.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 
diff --git a/third_party/blink/renderer/core/layout/text_decoration_offset_base.h b/third_party/blink/renderer/core/layout/text_decoration_offset_base.h
index 7c2c9cc9..3d6f4653 100644
--- a/third_party/blink/renderer/core/layout/text_decoration_offset_base.h
+++ b/third_party/blink/renderer/core/layout/text_decoration_offset_base.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/fonts/font_baseline.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/page/context_menu_controller_test.cc b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
index 65d7ad8..3f541d1e 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller_test.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
@@ -26,6 +26,10 @@
  public:
   MOCK_CONST_METHOD0(HasAudio, bool());
   MOCK_CONST_METHOD0(HasVideo, bool());
+
+  SurfaceLayerMode GetVideoSurfaceLayerMode() const override {
+    return SurfaceLayerMode::kAlways;
+  }
 };
 
 class TestWebFrameClientImpl : public FrameTestHelpers::TestWebFrameClient {
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.cc b/third_party/blink/renderer/core/paint/background_image_geometry.cc
index 53351c4..5b1183c 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -15,7 +15,7 @@
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/style/border_edge.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index ccdfb3c1..8a08392 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -84,28 +84,20 @@
 
 using namespace HTMLNames;
 
-static IntRect ContentsRect(const LayoutObject& layout_object) {
+static LayoutRect ContentsRect(const LayoutObject& layout_object) {
   if (!layout_object.IsBox())
-    return IntRect();
-  if (layout_object.IsCanvas()) {
-    return PixelSnappedIntRect(
-        ToLayoutHTMLCanvas(layout_object).ReplacedContentRect());
-  }
-  if (layout_object.IsVideo()) {
-    return PixelSnappedIntRect(
-        ToLayoutVideo(layout_object).ReplacedContentRect());
-  }
-
-  return PixelSnappedIntRect(
-      ToLayoutBox(layout_object).PhysicalContentBoxRect());
+    return LayoutRect();
+  if (layout_object.IsLayoutReplaced())
+    return ToLayoutReplaced(layout_object).ReplacedContentRect();
+  return ToLayoutBox(layout_object).PhysicalContentBoxRect();
 }
 
-static IntRect BackgroundRect(const LayoutObject& layout_object) {
+static LayoutRect BackgroundRect(const LayoutObject& layout_object) {
   if (!layout_object.IsBox())
-    return IntRect();
+    return LayoutRect();
 
   const LayoutBox& box = ToLayoutBox(layout_object);
-  return PixelSnappedIntRect(box.PhysicalBackgroundRect(kBackgroundClipRect));
+  return box.PhysicalBackgroundRect(kBackgroundClipRect);
 }
 
 static inline bool IsTextureLayerCanvas(const LayoutObject& layout_object) {
@@ -198,7 +190,6 @@
 
 CompositedLayerMapping::CompositedLayerMapping(PaintLayer& layer)
     : owning_layer_(layer),
-      content_offset_in_compositing_layer_dirty_(false),
       pending_update_scope_(kGraphicsLayerUpdateNone),
       is_main_frame_layout_view_layer_(false),
       scrolling_contents_are_empty_(false),
@@ -518,7 +509,6 @@
   // FIXME: if this is really needed for performance, it would be better to
   // store it on Layer.
   composited_bounds_ = owning_layer_.BoundingBoxForCompositing();
-  content_offset_in_compositing_layer_dirty_ = true;
 }
 
 GraphicsLayer* CompositedLayerMapping::FrameContentsGraphicsLayer() const {
@@ -565,7 +555,7 @@
           child_containment_layer_
               ? FloatPoint(child_containment_layer_->GetPosition())
               : FloatPoint();
-      document_layer->SetPosition(FloatPoint(FlooredIntPoint(
+      document_layer->SetPosition(FloatPoint(RoundedIntSize(
           FloatPoint(ContentsBox().Location()) - parent_position)));
     }
   }
@@ -1218,8 +1208,6 @@
   UpdateOverflowControlsHostLayerGeometry(compositing_stacking_context,
                                           compositing_container,
                                           graphics_layer_parent_location);
-  UpdateContentsOffsetInCompositingLayer(
-      snapped_offset_from_composited_ancestor, graphics_layer_parent_location);
   UpdateStickyConstraints(GetLayoutObject().StyleRef());
   UpdateSquashingLayerGeometry(
       graphics_layer_parent_location, compositing_container,
@@ -1606,16 +1594,13 @@
 void CompositedLayerMapping::UpdateChildTransformLayerGeometry() {
   if (!child_transform_layer_)
     return;
-  const IntRect border_box =
-      ToLayoutBox(owning_layer_.GetLayoutObject())
-          .PixelSnappedBorderBoxRect(SubpixelAccumulation());
-  child_transform_layer_->SetSize(gfx::Size(border_box.Size()));
-  child_transform_layer_->SetOffsetFromLayoutObject(
-      ToIntSize(border_box.Location()));
-  IntPoint parent_location(
-      child_transform_layer_->Parent()->OffsetFromLayoutObject());
-  child_transform_layer_->SetPosition(
-      FloatPoint(border_box.Location() - parent_location));
+
+  LayoutRect border_box =
+      ToLayoutBox(owning_layer_.GetLayoutObject()).BorderBoxRect();
+  border_box.Move(ContentOffsetInCompositingLayer());
+  child_transform_layer_->SetSize(gfx::Size(border_box.PixelSnappedSize()));
+  child_transform_layer_->SetOffsetFromLayoutObject(IntSize());
+  child_transform_layer_->SetPosition(FloatPoint(border_box.Location()));
 }
 
 void CompositedLayerMapping::UpdateMaskLayerGeometry() {
@@ -1913,59 +1898,6 @@
   graphics_layer_->SetContentsRect(PixelSnappedIntRect(ContentsBox()));
 }
 
-void CompositedLayerMapping::UpdateContentsOffsetInCompositingLayer(
-    const IntPoint& snapped_offset_from_composited_ancestor,
-    const IntPoint& graphics_layer_parent_location) {
-  // m_graphicsLayer is positioned relative to our compositing ancestor
-  // PaintLayer, but it's not positioned at the origin of m_owningLayer, it's
-  // offset by m_contentBounds.location(). This is what
-  // contentOffsetInCompositingLayer is meant to capture, roughly speaking
-  // (ignoring rounding and subpixel accumulation).
-  //
-  // Our ancestor graphics layers in this CLM (m_graphicsLayer and potentially
-  // m_ancestorClippingLayer) have pixel snapped, so if we don't adjust this
-  // offset, we'll see accumulated rounding errors due to that snapping.
-  //
-  // In order to ensure that we account for this rounding, we compute
-  // contentsOffsetInCompositingLayer in a somewhat roundabout way.
-  //
-  // our position = (desired position) - (inherited graphics layer offset).
-  //
-  // Precisely,
-  // Offset = snappedOffsetFromCompositedAncestor -
-  //          offsetDueToAncestorGraphicsLayers (See code below)
-  //        = snappedOffsetFromCompositedAncestor -
-  //          (m_graphicsLayer->position() + graphicsLayerParentLocation)
-  //        = snappedOffsetFromCompositedAncestor -
-  //          (relativeCompositingBounds.location() -
-  //              graphicsLayerParentLocation +
-  //              graphicsLayerParentLocation)
-  //          (See updateMainGraphicsLayerGeometry)
-  //        = snappedOffsetFromCompositedAncestor -
-  //          relativeCompositingBounds.location()
-  //        = snappedOffsetFromCompositedAncestor -
-  //          (pixelSnappedIntRect(contentBounds.location()) +
-  //              snappedOffsetFromCompositedAncestor)
-  //          (See computeBoundsOfOwningLayer)
-  //      = -pixelSnappedIntRect(contentBounds.location())
-  //
-  // As you can see, we've ended up at the same spot
-  // (-contentBounds.location()), but by subtracting off our ancestor graphics
-  // layers positions, we can be sure we've accounted correctly for any pixel
-  // snapping due to ancestor graphics layers.
-  //
-  // And drawing of composited children takes into account the subpixel
-  // accumulation of this CLM already (through its own
-  // graphicsLayerParentLocation it appears).
-  FloatPoint offset_due_to_ancestor_graphics_layers =
-      FloatPoint(graphics_layer_->GetPosition()) +
-      graphics_layer_parent_location;
-  content_offset_in_compositing_layer_ =
-      LayoutSize(snapped_offset_from_composited_ancestor -
-                 offset_due_to_ancestor_graphics_layers);
-  content_offset_in_compositing_layer_dirty_ = false;
-}
-
 void CompositedLayerMapping::UpdateDrawsContent() {
   bool in_overlay_fullscreen_video = false;
   if (GetLayoutObject().IsVideo()) {
@@ -2958,12 +2890,12 @@
 // Return the offset from the top-left of this compositing layer at which the
 // LayoutObject's contents are painted.
 LayoutSize CompositedLayerMapping::ContentOffsetInCompositingLayer() const {
-  DCHECK(!content_offset_in_compositing_layer_dirty_);
-  return content_offset_in_compositing_layer_;
+  return owning_layer_.SubpixelAccumulation() -
+         LayoutSize(graphics_layer_->OffsetFromLayoutObject());
 }
 
 LayoutRect CompositedLayerMapping::ContentsBox() const {
-  LayoutRect contents_box = LayoutRect(ContentsRect(GetLayoutObject()));
+  LayoutRect contents_box = ContentsRect(GetLayoutObject());
   contents_box.Move(ContentOffsetInCompositingLayer());
   return contents_box;
 }
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
index 36c7684..c8f845240 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
@@ -455,9 +455,6 @@
   Color LayoutObjectBackgroundColor() const;
   void UpdateBackgroundColor();
   void UpdateContentsRect();
-  void UpdateContentsOffsetInCompositingLayer(
-      const IntPoint& snapped_offset_from_composited_ancestor,
-      const IntPoint& graphics_layer_parent_location);
   void UpdateAfterPartResize();
   void UpdateCompositingReasons();
 
@@ -666,8 +663,6 @@
 
   LayoutRect composited_bounds_;
 
-  LayoutSize content_offset_in_compositing_layer_;
-
   // We keep track of the scrolling contents offset, so that when it changes we
   // can notify the ScrollingCoordinator, which passes on main-thread scrolling
   // updates to the compositor.
@@ -675,8 +670,6 @@
 
   const PaintLayer* clip_inheritance_ancestor_;
 
-  unsigned content_offset_in_compositing_layer_dirty_ : 1;
-
   unsigned pending_update_scope_ : 2;
   unsigned is_main_frame_layout_view_layer_ : 1;
 
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index 5947a83..096721d 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -1177,35 +1177,35 @@
   // direction to compensate.  To make this a little clearer, for the first
   // example here the layer positions are calculated as:
   //
-  //   m_graphicsLayer x = left_pos - shadow_spread + shadow_x_offset
+  //   graphics_layer_ x = left_pos - shadow_spread + shadow_x_offset
   //                     = 50 - 10 - 10
   //                     = 30
   //
-  //   m_graphicsLayer y = top_pos - shadow_spread + shadow_y_offset
+  //   graphics_layer_ y = top_pos - shadow_spread + shadow_y_offset
   //                     = 50 - 10 + 0
   //                     = 40
   //
-  //   contents x = 50 - m_graphicsLayer x = 50 - 30 = 20
-  //   contents y = 50 - m_graphicsLayer y = 50 - 40 = 10
+  //   contents x = 50 - graphics_layer_ x = 50 - 30 = 20
+  //   contents y = 50 - graphics_layer_ y = 50 - 40 = 10
   //
   // The reason that perspective matters is that it affects which 'contents'
-  // layer is offset; m_childTransformLayer when using perspective, or
-  // m_scrollingLayer when there is no perspective.
+  // layer is offset; child_transform_layer_ when using perspective, or
+  // scrolling_layer_ when there is no perspective.
 
-  SetBodyInnerHTML(
-      "<div id='scroller' style='position: absolute; top: 50px; left: 50px; "
-      "width: 400px; height: 245px; overflow: auto; will-change: transform; "
-      "box-shadow: -10px 0 0 10px; perspective: 1px;'>"
-      "    <div style='position: absolute; top: 50px; bottom: 0; width: 200px; "
-      "height: 200px;'></div>"
-      "</div>"
-
-      "<div id='scroller2' style='position: absolute; top: 400px; left: 50px; "
-      "width: 400px; height: 245px; overflow: auto; will-change: transform; "
-      "box-shadow: -10px 0 0 10px;'>"
-      "    <div style='position: absolute; top: 50px; bottom: 0; width: 200px; "
-      "height: 200px;'></div>"
-      "</div>");
+  SetBodyInnerHTML(R"HTML(
+    <div id='scroller' style='position: absolute; top: 50px; left: 50px;
+        width: 400px; height: 245px; overflow: auto; will-change: transform;
+        box-shadow: -10px 0 0 10px; perspective: 1px;'>
+      <div style='position: absolute; top: 50px; bottom: 0; width: 200px;
+          height: 200px;'></div>
+      </div>
+    <div id='scroller2' style='position: absolute; top: 400px; left: 50px;
+        width: 400px; height: 245px; overflow: auto; will-change: transform;
+        box-shadow: -10px 0 0 10px;'>
+      <div style='position: absolute; top: 50px; bottom: 0; width: 200px;
+          height: 200px;'></div>
+    </div>
+  )HTML");
 
   CompositedLayerMapping* mapping =
       ToLayoutBlock(GetLayoutObjectByElementId("scroller"))
diff --git a/third_party/blink/renderer/core/paint/decoration_info.h b/third_party/blink/renderer/core/paint/decoration_info.h
index a3147ce..6871a017 100644
--- a/third_party/blink/renderer/core/paint/decoration_info.h
+++ b/third_party/blink/renderer/core/paint/decoration_info.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/platform/fonts/font_baseline.h"
 #include "third_party/blink/renderer/platform/geometry/float_point.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/paint/document_marker_painter.cc b/third_party/blink/renderer/core/paint/document_marker_painter.cc
index 4777c420..40063a37 100644
--- a/third_party/blink/renderer/core/paint/document_marker_painter.cc
+++ b/third_party/blink/renderer/core/paint/document_marker_painter.cc
@@ -10,8 +10,8 @@
 #include "third_party/blink/renderer/core/paint/text_paint_style.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/paint/embedded_content_painter.cc b/third_party/blink/renderer/core/paint/embedded_content_painter.cc
index b957865..4ebe5df 100644
--- a/third_party/blink/renderer/core/paint/embedded_content_painter.cc
+++ b/third_party/blink/renderer/core/paint/embedded_content_painter.cc
@@ -30,10 +30,6 @@
       paint_offset +
       layout_embedded_content_.ReplacedContentRect().Location()));
 
-  // Views don't support painting with a paint offset, but instead
-  // offset themselves using the frame rect location. To paint Views at
-  // our desired location, we need to apply paint offset as a transform, with
-  // the frame rect neutralized.
   IntSize view_paint_offset =
       paint_location - embedded_content_view->FrameRect().Location();
   CullRect adjusted_cull_rect(paint_info.GetCullRect(), -view_paint_offset);
diff --git a/third_party/blink/renderer/core/style/nine_piece_image.h b/third_party/blink/renderer/core/style/nine_piece_image.h
index 9de65875..564b2bd 100644
--- a/third_party/blink/renderer/core/style/nine_piece_image.h
+++ b/third_party/blink/renderer/core/style/nine_piece_image.h
@@ -29,9 +29,9 @@
 #include "third_party/blink/renderer/core/style/border_image_length_box.h"
 #include "third_party/blink/renderer/core/style/data_ref.h"
 #include "third_party/blink/renderer/core/style/style_image.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/geometry/length_box.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 
diff --git a/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js b/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js
index 7ae9081..c29c85c 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js
+++ b/third_party/blink/renderer/devtools/front_end/elements/ElementsPanel.js
@@ -932,14 +932,10 @@
         treeOutline.toggleEditAsHTML(node);
         return true;
       case 'elements.undo':
-        if (UI.isEditing())
-          return false;
         SDK.domModelUndoStack.undo();
         Elements.ElementsPanel.instance()._stylesWidget.forceUpdate();
         return true;
       case 'elements.redo':
-        if (UI.isEditing())
-          return false;
         SDK.domModelUndoStack.redo();
         Elements.ElementsPanel.instance()._stylesWidget.forceUpdate();
         return true;
diff --git a/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js b/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
index 6010077..65317dd 100644
--- a/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
+++ b/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
@@ -162,7 +162,6 @@
 
     this._codeMirror.on('changes', this._changes.bind(this));
     this._codeMirror.on('beforeSelectionChange', this._beforeSelectionChange.bind(this));
-    this._codeMirror.on('keyHandled', this._onKeyHandled.bind(this));
 
     this.element.style.overflow = 'hidden';
     this._codeMirrorElement.classList.add('source-code');
@@ -374,10 +373,6 @@
     return this;
   }
 
-  _onKeyHandled() {
-    UI.shortcutRegistry.dismissPendingShortcutAction();
-  }
-
   /**
    * @param {number} lineNumber
    * @param {number} lineLength
diff --git a/third_party/blink/renderer/devtools/front_end/ui/ShortcutRegistry.js b/third_party/blink/renderer/devtools/front_end/ui/ShortcutRegistry.js
index 0178835..648ca00 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/ShortcutRegistry.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/ShortcutRegistry.js
@@ -118,36 +118,18 @@
    * @param {string} domKey
    * @param {!KeyboardEvent=} event
    */
-  handleKey(key, domKey, event) {
+  async handleKey(key, domKey, event) {
     const keyModifiers = key >> 8;
     const actions = this._applicableActions(key);
-    if (!actions.length)
+    if (!actions.length || isPossiblyInputKey())
       return;
-    if (UI.Dialog.hasInstance()) {
-      if (event && !isPossiblyInputKey())
-        event.consume(true);
+    if (event)
+      event.consume(true);
+    if (UI.Dialog.hasInstance())
       return;
-    }
-
-    if (!isPossiblyInputKey()) {
-      if (event)
-        event.consume(true);
-      processNextAction.call(this, false);
-    } else {
-      this._pendingActionTimer = setTimeout(processNextAction.bind(this, false), 0);
-    }
-
-    /**
-     * @param {boolean} handled
-     * @this {UI.ShortcutRegistry}
-     */
-    function processNextAction(handled) {
-      delete this._pendingActionTimer;
-      const action = actions.shift();
-      if (!action || handled)
+    for (const action of actions) {
+      if (await action.execute())
         return;
-
-      action.execute().then(processNextAction.bind(this));
     }
 
     /**
@@ -203,18 +185,10 @@
     this._defaultKeyToActions.set(String(descriptor.key), actionId);
   }
 
-  dismissPendingShortcutAction() {
-    if (this._pendingActionTimer) {
-      clearTimeout(this._pendingActionTimer);
-      delete this._pendingActionTimer;
-    }
-  }
-
   /**
    * @param {!Document} document
    */
   _registerBindings(document) {
-    document.addEventListener('input', this.dismissPendingShortcutAction.bind(this), true);
     const extensions = self.runtime.extensions('action');
     extensions.forEach(registerExtension, this);
 
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 0611291..795f1230 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -267,6 +267,7 @@
     "eventsource/event_source_parser_test.cc",
     "filesystem/dom_file_system_base_test.cc",
     "filesystem/file_writer_test.cc",
+    "indexeddb/idb_factory_test.cc",
     "indexeddb/idb_key_path_test.cc",
     "indexeddb/idb_request_test.cc",
     "indexeddb/idb_test_helper.cc",
@@ -274,6 +275,8 @@
     "indexeddb/idb_value_wrapping_test.cc",
     "indexeddb/mock_web_idb_database.cc",
     "indexeddb/mock_web_idb_database.h",
+    "indexeddb/mock_web_idb_factory.cc",
+    "indexeddb/mock_web_idb_factory.h",
     "manifest/image_resource_type_converters_test.cc",
     "media_controls/elements/media_control_animated_arrow_container_element_test.cc",
     "media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
index b83a8e6c..8074aec 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
@@ -34,7 +34,7 @@
 #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
 #include "third_party/blink/renderer/modules/accessibility/ax_position.h"
 #include "third_party/blink/renderer/modules/accessibility/ax_range.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
index 2722b7d..1d7b7ee 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
@@ -36,7 +36,6 @@
 
 WorkletGlobalScopeProxy* AnimationWorklet::CreateGlobalScope() {
   DCHECK(NeedsToCreateGlobalScope());
-  AnimationWorkletThread::EnsureSharedBackingThread();
 
   Document* document = To<Document>(GetExecutionContext());
   AnimationWorkletProxyClient* proxy_client =
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
index 13e1c9b2..dfbdae8 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
@@ -57,7 +57,6 @@
   AnimationWorkletGlobalScopeTest() = default;
 
   void SetUp() override {
-    AnimationWorkletThread::EnsureSharedBackingThread();
     PageTestBase::SetUp(IntSize());
     Document* document = &GetDocument();
     document->SetURL(KURL("https://example.com/"));
@@ -65,10 +64,6 @@
     reporting_proxy_ = std::make_unique<WorkerReportingProxy>();
   }
 
-  void TearDown() override {
-    AnimationWorkletThread::ClearSharedBackingThread();
-  }
-
   std::unique_ptr<AnimationWorkletThread> CreateAnimationWorkletThread(
       AnimationWorkletProxyClient* proxy_client) {
     std::unique_ptr<AnimationWorkletThread> thread =
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc
index 6f047664..3f687505 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc
@@ -15,6 +15,10 @@
 
 namespace blink {
 
+namespace {
+unsigned s_ref_count = 0;
+}
+
 std::unique_ptr<AnimationWorkletThread> AnimationWorkletThread::Create(
     WorkerReportingProxy& worker_reporting_proxy) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("animation-worklet"),
@@ -27,9 +31,19 @@
 
 AnimationWorkletThread::AnimationWorkletThread(
     WorkerReportingProxy& worker_reporting_proxy)
-    : WorkerThread(worker_reporting_proxy) {}
+    : WorkerThread(worker_reporting_proxy) {
+  DCHECK(IsMainThread());
+  if (++s_ref_count == 1) {
+    EnsureSharedBackingThread();
+  }
+}
 
-AnimationWorkletThread::~AnimationWorkletThread() = default;
+AnimationWorkletThread::~AnimationWorkletThread() {
+  DCHECK(IsMainThread());
+  if (--s_ref_count == 0) {
+    ClearSharedBackingThread();
+  }
+}
 
 WorkerBackingThread& AnimationWorkletThread::GetWorkerBackingThread() {
   return *WorkletThreadHolder<AnimationWorkletThread>::GetInstance()
@@ -53,15 +67,6 @@
   done_event.Wait();
 }
 
-void AnimationWorkletThread::EnsureSharedBackingThread() {
-  WorkletThreadHolder<AnimationWorkletThread>::EnsureInstance(
-      ThreadCreationParams(WebThreadType::kAnimationWorkletThread));
-}
-
-void AnimationWorkletThread::ClearSharedBackingThread() {
-  WorkletThreadHolder<AnimationWorkletThread>::ClearInstance();
-}
-
 WorkerOrWorkletGlobalScope* AnimationWorkletThread::CreateWorkerGlobalScope(
     std::unique_ptr<GlobalScopeCreationParams> creation_params) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("animation-worklet"),
@@ -69,4 +74,22 @@
   return AnimationWorkletGlobalScope::Create(std::move(creation_params), this);
 }
 
+void AnimationWorkletThread::EnsureSharedBackingThread() {
+  DCHECK(IsMainThread());
+  WorkletThreadHolder<AnimationWorkletThread>::EnsureInstance(
+      ThreadCreationParams(WebThreadType::kAnimationWorkletThread));
+}
+
+void AnimationWorkletThread::ClearSharedBackingThread() {
+  DCHECK(IsMainThread());
+  DCHECK_EQ(s_ref_count, 0u);
+  WorkletThreadHolder<AnimationWorkletThread>::ClearInstance();
+}
+
+// static
+WorkletThreadHolder<AnimationWorkletThread>*
+AnimationWorkletThread::GetWorkletThreadHolderForTesting() {
+  return WorkletThreadHolder<AnimationWorkletThread>::GetInstance();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h b/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h
index 622a771..7f1849e 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
+#include "third_party/blink/renderer/core/workers/worklet_thread_holder.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 
 namespace blink {
@@ -29,8 +30,8 @@
   // This may block the main thread.
   static void CollectAllGarbage();
 
-  static void EnsureSharedBackingThread();
-  static void ClearSharedBackingThread();
+  static WorkletThreadHolder<AnimationWorkletThread>*
+  GetWorkletThreadHolderForTesting();
 
  private:
   explicit AnimationWorkletThread(WorkerReportingProxy&);
@@ -43,6 +44,9 @@
   WebThreadType GetThreadType() const override {
     return WebThreadType::kAnimationWorkletThread;
   }
+
+  void EnsureSharedBackingThread();
+  void ClearSharedBackingThread();
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread_test.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread_test.cc
index e7462ff0..c4f7d941 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread_test.cc
@@ -24,6 +24,7 @@
 #include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
 #include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h"
+#include "third_party/blink/renderer/core/workers/worklet_thread_holder.h"
 #include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h"
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/loader/fetch/access_control_status.h"
@@ -48,7 +49,6 @@
 class AnimationWorkletThreadTest : public PageTestBase {
  public:
   void SetUp() override {
-    AnimationWorkletThread::EnsureSharedBackingThread();
     PageTestBase::SetUp(IntSize());
     Document* document = &GetDocument();
     document->SetURL(KURL("https://example.com/"));
@@ -56,10 +56,6 @@
     reporting_proxy_ = std::make_unique<WorkerReportingProxy>();
   }
 
-  void TearDown() override {
-    AnimationWorkletThread::ClearSharedBackingThread();
-  }
-
   std::unique_ptr<AnimationWorkletThread> CreateAnimationWorkletThread() {
     WorkerClients* clients = WorkerClients::Create();
     ProvideAnimationWorkletProxyClientTo(clients,
@@ -161,8 +157,8 @@
   second_worklet->WaitForShutdownForTesting();
 }
 
-// Tests that a new WebThread is created if all existing worklets are
-// terminated before a new worklet is created.
+// Tests that the WebThread is reused if all existing worklets are terminated
+// before a new worklet is created, as long as the worklets are not destructed.
 TEST_F(AnimationWorkletThreadTest, TerminateFirstAndCreateSecond) {
   // Create the first worklet, wait until it is initialized, and terminate it.
   std::unique_ptr<AnimationWorkletThread> worklet =
@@ -216,4 +212,42 @@
   second_worklet->WaitForShutdownForTesting();
 }
 
+// Tests that the backing thread is correctly created, torn down, and recreated
+// as AnimationWorkletThreads are created and destroyed.
+TEST_F(AnimationWorkletThreadTest, WorkletThreadHolderIsRefCountedProperly) {
+  EXPECT_FALSE(AnimationWorkletThread::GetWorkletThreadHolderForTesting());
+
+  std::unique_ptr<AnimationWorkletThread> worklet =
+      CreateAnimationWorkletThread();
+  ASSERT_TRUE(worklet.get());
+  WorkletThreadHolder<AnimationWorkletThread>* holder =
+      AnimationWorkletThread::GetWorkletThreadHolderForTesting();
+  EXPECT_TRUE(holder);
+
+  std::unique_ptr<AnimationWorkletThread> worklet2 =
+      CreateAnimationWorkletThread();
+  ASSERT_TRUE(worklet2.get());
+  WorkletThreadHolder<AnimationWorkletThread>* holder2 =
+      AnimationWorkletThread::GetWorkletThreadHolderForTesting();
+  EXPECT_EQ(holder, holder2);
+
+  worklet->Terminate();
+  worklet->WaitForShutdownForTesting();
+  worklet.reset();
+  EXPECT_TRUE(AnimationWorkletThread::GetWorkletThreadHolderForTesting());
+
+  worklet2->Terminate();
+  worklet2->WaitForShutdownForTesting();
+  worklet2.reset();
+  EXPECT_FALSE(AnimationWorkletThread::GetWorkletThreadHolderForTesting());
+
+  std::unique_ptr<AnimationWorkletThread> worklet3 =
+      CreateAnimationWorkletThread();
+  ASSERT_TRUE(worklet3.get());
+  EXPECT_TRUE(AnimationWorkletThread::GetWorkletThreadHolderForTesting());
+
+  worklet3->Terminate();
+  worklet3->WaitForShutdownForTesting();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
index 29e53d2..00a4070 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
@@ -391,15 +391,8 @@
 
   DCHECK_EQ(effects_.size(), local_times_.size());
   for (size_t i = 0; i < effects_.size(); ++i) {
-    // TODO(crbug.com/756539): For now we use 0 as inherited time for compositor
-    // worklet animations. Will need to get the inherited time from worklet
-    // context.
-    double inherited_time_seconds = 0;
-
-    if (local_times_[i])
-      inherited_time_seconds = local_times_[i]->InSecondsF();
-
-    effects_[i]->UpdateInheritedTime(inherited_time_seconds, reason);
+    effects_[i]->UpdateInheritedTime(
+        local_times_[i] ? local_times_[i]->InSecondsF() : NullValue(), reason);
   }
 }
 
diff --git a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
index ba81e262..0d589c38e 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
@@ -130,6 +130,9 @@
       return CredentialManagerError::NOT_IMPLEMENTED;
     case blink::mojom::blink::AuthenticatorStatus::NOT_FOCUSED:
       return CredentialManagerError::NOT_FOCUSED;
+    case blink::mojom::blink::AuthenticatorStatus::
+        RESIDENT_CREDENTIALS_UNSUPPORTED:
+      return CredentialManagerError::RESIDENT_CREDENTIALS_UNSUPPORTED;
     case blink::mojom::blink::AuthenticatorStatus::ALGORITHM_UNSUPPORTED:
       return CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED;
     case blink::mojom::blink::AuthenticatorStatus::EMPTY_ALLOW_CREDENTIALS:
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
index cdee03b..5b0c42c 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -241,6 +241,11 @@
       return DOMException::Create(DOMExceptionCode::kNotAllowedError,
                                   "The operation is not allowed at this time "
                                   "because the page does not have focus.");
+    case CredentialManagerError::RESIDENT_CREDENTIALS_UNSUPPORTED:
+      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
+                                  "Resident credentials or empty "
+                                  "'allowCredentials' lists are not supported "
+                                  "at this time.");
     case CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED:
       return DOMException::Create(DOMExceptionCode::kNotSupportedError,
                                   "None of the algorithms specified in "
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_database_info.idl b/third_party/blink/renderer/modules/indexeddb/idb_database_info.idl
new file mode 100644
index 0000000..81b3c0fb
--- /dev/null
+++ b/third_party/blink/renderer/modules/indexeddb/idb_database_info.idl
@@ -0,0 +1,10 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Spec pull-request for addition:
+// https://github.com/w3c/IndexedDB/pull/240/commits
+dictionary IDBDatabaseInfo {
+  DOMString name;
+  unsigned long long version;
+};
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_factory.cc b/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
index 3f70fec..1e123b7a 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
@@ -29,32 +29,155 @@
 #include "third_party/blink/renderer/modules/indexeddb/idb_factory.h"
 
 #include <memory>
+#include <utility>
+
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_callbacks.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_callbacks.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h"
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.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/probe/core_probes.h"
+#include "third_party/blink/renderer/modules/indexed_db_names.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
+#include "third_party/blink/renderer/modules/indexeddb/idb_database_info.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
 #include "third_party/blink/renderer/modules/indexeddb/indexed_db_client.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
 
+namespace {
+
+class WebIDBGetDBNamesCallbacksImpl : public WebIDBCallbacks {
+ public:
+  // static
+  static std::unique_ptr<WebIDBGetDBNamesCallbacksImpl> Create(
+      ScriptPromiseResolver* promise_resolver) {
+    return base::WrapUnique(
+        new WebIDBGetDBNamesCallbacksImpl(promise_resolver));
+  }
+
+  WebIDBGetDBNamesCallbacksImpl(ScriptPromiseResolver* promise_resolver)
+      : promise_resolver_(promise_resolver) {
+    probe::AsyncTaskScheduled(
+        ExecutionContext::From(promise_resolver_->GetScriptState()),
+        IndexedDBNames::IndexedDB, this);
+  }
+
+  ~WebIDBGetDBNamesCallbacksImpl() override {
+    if (promise_resolver_) {
+      probe::AsyncTaskCanceled(
+          ExecutionContext::From(promise_resolver_->GetScriptState()), this);
+      promise_resolver_->Reject(
+          DOMException::Create(DOMExceptionCode::kUnknownError,
+                               "An unexpected shutdown occured before the "
+                               "databases() promise could be resolved"));
+    }
+  }
+
+  void OnError(const WebIDBDatabaseError& error) override {
+    if (!promise_resolver_)
+      return;
+
+    probe::AsyncTask async_task(
+        ExecutionContext::From(promise_resolver_->GetScriptState()), this,
+        "error");
+    promise_resolver_->Reject(
+        DOMException::Create(DOMExceptionCode::kUnknownError,
+                             "The databases() promise was rejected."));
+    promise_resolver_.Clear();
+  }
+
+  void OnSuccess(const WebVector<WebIDBNameAndVersion>&
+                     web_database_name_and_version_list) override {
+    if (!promise_resolver_)
+      return;
+
+    HeapVector<IDBDatabaseInfo> database_name_and_version_list;
+    for (size_t i = 0; i < web_database_name_and_version_list.size(); ++i) {
+      IDBDatabaseInfo idb_info;
+      idb_info.setName(web_database_name_and_version_list[i].name);
+      idb_info.setVersion(web_database_name_and_version_list[i].version);
+      database_name_and_version_list.push_back(idb_info);
+    }
+    probe::AsyncTask async_task(
+        ExecutionContext::From(promise_resolver_->GetScriptState()), this,
+        "success");
+    promise_resolver_->Resolve(database_name_and_version_list);
+    promise_resolver_.Clear();
+  }
+
+  void OnSuccess(const WebVector<WebString>&) override { NOTREACHED(); }
+
+  void OnSuccess(WebIDBCursor* cursor,
+                 WebIDBKey key,
+                 WebIDBKey primary_key,
+                 WebIDBValue value) override {
+    NOTREACHED();
+  }
+
+  void OnSuccess(WebIDBDatabase* backend,
+                 const WebIDBMetadata& metadata) override {
+    NOTREACHED();
+  }
+
+  void OnSuccess(WebIDBKey key) override { NOTREACHED(); }
+
+  void OnSuccess(WebIDBValue value) override { NOTREACHED(); }
+
+  void OnSuccess(WebVector<WebIDBValue> values) override { NOTREACHED(); }
+
+  void OnSuccess(long long value) override { NOTREACHED(); }
+
+  void OnSuccess() override { NOTREACHED(); }
+
+  void OnSuccess(WebIDBKey key,
+                 WebIDBKey primary_key,
+                 WebIDBValue value) override {
+    NOTREACHED();
+  }
+
+  void OnBlocked(long long old_version) override { NOTREACHED(); }
+
+  void OnUpgradeNeeded(long long old_version,
+                       WebIDBDatabase* database,
+                       const WebIDBMetadata& metadata,
+                       unsigned short data_loss,
+                       WebString data_loss_message) override {
+    NOTREACHED();
+  }
+
+  void Detach() override { NOTREACHED(); }
+
+ private:
+  Persistent<ScriptPromiseResolver> promise_resolver_;
+};
+
+}  // namespace
+
 static const char kPermissionDeniedErrorMessage[] =
     "The user denied permission to access the database.";
 
 IDBFactory::IDBFactory() = default;
 
+IDBFactory::IDBFactory(std::unique_ptr<WebIDBFactory> web_idb_factory)
+    : web_idb_factory_(std::move(web_idb_factory)) {}
+
 static bool IsContextValid(ExecutionContext* context) {
   DCHECK(IsA<Document>(context) || context->IsWorkerGlobalScope());
   if (auto* document = DynamicTo<Document>(context))
@@ -68,6 +191,19 @@
   return web_idb_factory_.get();
 }
 
+ScriptPromise IDBFactory::GetDatabaseInfo(ScriptState* script_state,
+                                          ExceptionState& exception_state) {
+  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+  GetFactory()->GetDatabaseInfo(
+      WebIDBGetDBNamesCallbacksImpl::Create(resolver).release(),
+      WebSecurityOrigin(
+          ExecutionContext::From(script_state)->GetSecurityOrigin()),
+      ExecutionContext::From(script_state)
+          ->GetTaskRunner(TaskType::kInternalIndexedDB));
+  ScriptPromise promise = resolver->Promise();
+  return promise;
+}
+
 IDBRequest* IDBFactory::GetDatabaseNames(ScriptState* script_state,
                                          ExceptionState& exception_state) {
   IDB_TRACE("IDBFactory::getDatabaseNamesRequestSetup");
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_factory.h b/third_party/blink/renderer/modules/indexeddb/idb_factory.h
index bc54174..3d7e36d 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_factory.h
+++ b/third_party/blink/renderer/modules/indexeddb/idb_factory.h
@@ -25,11 +25,14 @@
  * (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_MODULES_INDEXEDDB_IDB_FACTORY_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_FACTORY_H_
 
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_open_db_request.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -39,11 +42,15 @@
 class ExceptionState;
 class ScriptState;
 
-class IDBFactory final : public ScriptWrappable {
+class MODULES_EXPORT IDBFactory final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
   static IDBFactory* Create() { return new IDBFactory(); }
+  static IDBFactory* CreateForTest(
+      std::unique_ptr<WebIDBFactory> web_idb_factory) {
+    return new IDBFactory(std::move(web_idb_factory));
+  }
 
   // Implement the IDBFactory IDL
   IDBOpenDBRequest* open(ScriptState*, const String& name, ExceptionState&);
@@ -65,8 +72,11 @@
                                                       const String& name,
                                                       ExceptionState&);
 
+  ScriptPromise GetDatabaseInfo(ScriptState*, ExceptionState&);
+
  private:
   IDBFactory();
+  IDBFactory(std::unique_ptr<WebIDBFactory>);
 
   WebIDBFactory* GetFactory();
 
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_factory.idl b/third_party/blink/renderer/modules/indexeddb/idb_factory.idl
index 57cc48a7..3f9d847 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_factory.idl
+++ b/third_party/blink/renderer/modules/indexeddb/idb_factory.idl
@@ -29,13 +29,19 @@
     Exposed=(Window,Worker)
 ] interface IDBFactory {
     [
-        NewObject,
-        CallWith=ScriptState,
-        Measure,
-        RaisesException
+      NewObject,
+      CallWith=ScriptState,
+      Measure,
+      RaisesException
     ] IDBOpenDBRequest open(DOMString name,
                             optional [EnforceRange] unsigned long long version);
     [NewObject, CallWith=ScriptState, RaisesException] IDBOpenDBRequest deleteDatabase(DOMString name);
-
     [CallWith=ScriptState, RaisesException] short cmp(any first, any second);
+    [
+      CallWith=ScriptState,
+      ImplementedAs=GetDatabaseInfo,
+      RaisesException,
+      RuntimeEnabled=IDBGetDatabases
+    ] Promise<sequence<IDBDatabaseInfo>> databases();
 };
+
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc b/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc
new file mode 100644
index 0000000..0e7351a
--- /dev/null
+++ b/third_party/blink/renderer/modules/indexeddb/idb_factory_test.cc
@@ -0,0 +1,128 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/indexeddb/idb_factory.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/scoped_refptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+
+namespace blink {
+namespace {
+
+class TestHelperFunction : public ScriptFunction {
+ public:
+  static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
+                                                bool* called_flag) {
+    auto* self = new TestHelperFunction(script_state, called_flag);
+    return self->BindToV8Function();
+  }
+
+ private:
+  TestHelperFunction(ScriptState* script_state, bool* called_flag)
+      : ScriptFunction(script_state), called_flag_(called_flag) {}
+
+  ScriptValue Call(ScriptValue value) override {
+    *called_flag_ = true;
+    return value;
+  }
+
+  bool* called_flag_;
+};
+
+class IDBFactoryTest : public testing::Test {
+ protected:
+  IDBFactoryTest() {}
+
+  ~IDBFactoryTest() override {}
+};
+
+ACTION_TEMPLATE(SaveUniquePointer,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_1_VALUE_PARAMS(unique_pointer)) {
+  *unique_pointer = base::WrapUnique(std::get<k>(args));
+}
+
+TEST_F(IDBFactoryTest, WebIDBGetDBNamesCallbacksResolvesPromise) {
+  V8TestingScope scope;
+  std::unique_ptr<MockWebIDBFactory> web_factory = MockWebIDBFactory::Create();
+  std::unique_ptr<WebIDBCallbacks> wc;
+  EXPECT_CALL(*web_factory, GetDatabaseInfo(testing::_, testing::_, testing::_))
+      .Times(1)
+      .WillOnce(SaveUniquePointer<0>(&wc));
+  IDBFactory* factory = IDBFactory::CreateForTest(std::move(web_factory));
+
+  DummyExceptionStateForTesting exception_state;
+  ScriptPromise promise =
+      factory->GetDatabaseInfo(scope.GetScriptState(), exception_state);
+  bool on_fulfilled = false;
+  bool on_rejected = false;
+  promise.Then(
+      TestHelperFunction::CreateFunction(scope.GetScriptState(), &on_fulfilled),
+      TestHelperFunction::CreateFunction(scope.GetScriptState(), &on_rejected));
+
+  EXPECT_FALSE(on_fulfilled);
+  EXPECT_FALSE(on_rejected);
+
+  const WebVector<WebIDBNameAndVersion> wv;
+  wc->OnSuccess(wv);
+
+  EXPECT_FALSE(on_fulfilled);
+  EXPECT_FALSE(on_rejected);
+
+  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+  EXPECT_TRUE(on_fulfilled);
+  EXPECT_FALSE(on_rejected);
+}
+
+TEST_F(IDBFactoryTest, WebIDBGetDBNamesCallbacksRejectsPromise) {
+  V8TestingScope scope;
+  std::unique_ptr<MockWebIDBFactory> web_factory = MockWebIDBFactory::Create();
+  std::unique_ptr<WebIDBCallbacks> wc;
+  EXPECT_CALL(*web_factory, GetDatabaseInfo(testing::_, testing::_, testing::_))
+      .Times(1)
+      .WillOnce(SaveUniquePointer<0>(&wc));
+  IDBFactory* factory = IDBFactory::CreateForTest(std::move(web_factory));
+
+  DummyExceptionStateForTesting exception_state;
+  ScriptPromise promise =
+      factory->GetDatabaseInfo(scope.GetScriptState(), exception_state);
+  bool on_fulfilled = false;
+  bool on_rejected = false;
+  promise.Then(
+      TestHelperFunction::CreateFunction(scope.GetScriptState(), &on_fulfilled),
+      TestHelperFunction::CreateFunction(scope.GetScriptState(), &on_rejected));
+
+  EXPECT_FALSE(on_fulfilled);
+  EXPECT_FALSE(on_rejected);
+
+  const WebVector<WebIDBNameAndVersion> wv;
+  wc->OnError(WebIDBDatabaseError(1));
+
+  EXPECT_FALSE(on_fulfilled);
+  EXPECT_FALSE(on_rejected);
+
+  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
+
+  EXPECT_FALSE(on_fulfilled);
+  EXPECT_TRUE(on_rejected);
+}
+
+}  // namespace
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.cc b/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.cc
new file mode 100644
index 0000000..80cf3436
--- /dev/null
+++ b/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.cc
@@ -0,0 +1,20 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+
+namespace blink {
+
+MockWebIDBFactory::MockWebIDBFactory() = default;
+
+MockWebIDBFactory::~MockWebIDBFactory() = default;
+
+std::unique_ptr<MockWebIDBFactory> MockWebIDBFactory::Create() {
+  return base::WrapUnique(new MockWebIDBFactory());
+}
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h b/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h
new file mode 100644
index 0000000..83c890d
--- /dev/null
+++ b/third_party/blink/renderer/modules/indexeddb/mock_web_idb_factory.h
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_MOCK_WEB_IDB_FACTORY_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_MOCK_WEB_IDB_FACTORY_H_
+
+#include <gmock/gmock.h>
+#include <memory>
+
+#include "base/single_thread_task_runner.h"
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace blink {
+
+class WebIDBCallbacks;
+class WebIDBDatabaseCallbacks;
+class WebSecurityOrigin;
+class WebString;
+
+class MockWebIDBFactory : public testing::StrictMock<blink::WebIDBFactory> {
+ public:
+  ~MockWebIDBFactory() override;
+
+  static std::unique_ptr<MockWebIDBFactory> Create();
+
+  MOCK_METHOD3(GetDatabaseInfo,
+               void(WebIDBCallbacks*,
+                    const WebSecurityOrigin&,
+                    scoped_refptr<base::SingleThreadTaskRunner>));
+  MOCK_METHOD3(GetDatabaseNames,
+               void(WebIDBCallbacks*,
+                    const WebSecurityOrigin&,
+                    scoped_refptr<base::SingleThreadTaskRunner>));
+  MOCK_METHOD7(Open,
+               void(const WebString& name,
+                    long long version,
+                    long long transaction_id,
+                    WebIDBCallbacks*,
+                    WebIDBDatabaseCallbacks*,
+                    const WebSecurityOrigin&,
+                    scoped_refptr<base::SingleThreadTaskRunner>));
+  MOCK_METHOD5(DeleteDatabase,
+               void(const WebString& name,
+                    WebIDBCallbacks*,
+                    const WebSecurityOrigin&,
+                    bool force_close,
+                    scoped_refptr<base::SingleThreadTaskRunner>));
+
+ private:
+  MockWebIDBFactory();
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_MOCK_WEB_IDB_FACTORY_H_
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc b/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
index fe63972a..34f3c12 100644
--- a/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
+++ b/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc
@@ -35,6 +35,7 @@
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_database.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_error.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h"
+#include "third_party/blink/public/platform/modules/indexeddb/web_idb_name_and_version.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_value.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
@@ -51,6 +52,7 @@
 using blink::WebIDBKey;
 using blink::WebIDBKeyPath;
 using blink::WebIDBMetadata;
+using blink::WebIDBNameAndVersion;
 using blink::WebIDBValue;
 using blink::WebVector;
 
@@ -88,6 +90,12 @@
 }
 
 void WebIDBCallbacksImpl::OnSuccess(
+    const WebVector<WebIDBNameAndVersion>& web_name_and_version_list) {
+  // Only implemented in idb_factory.cc for the promise-based databases() call.
+  NOTREACHED();
+}
+
+void WebIDBCallbacksImpl::OnSuccess(
     const WebVector<WebString>& web_string_list) {
   if (!request_)
     return;
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h b/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
index 849ba81..4e3012c5 100644
--- a/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
+++ b/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h
@@ -43,6 +43,7 @@
 class WebIDBDatabaseError;
 class WebIDBKey;
 struct WebIDBMetadata;
+struct WebIDBNameAndVersion;
 class WebIDBValue;
 
 class WebIDBCallbacksImpl final : public WebIDBCallbacks {
@@ -55,6 +56,7 @@
 
   // Pointers transfer ownership.
   void OnError(const WebIDBDatabaseError&) override;
+  void OnSuccess(const WebVector<WebIDBNameAndVersion>&) override;
   void OnSuccess(const WebVector<WebString>&) override;
   void OnSuccess(WebIDBCursor*,
                  WebIDBKey,
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
index 79166771..8bf2d05 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
@@ -73,6 +73,9 @@
   // WebMediaPlayer overrides:
   WebTimeRanges Seekable() const override { return seekable_; }
   bool HasVideo() const override { return true; }
+  SurfaceLayerMode GetVideoSurfaceLayerMode() const override {
+    return SurfaceLayerMode::kAlways;
+  }
 
   WebTimeRanges seekable_;
 };
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 6626bd4..d02a51d 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -541,6 +541,7 @@
           "imagecapture/constrain_point_2d_parameters.idl",
           "imagecapture/photo_settings.idl",
           "imagecapture/point_2d.idl",
+          "indexeddb/idb_database_info.idl",
           "indexeddb/idb_index_parameters.idl",
           "indexeddb/idb_object_store_parameters.idl",
           "indexeddb/idb_observer_init.idl",
diff --git a/third_party/blink/renderer/modules/permissions/permissions.cc b/third_party/blink/renderer/modules/permissions/permissions.cc
index 4b57a301..958d952 100644
--- a/third_party/blink/renderer/modules/permissions/permissions.cc
+++ b/third_party/blink/renderer/modules/permissions/permissions.cc
@@ -232,7 +232,7 @@
   Vector<PermissionDescriptorPtr> internal_permissions;
   Vector<int> caller_index_to_internal_index;
   caller_index_to_internal_index.resize(raw_permissions.size());
-  for (size_t i = 0; i < raw_permissions.size(); ++i) {
+  for (wtf_size_t i = 0; i < raw_permissions.size(); ++i) {
     const ScriptValue& raw_permission = raw_permissions[i];
 
     auto descriptor =
@@ -241,8 +241,8 @@
       return ScriptPromise();
 
     // Only append permissions types that are not already present in the vector.
-    size_t internal_index = kNotFound;
-    for (size_t j = 0; j < internal_permissions.size(); ++j) {
+    wtf_size_t internal_index = kNotFound;
+    for (wtf_size_t j = 0; j < internal_permissions.size(); ++j) {
       if (internal_permissions[j]->name == descriptor->name) {
         internal_index = j;
         break;
diff --git a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
index a07678ca..e140944c 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc
@@ -35,6 +35,10 @@
     "Must be handling a user gesture to request picture in picture.";
 const char kDisablePictureInPicturePresent[] =
     "\"disablePictureInPicture\" attribute is present.";
+const char kVideoLayerNotSupported[] =
+    "The use of VideoLayer for video Picture-in-Picture is not supported. "
+    "Please enable the enable-surfaces-for-videos flag if you wish to use this "
+    "feature.";
 }  // namespace
 
 // static
@@ -75,6 +79,11 @@
           script_state,
           DOMException::Create(DOMExceptionCode::kNotSupportedError,
                                kNotAvailable));
+    case Status::kVideoLayerNotSupported:
+      return ScriptPromise::RejectWithDOMException(
+          script_state,
+          DOMException::Create(DOMExceptionCode::kNotSupportedError,
+                               kVideoLayerNotSupported));
     case Status::kEnabled:
       break;
   }
@@ -147,13 +156,13 @@
 HTMLVideoElementPictureInPicture::ToPictureInPictureControlInfoVector(
     const HeapVector<PictureInPictureControl>& controls) {
   std::vector<PictureInPictureControlInfo> converted_controls;
-  for (size_t i = 0; i < controls.size(); ++i) {
+  for (const PictureInPictureControl& control : controls) {
     PictureInPictureControlInfo current_converted_control;
-    HeapVector<MediaImage> current_icons = controls[i].icons();
+    HeapVector<MediaImage> current_icons = control.icons();
 
     // Only two icons are supported, so cap the loop at running that many times
     // to avoid potential problems.
-    for (size_t j = 0; j < current_icons.size() && j < 2; ++j) {
+    for (wtf_size_t j = 0; j < current_icons.size() && j < 2; ++j) {
       PictureInPictureControlInfo::Icon current_icon;
       current_icon.src = KURL(WebString(current_icons[j].src()));
 
@@ -168,8 +177,8 @@
       current_converted_control.icons.push_back(current_icon);
     }
 
-    current_converted_control.id = WebString(controls[i].id()).Utf8();
-    current_converted_control.label = WebString(controls[i].label()).Utf8();
+    current_converted_control.id = WebString(control.id()).Utf8();
+    current_converted_control.label = WebString(control.label()).Utf8();
     converted_controls.push_back(current_converted_control);
   }
   return converted_controls;
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index c8ff90a4..90e4ab4f 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -79,6 +79,9 @@
   if (element.FastHasAttribute(HTMLNames::disablepictureinpictureAttr))
     return Status::kDisabledByAttribute;
 
+  if (!element.UsesSurfaceLayer())
+    return Status::kVideoLayerNotSupported;
+
   return Status::kEnabled;
 }
 
diff --git a/third_party/blink/renderer/modules/plugins/dom_mime_type.cc b/third_party/blink/renderer/modules/plugins/dom_mime_type.cc
index 8ff4b45..a086557 100644
--- a/third_party/blink/renderer/modules/plugins/dom_mime_type.cc
+++ b/third_party/blink/renderer/modules/plugins/dom_mime_type.cc
@@ -49,7 +49,7 @@
   const Vector<String>& extensions = mime_class_info_->Extensions();
 
   StringBuilder builder;
-  for (size_t i = 0; i < extensions.size(); ++i) {
+  for (wtf_size_t i = 0; i < extensions.size(); ++i) {
     if (i)
       builder.Append(',');
     builder.Append(extensions[i]);
diff --git a/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc b/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc
index 5b027492..70c3dae 100644
--- a/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc
+++ b/third_party/blink/renderer/modules/plugins/dom_mime_type_array.cc
@@ -63,7 +63,7 @@
 
   for (const Member<MimeClassInfo>& mime : data->Mimes()) {
     if (mime->Type() == property_name) {
-      size_t index = &mime - &data->Mimes()[0];
+      unsigned index = static_cast<unsigned>(&mime - &data->Mimes()[0]);
       return item(index);
     }
   }
@@ -111,7 +111,8 @@
     if (mime) {
       for (const Member<MimeClassInfo>& mime_info : data->Mimes()) {
         if (mime->type() == mime_info->Type()) {
-          size_t index = &mime_info - &data->Mimes()[0];
+          unsigned index =
+              static_cast<unsigned>(&mime_info - &data->Mimes()[0]);
           dom_mime_types_[index] = mime;
         }
       }
diff --git a/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc b/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc
index e8cbb82..a054d542 100644
--- a/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc
+++ b/third_party/blink/renderer/modules/plugins/dom_plugin_array.cc
@@ -69,7 +69,8 @@
 
   for (const Member<PluginInfo>& plugin_info : data->Plugins()) {
     if (plugin_info->Name() == property_name) {
-      size_t index = &plugin_info - &data->Plugins()[0];
+      unsigned index =
+          static_cast<unsigned>(&plugin_info - &data->Plugins()[0]);
       return item(index);
     }
   }
@@ -138,7 +139,8 @@
     if (plugin) {
       for (const Member<PluginInfo>& plugin_info : data->Plugins()) {
         if (plugin->name() == plugin_info->Name()) {
-          size_t index = &plugin_info - &data->Plugins()[0];
+          unsigned index =
+              static_cast<unsigned>(&plugin_info - &data->Plugins()[0]);
           dom_plugins_[index] = plugin;
         }
       }
diff --git a/third_party/blink/renderer/modules/push_messaging/push_subscription.cc b/third_party/blink/renderer/modules/push_messaging/push_subscription.cc
index 625124a..660a4023 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_subscription.cc
+++ b/third_party/blink/renderer/modules/push_messaging/push_subscription.cc
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/modules/push_messaging/push_subscription_options.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/base64.h"
 
 namespace blink {
@@ -64,10 +65,12 @@
     ServiceWorkerRegistration* service_worker_registration)
     : endpoint_(subscription.endpoint),
       options_(PushSubscriptionOptions::Create(subscription.options)),
-      p256dh_(DOMArrayBuffer::Create(subscription.p256dh.Data(),
-                                     subscription.p256dh.size())),
-      auth_(DOMArrayBuffer::Create(subscription.auth.Data(),
-                                   subscription.auth.size())),
+      p256dh_(DOMArrayBuffer::Create(
+          subscription.p256dh.Data(),
+          SafeCast<unsigned>(subscription.p256dh.size()))),
+      auth_(
+          DOMArrayBuffer::Create(subscription.auth.Data(),
+                                 SafeCast<unsigned>(subscription.auth.size()))),
       service_worker_registration_(service_worker_registration) {}
 
 PushSubscription::~PushSubscription() = default;
diff --git a/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc b/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc
index 0a7c481..9d88f20 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc
+++ b/third_party/blink/renderer/modules/push_messaging/push_subscription_options.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
@@ -75,9 +76,9 @@
 PushSubscriptionOptions::PushSubscriptionOptions(
     const WebPushSubscriptionOptions& options)
     : user_visible_only_(options.user_visible_only),
-      application_server_key_(
-          DOMArrayBuffer::Create(options.application_server_key.Latin1().data(),
-                                 options.application_server_key.length())) {}
+      application_server_key_(DOMArrayBuffer::Create(
+          options.application_server_key.Latin1().data(),
+          SafeCast<unsigned>(options.application_server_key.length()))) {}
 
 void PushSubscriptionOptions::Trace(blink::Visitor* visitor) {
   visitor->Trace(application_server_key_);
diff --git a/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc b/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
index d20885bc..dd23df0e 100644
--- a/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
+++ b/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/modules/presentation/presentation_controller.h"
 #include "third_party/blink/renderer/modules/remoteplayback/availability_callback_wrapper.h"
 #include "third_party/blink/renderer/platform/memory_coordinator.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/base64.h"
 
 namespace blink {
@@ -58,8 +59,8 @@
   // remote-playback://<encoded-data> where |encoded-data| is base64 URL
   // encoded string representation of the source URL.
   std::string source_string = source.GetString().Utf8();
-  String encoded_source =
-      WTF::Base64URLEncode(source_string.data(), source_string.length());
+  String encoded_source = WTF::Base64URLEncode(
+      source_string.data(), SafeCast<unsigned>(source_string.length()));
 
   return KURL("remote-playback://" + encoded_source);
 }
diff --git a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.cc b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.cc
index 00ac5f41..add820c1 100644
--- a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.cc
+++ b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.cc
@@ -168,9 +168,9 @@
     dispatch_event_timer_.StartOneShot(TimeDelta(), FROM_HERE);
 
   // ... and child frames, if they have a ScreenOrientationControllerImpl.
-  for (size_t i = 0; i < child_frames.size(); ++i) {
+  for (LocalFrame* child_frame : child_frames) {
     if (ScreenOrientationControllerImpl* controller =
-            ScreenOrientationControllerImpl::From(*child_frames[i])) {
+            ScreenOrientationControllerImpl::From(*child_frame)) {
       controller->NotifyOrientationChanged();
     }
   }
diff --git a/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc b/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc
index c52eb7c1..9aee25cc 100644
--- a/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc
+++ b/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.cc
@@ -264,8 +264,9 @@
   if (it == active_frequencies_.end()) {
     active_frequencies_.push_back(frequency);
   } else {
-    active_frequencies_.insert(std::distance(active_frequencies_.begin(), it),
-                               frequency);
+    active_frequencies_.insert(
+        static_cast<wtf_size_t>(std::distance(active_frequencies_.begin(), it)),
+        frequency);
   }
   UpdatePollingStatus();
 }
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 bb19a2cb..3a98213 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
@@ -34,6 +34,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
@@ -219,13 +220,15 @@
   DEFINE_THREAD_SAFE_STATIC_LOCAL(
       CustomCountHistogram, script_size_histogram,
       ("ServiceWorker.ScriptSize", 1000, 5000000, 50));
-  script_size_histogram.Count(script_size);
+  script_size_histogram.Count(
+      base::saturated_cast<base::Histogram::Sample>(script_size));
 
   if (cached_metadata_size) {
     DEFINE_THREAD_SAFE_STATIC_LOCAL(
         CustomCountHistogram, script_cached_metadata_size_histogram,
         ("ServiceWorker.ScriptCachedMetadataSize", 1000, 50000000, 50));
-    script_cached_metadata_size_histogram.Count(cached_metadata_size);
+    script_cached_metadata_size_histogram.Count(
+        base::saturated_cast<base::Histogram::Sample>(cached_metadata_size));
   }
 
   CountScriptInternal(script_size, cached_metadata_size);
@@ -253,16 +256,20 @@
   // if they're no longer used.
   DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, script_count_histogram,
                                   ("ServiceWorker.ScriptCount", 1, 1000, 50));
-  script_count_histogram.Count(script_count_);
+  script_count_histogram.Count(
+      base::saturated_cast<base::Histogram::Sample>(script_count_));
   DEFINE_THREAD_SAFE_STATIC_LOCAL(
       CustomCountHistogram, script_total_size_histogram,
       ("ServiceWorker.ScriptTotalSize", 1000, 5000000, 50));
-  script_total_size_histogram.Count(script_total_size_);
+  script_total_size_histogram.Count(
+      base::saturated_cast<base::Histogram::Sample>(script_total_size_));
   if (script_cached_metadata_total_size_) {
     DEFINE_THREAD_SAFE_STATIC_LOCAL(
         CustomCountHistogram, cached_metadata_histogram,
         ("ServiceWorker.ScriptCachedMetadataTotalSize", 1000, 50000000, 50));
-    cached_metadata_histogram.Count(script_cached_metadata_total_size_);
+    cached_metadata_histogram.Count(
+        base::saturated_cast<base::Histogram::Sample>(
+            script_cached_metadata_total_size_));
   }
 }
 
@@ -432,14 +439,16 @@
       CustomCountHistogram, script_size_histogram,
       ("ServiceWorker.CacheStorageInstalledScript.ScriptSize", 1000, 5000000,
        50));
-  script_size_histogram.Count(script_size);
+  script_size_histogram.Count(
+      base::saturated_cast<base::Histogram::Sample>(script_size));
 
   if (script_metadata_size) {
     DEFINE_THREAD_SAFE_STATIC_LOCAL(
         CustomCountHistogram, script_metadata_size_histogram,
         ("ServiceWorker.CacheStorageInstalledScript.CachedMetadataSize", 1000,
          50000000, 50));
-    script_metadata_size_histogram.Count(script_metadata_size);
+    script_metadata_size_histogram.Count(
+        base::saturated_cast<base::Histogram::Sample>(script_metadata_size));
   }
 }
 
@@ -454,13 +463,15 @@
       CustomCountHistogram, cache_storage_installed_script_count_histogram,
       ("ServiceWorker.CacheStorageInstalledScript.Count", 1, 1000, 50));
   cache_storage_installed_script_count_histogram.Count(
-      cache_storage_installed_script_count_);
+      base::saturated_cast<base::Histogram::Sample>(
+          cache_storage_installed_script_count_));
   DEFINE_THREAD_SAFE_STATIC_LOCAL(
       CustomCountHistogram, cache_storage_installed_script_total_size_histogram,
       ("ServiceWorker.CacheStorageInstalledScript.ScriptTotalSize", 1000,
        50000000, 50));
   cache_storage_installed_script_total_size_histogram.Count(
-      cache_storage_installed_script_total_size_);
+      base::saturated_cast<base::Histogram::Sample>(
+          cache_storage_installed_script_total_size_));
 
   if (cache_storage_installed_script_metadata_total_size_) {
     DEFINE_THREAD_SAFE_STATIC_LOCAL(
@@ -469,7 +480,8 @@
         ("ServiceWorker.CacheStorageInstalledScript.CachedMetadataTotalSize",
          1000, 50000000, 50));
     cache_storage_installed_script_metadata_total_size_histogram.Count(
-        cache_storage_installed_script_metadata_total_size_);
+        base::saturated_cast<base::Histogram::Sample>(
+            cache_storage_installed_script_metadata_total_size_));
   }
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
index 481a0f3..f0d8ef2 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
@@ -43,6 +43,7 @@
 #include "third_party/blink/renderer/modules/service_worker/service_worker_window_client.h"
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -111,7 +112,7 @@
                                                        const char* data,
                                                        size_t size) {
   Vector<uint8_t> meta_data;
-  meta_data.Append(data, size);
+  meta_data.Append(data, SafeCast<wtf_size_t>(size));
   service_worker_host_->SetCachedMetadata(url, meta_data);
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index 6cf93ca4..437816c 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -87,6 +87,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 namespace mojo {
 
@@ -144,10 +145,11 @@
   static blink::mojom::blink::NotificationDataPtr Convert(
       const blink::WebNotificationData& input) {
     Vector<int32_t> vibration_pattern;
-    vibration_pattern.Append(input.vibrate.Data(), input.vibrate.size());
+    vibration_pattern.Append(input.vibrate.Data(),
+                             SafeCast<wtf_size_t>(input.vibrate.size()));
 
     Vector<uint8_t> data;
-    data.Append(input.data.Data(), input.data.size());
+    data.Append(input.data.Data(), SafeCast<wtf_size_t>(input.data.size()));
 
     Vector<blink::mojom::blink::NotificationActionPtr> actions;
     for (const auto& web_action : input.actions) {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc b/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
index b42870a6..cc94d80 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
@@ -289,9 +290,10 @@
     for (const auto& chunk : raw_script_data->MetaDataChunks())
       total_metadata_size += chunk.size();
     meta_data = std::make_unique<Vector<char>>();
-    meta_data->ReserveInitialCapacity(total_metadata_size);
+    meta_data->ReserveInitialCapacity(
+        SafeCast<wtf_size_t>(total_metadata_size));
     for (const auto& chunk : raw_script_data->MetaDataChunks())
-      meta_data->Append(chunk.data(), chunk.size());
+      meta_data->Append(chunk.data(), static_cast<wtf_size_t>(chunk.size()));
   }
 
   return std::make_unique<InstalledScriptsManager::ScriptData>(
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
index afc5524..f0c7d6b0 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.cc
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/storage/cached_storage_area.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/rand_util.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
@@ -451,8 +452,10 @@
   // Track localStorage size, from 0-6MB. Note that the maximum size should be
   // 10MB, but we add some slop since we want to make sure the max size is
   // always above what we see in practice, since histograms can't change.
-  UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.MojoSizeInKB",
-                              local_storage_size_kb, 1, 6 * 1024, 50);
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      "LocalStorage.MojoSizeInKB",
+      base::saturated_cast<base::Histogram::Sample>(local_storage_size_kb), 1,
+      6 * 1024, 50);
   if (local_storage_size_kb < 100) {
     UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrimeForUnder100KB",
                         time_to_prime);
@@ -509,7 +512,7 @@
                                               FormatOption format_option) {
   if (input.IsEmpty())
     return g_empty_string;
-  const size_t input_size = input.size();
+  const wtf_size_t input_size = input.size();
   String result;
   bool corrupt = false;
   switch (format_option) {
@@ -536,7 +539,7 @@
     }
     case FormatOption::kLocalStorageDetectFormat: {
       StorageFormat format = static_cast<StorageFormat>(input[0]);
-      const size_t payload_size = input_size - 1;
+      const wtf_size_t payload_size = input_size - 1;
       switch (format) {
         case StorageFormat::UTF16: {
           if (payload_size % sizeof(UChar) != 0) {
@@ -604,7 +607,8 @@
                 reinterpret_cast<char*>(buffer + buffer_vector.size()));
         // (length * 3) should be sufficient for any conversion
         DCHECK_NE(result, WTF::Unicode::kTargetExhausted);
-        buffer_vector.Shrink(buffer - buffer_vector.data());
+        buffer_vector.Shrink(
+            static_cast<wtf_size_t>(buffer - buffer_vector.data()));
         return buffer_vector;
       }
 
diff --git a/third_party/blink/renderer/modules/vibration/vibration_controller.cc b/third_party/blink/renderer/modules/vibration/vibration_controller.cc
index 20965e8..7b4448c 100644
--- a/third_party/blink/renderer/modules/vibration/vibration_controller.cc
+++ b/third_party/blink/renderer/modules/vibration/vibration_controller.cc
@@ -38,7 +38,7 @@
 blink::VibrationController::VibrationPattern sanitizeVibrationPatternInternal(
     const blink::VibrationController::VibrationPattern& pattern) {
   blink::VibrationController::VibrationPattern sanitized = pattern;
-  size_t length = sanitized.size();
+  wtf_size_t length = sanitized.size();
 
   // If the pattern is too long then truncate it.
   if (length > kVibrationPatternLengthMax) {
@@ -47,7 +47,7 @@
   }
 
   // If any pattern entry is too long then truncate it.
-  for (size_t i = 0; i < length; ++i) {
+  for (wtf_size_t i = 0; i < length; ++i) {
     if (sanitized[i] > kVibrationDurationMsMax)
       sanitized[i] = kVibrationDurationMsMax;
   }
diff --git a/third_party/blink/renderer/modules/vr/PRESUBMIT.py b/third_party/blink/renderer/modules/vr/PRESUBMIT.py
deleted file mode 100644
index 19d6c2c..0000000
--- a/third_party/blink/renderer/modules/vr/PRESUBMIT.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (c) 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for third_party/blink/renderer/modules/vr.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-
-def PostUploadHook(cl, change, output_api):  # pylint: disable=C0103,W0613
-    """git cl upload will call this hook after the issue is created/modified.
-
-    This hook modifies the CL description in order to run extra GPU
-    tests (in particular, WebXR and WebVR browser tests) in addition
-    to the regular CQ try bots. This test suite is too large to run
-    against all Chromium commits, but should be run against changes
-    likely to affect these tests.
-    """
-    return output_api.EnsureCQIncludeTrybotsAreAdded(
-        cl,
-        ['luci.chromium.try:win_optional_gpu_tests_rel'],
-        'Automatically added optional GPU tests to run on CQ.')
diff --git a/third_party/blink/renderer/modules/vr/vr_eye_parameters.h b/third_party/blink/renderer/modules/vr/vr_eye_parameters.h
index 235f30c..12b57d3 100644
--- a/third_party/blink/renderer/modules/vr/vr_eye_parameters.h
+++ b/third_party/blink/renderer/modules/vr/vr_eye_parameters.h
@@ -24,16 +24,16 @@
 
   DOMFloat32Array* offset() const { return offset_; }
   VRFieldOfView* FieldOfView() const { return field_of_view_; }
-  unsigned long renderWidth() const { return render_width_; }
-  unsigned long renderHeight() const { return render_height_; }
+  uint32_t renderWidth() const { return render_width_; }
+  uint32_t renderHeight() const { return render_height_; }
 
   void Trace(blink::Visitor*) override;
 
  private:
   Member<DOMFloat32Array> offset_;
   Member<VRFieldOfView> field_of_view_;
-  unsigned long render_width_;
-  unsigned long render_height_;
+  uint32_t render_width_;
+  uint32_t render_height_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/PRESUBMIT.py b/third_party/blink/renderer/modules/webgl/PRESUBMIT.py
deleted file mode 100644
index ca8282a..0000000
--- a/third_party/blink/renderer/modules/webgl/PRESUBMIT.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (c) 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for Source/modules/webgl.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-    """git cl upload will call this hook after the issue is created/modified.
-
-    This hook modifies the CL description in order to run extra GPU
-    tests (in particular, the WebGL 2.0 conformance tests) in addition
-    to the regular CQ try bots. This test suite is too large to run
-    against all Chromium commits, but should be run against changes
-    likely to affect these tests.
-    """
-    return output_api.EnsureCQIncludeTrybotsAreAdded(
-        cl,
-        ['luci.chromium.try:linux_optional_gpu_tests_rel',
-         'luci.chromium.try:mac_optional_gpu_tests_rel',
-         'luci.chromium.try:win_optional_gpu_tests_rel',
-         'luci.chromium.try:android_optional_gpu_tests_rel'],
-        'Automatically added optional GPU tests to run on CQ.')
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index 690a0193..3bd6dac 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -589,7 +589,7 @@
   if (!framebuffer_binding) {
     // For the default framebuffer, translate GL_COLOR/GL_DEPTH/GL_STENCIL.
     // The default framebuffer of WebGL is not fb 0, it is an internal fbo.
-    for (size_t i = 0; i < attachments.size(); ++i) {
+    for (wtf_size_t i = 0; i < attachments.size(); ++i) {
       switch (attachments[i]) {
         case GL_COLOR:
           attachments[i] = GL_COLOR_ATTACHMENT0;
@@ -758,7 +758,7 @@
     GLenum format,
     GLenum type,
     MaybeShared<DOMArrayBufferView> pixels,
-    GLuint offset) {
+    long long offset) {
   if (isContextLost())
     return;
   if (bound_pixel_pack_buffer_.Get()) {
@@ -4035,7 +4035,7 @@
   if (isContextLost())
     return;
 
-  for (size_t i = 0; i < sampler_units_.size(); ++i) {
+  for (wtf_size_t i = 0; i < sampler_units_.size(); ++i) {
     if (sampler == sampler_units_[i]) {
       sampler_units_[i] = nullptr;
       ContextGL()->BindSampler(i, 0);
@@ -4465,8 +4465,8 @@
   Vector<CString> keep_alive;  // Must keep these instances alive while looking
                                // at their data
   Vector<const char*> varying_strings;
-  for (size_t i = 0; i < varyings.size(); ++i) {
-    keep_alive.push_back(varyings[i].Ascii());
+  for (const String& varying : varyings) {
+    keep_alive.push_back(varying.Ascii());
     varying_strings.push_back(keep_alive.back().data());
   }
 
@@ -4746,8 +4746,8 @@
   Vector<CString> keep_alive;  // Must keep these instances alive while looking
                                // at their data
   Vector<const char*> uniform_strings;
-  for (size_t i = 0; i < uniform_names.size(); ++i) {
-    keep_alive.push_back(uniform_names[i].Ascii());
+  for (const String& uniform_name : uniform_names) {
+    keep_alive.push_back(uniform_name.Ascii());
     uniform_strings.push_back(keep_alive.back().data());
   }
 
@@ -4795,9 +4795,9 @@
                             &active_uniforms);
 
   GLuint active_uniforms_unsigned = active_uniforms;
-  size_t size = uniform_indices.size();
-  for (size_t i = 0; i < size; ++i) {
-    if (uniform_indices[i] >= active_uniforms_unsigned) {
+  wtf_size_t size = uniform_indices.size();
+  for (GLuint index : uniform_indices) {
+    if (index >= active_uniforms_unsigned) {
       SynthesizeGLError(GL_INVALID_VALUE, "getActiveUniforms",
                         "uniform index greater than ACTIVE_UNIFORMS");
       return ScriptValue::CreateNull(script_state);
@@ -4811,13 +4811,13 @@
   switch (return_type) {
     case kEnumType: {
       Vector<GLenum> enum_result(size);
-      for (size_t i = 0; i < size; ++i)
+      for (wtf_size_t i = 0; i < size; ++i)
         enum_result[i] = static_cast<GLenum>(result[i]);
       return WebGLAny(script_state, enum_result);
     }
     case kUnsignedIntType: {
       Vector<GLuint> uint_result(size);
-      for (size_t i = 0; i < size; ++i)
+      for (wtf_size_t i = 0; i < size; ++i)
         uint_result[i] = static_cast<GLuint>(result[i]);
       return WebGLAny(script_state, uint_result);
     }
@@ -4826,7 +4826,7 @@
     }
     case kBoolType: {
       Vector<bool> bool_result(size);
-      for (size_t i = 0; i < size; ++i)
+      for (wtf_size_t i = 0; i < size; ++i)
         bool_result[i] = static_cast<bool>(result[i]);
       return WebGLAny(script_state, bool_result);
     }
@@ -5445,7 +5445,7 @@
           max_bound_uniform_buffer_index_ = index;
       } else if (max_bound_uniform_buffer_index_ > 0 &&
                  index == max_bound_uniform_buffer_index_) {
-        size_t i = max_bound_uniform_buffer_index_ - 1;
+        wtf_size_t i = max_bound_uniform_buffer_index_ - 1;
         for (; i > 0; --i) {
           if (bound_indexed_uniform_buffers_[i].Get())
             break;
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
index a410ef3..f8e36e4 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
@@ -936,7 +936,7 @@
                   GLenum format,
                   GLenum type,
                   MaybeShared<DOMArrayBufferView> pixels,
-                  GLuint offset);
+                  long long offset);
   void readPixels(GLint x,
                   GLint y,
                   GLsizei width,
@@ -1136,7 +1136,7 @@
       bound_indexed_shader_storage_buffers_;
   HeapVector<TraceWrapperMember<WebGLBuffer>> bound_indexed_uniform_buffers_;
   GLint max_transform_feedback_separate_attribs_;
-  size_t max_bound_uniform_buffer_index_;
+  wtf_size_t max_bound_uniform_buffer_index_;
 
   TraceWrapperMember<WebGLQuery> current_boolean_occlusion_query_;
   TraceWrapperMember<WebGLQuery>
diff --git a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
index 7d03d403..8afef7a8 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
@@ -416,7 +416,7 @@
 void WebGLFramebuffer::DrawBuffers(const Vector<GLenum>& bufs) {
   draw_buffers_ = bufs;
   filtered_draw_buffers_.resize(draw_buffers_.size());
-  for (size_t i = 0; i < filtered_draw_buffers_.size(); ++i)
+  for (wtf_size_t i = 0; i < filtered_draw_buffers_.size(); ++i)
     filtered_draw_buffers_[i] = GL_NONE;
   DrawBuffersIfNecessary(true);
 }
@@ -426,7 +426,7 @@
       Context()->ExtensionEnabled(kWebGLDrawBuffersName)) {
     bool reset = force;
     // This filtering works around graphics driver bugs on Mac OS X.
-    for (size_t i = 0; i < draw_buffers_.size(); ++i) {
+    for (wtf_size_t i = 0; i < draw_buffers_.size(); ++i) {
       if (draw_buffers_[i] != GL_NONE && GetAttachment(draw_buffers_[i])) {
         if (filtered_draw_buffers_[i] != draw_buffers_[i]) {
           filtered_draw_buffers_[i] = draw_buffers_[i];
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 8fa16dc..3ff964a 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -2412,7 +2412,7 @@
     return;
 
   int max_bound_texture_index = -1;
-  for (size_t i = 0; i < one_plus_max_non_default_texture_unit_; ++i) {
+  for (wtf_size_t i = 0; i < one_plus_max_non_default_texture_unit_; ++i) {
     if (texture == texture_units_[i].texture2d_binding_) {
       texture_units_[i].texture2d_binding_ = nullptr;
       max_bound_texture_index = i;
@@ -2950,8 +2950,7 @@
   WebGLExtension* extension = nullptr;
 
   if (!isContextLost()) {
-    for (size_t i = 0; i < extensions_.size(); ++i) {
-      ExtensionTracker* tracker = extensions_[i];
+    for (ExtensionTracker* tracker : extensions_) {
       if (tracker->MatchesNameWithPrefixes(name)) {
         if (ExtensionSupportedAndAllowed(tracker)) {
           extension = tracker->GetExtension(this);
@@ -3550,8 +3549,7 @@
 
   Vector<String> result;
 
-  for (size_t i = 0; i < extensions_.size(); ++i) {
-    ExtensionTracker* tracker = extensions_[i].Get();
+  for (ExtensionTracker* tracker : extensions_) {
     if (ExtensionSupportedAndAllowed(tracker)) {
       const char* const* prefixes = tracker->Prefixes();
       for (; *prefixes; ++prefixes) {
@@ -4296,7 +4294,7 @@
                                                  GLenum format,
                                                  GLenum type,
                                                  DOMArrayBufferView* pixels,
-                                                 GLuint offset) {
+                                                 long long offset) {
   if (isContextLost())
     return;
   // Due to WebGL's same-origin restrictions, it is not possible to
@@ -6461,12 +6459,11 @@
   auto_recovery_method_ = auto_recovery_method;
 
   // Lose all the extensions.
-  for (size_t i = 0; i < extensions_.size(); ++i) {
-    ExtensionTracker* tracker = extensions_[i];
+  for (ExtensionTracker* tracker : extensions_) {
     tracker->LoseExtension(false);
   }
 
-  for (size_t i = 0; i < kWebGLExtensionNameCount; ++i)
+  for (wtf_size_t i = 0; i < kWebGLExtensionNameCount; ++i)
     extension_enabled_[i] = false;
 
   RemoveAllCompressedTextureFormats();
@@ -6846,7 +6843,7 @@
 
 bool WebGLRenderingContextBase::ValidateString(const char* function_name,
                                                const String& string) {
-  for (size_t i = 0; i < string.length(); ++i) {
+  for (wtf_size_t i = 0; i < string.length(); ++i) {
     if (!ValidateCharacter(string[i])) {
       SynthesizeGLError(GL_INVALID_VALUE, function_name, "string not ASCII");
       return false;
@@ -6856,7 +6853,7 @@
 }
 
 bool WebGLRenderingContextBase::ValidateShaderSource(const String& string) {
-  for (size_t i = 0; i < string.length(); ++i) {
+  for (wtf_size_t i = 0; i < string.length(); ++i) {
     // line-continuation character \ is supported in WebGL 2.0.
     if (IsWebGL2OrHigher() && string[i] == '\\') {
       continue;
@@ -7771,13 +7768,13 @@
 }
 
 WebGLRenderingContextBase::LRUCanvasResourceProviderCache::
-    LRUCanvasResourceProviderCache(size_t capacity)
+    LRUCanvasResourceProviderCache(wtf_size_t capacity)
     : resource_providers_(capacity) {}
 
 CanvasResourceProvider* WebGLRenderingContextBase::
     LRUCanvasResourceProviderCache::GetCanvasResourceProvider(
         const IntSize& size) {
-  size_t i;
+  wtf_size_t i;
   for (i = 0; i < resource_providers_.size(); ++i) {
     CanvasResourceProvider* resource_provider = resource_providers_[i].get();
     if (!resource_provider)
@@ -7797,7 +7794,7 @@
       nullptr));  // canvas_resource_dispatcher
   if (!temp)
     return nullptr;
-  i = std::min(static_cast<size_t>(resource_providers_.size() - 1), i);
+  i = std::min(resource_providers_.size() - 1, i);
   resource_providers_[i] = std::move(temp);
 
   CanvasResourceProvider* resource_provider = resource_providers_[i].get();
@@ -7806,8 +7803,8 @@
 }
 
 void WebGLRenderingContextBase::LRUCanvasResourceProviderCache::BubbleToFront(
-    size_t idx) {
-  for (size_t i = idx; i > 0; --i)
+    wtf_size_t idx) {
+  for (wtf_size_t i = idx; i > 0; --i)
     resource_providers_[i].swap(resource_providers_[i - 1]);
 }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index fcca0c0b..b938117 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -756,19 +756,19 @@
   Member<XRDevice> compatible_xr_device_;
 
   HeapVector<TextureUnitState> texture_units_;
-  unsigned long active_texture_unit_;
+  wtf_size_t active_texture_unit_;
 
   Vector<GLenum> compressed_texture_formats_;
 
   // Fixed-size cache of reusable resource providers for video texImage2D calls.
   class LRUCanvasResourceProviderCache {
    public:
-    explicit LRUCanvasResourceProviderCache(size_t capacity);
+    explicit LRUCanvasResourceProviderCache(wtf_size_t capacity);
     // The pointer returned is owned by the image buffer map.
     CanvasResourceProvider* GetCanvasResourceProvider(const IntSize&);
 
    private:
-    void BubbleToFront(size_t idx);
+    void BubbleToFront(wtf_size_t idx);
     Vector<std::unique_ptr<CanvasResourceProvider>> resource_providers_;
   };
   LRUCanvasResourceProviderCache generated_image_cache_ =
@@ -822,7 +822,7 @@
   bool synthesized_errors_to_console_ = true;
   int num_gl_errors_to_console_allowed_;
 
-  unsigned long one_plus_max_non_default_texture_unit_ = 0;
+  wtf_size_t one_plus_max_non_default_texture_unit_ = 0;
 
   std::unique_ptr<Extensions3DUtil> extensions_util_;
 
@@ -1668,7 +1668,7 @@
                         GLenum format,
                         GLenum type,
                         DOMArrayBufferView* pixels,
-                        GLuint offset);
+                        long long offset);
 
  private:
   WebGLRenderingContextBase(CanvasRenderingContextHost*,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc b/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc
index db1df4bf..f2d4b38b 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc
@@ -45,10 +45,9 @@
 }
 
 void WebGLTransformFeedback::DispatchDetached(gpu::gles2::GLES2Interface* gl) {
-  for (size_t i = 0; i < bound_indexed_transform_feedback_buffers_.size();
-       ++i) {
-    if (bound_indexed_transform_feedback_buffers_[i])
-      bound_indexed_transform_feedback_buffers_[i]->OnDetached(gl);
+  for (WebGLBuffer* buffer : bound_indexed_transform_feedback_buffers_) {
+    if (buffer)
+      buffer->OnDetached(gl);
   }
 }
 
@@ -123,16 +122,16 @@
 }
 
 bool WebGLTransformFeedback::UsesBuffer(WebGLBuffer* buffer) {
-  for (size_t i = 0; i < bound_indexed_transform_feedback_buffers_.size();
-       ++i) {
-    if (bound_indexed_transform_feedback_buffers_[i] == buffer)
+  for (WebGLBuffer* feedback_buffer :
+       bound_indexed_transform_feedback_buffers_) {
+    if (feedback_buffer == buffer)
       return true;
   }
   return false;
 }
 
 void WebGLTransformFeedback::UnbindBuffer(WebGLBuffer* buffer) {
-  for (size_t i = 0; i < bound_indexed_transform_feedback_buffers_.size();
+  for (wtf_size_t i = 0; i < bound_indexed_transform_feedback_buffers_.size();
        ++i) {
     if (bound_indexed_transform_feedback_buffers_[i] == buffer) {
       bound_indexed_transform_feedback_buffers_[i]->OnDetached(
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc
index da110a05..6113578 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc
@@ -19,7 +19,7 @@
       is_all_enabled_attrib_buffer_bound_(true) {
   array_buffer_list_.resize(ctx->MaxVertexAttribs());
   attrib_enabled_.resize(ctx->MaxVertexAttribs());
-  for (size_t i = 0; i < attrib_enabled_.size(); ++i) {
+  for (wtf_size_t i = 0; i < attrib_enabled_.size(); ++i) {
     attrib_enabled_[i] = false;
   }
 
@@ -41,9 +41,9 @@
   if (bound_element_array_buffer_)
     bound_element_array_buffer_->OnDetached(gl);
 
-  for (size_t i = 0; i < array_buffer_list_.size(); ++i) {
-    if (array_buffer_list_[i])
-      array_buffer_list_[i]->OnDetached(gl);
+  for (WebGLBuffer* buffer : array_buffer_list_) {
+    if (buffer)
+      buffer->OnDetached(gl);
   }
 }
 
@@ -74,7 +74,7 @@
   bound_element_array_buffer_ = buffer;
 }
 
-WebGLBuffer* WebGLVertexArrayObjectBase::GetArrayBufferForAttrib(size_t index) {
+WebGLBuffer* WebGLVertexArrayObjectBase::GetArrayBufferForAttrib(GLuint index) {
   DCHECK(index < Context()->MaxVertexAttribs());
   return array_buffer_list_[index].Get();
 }
@@ -103,7 +103,7 @@
 
 void WebGLVertexArrayObjectBase::UpdateAttribBufferBoundStatus() {
   is_all_enabled_attrib_buffer_bound_ = true;
-  for (size_t i = 0; i < attrib_enabled_.size(); ++i) {
+  for (wtf_size_t i = 0; i < attrib_enabled_.size(); ++i) {
     if (attrib_enabled_[i] && !array_buffer_list_[i]) {
       is_all_enabled_attrib_buffer_bound_ = false;
       return;
@@ -117,7 +117,7 @@
     bound_element_array_buffer_ = nullptr;
   }
 
-  for (size_t i = 0; i < array_buffer_list_.size(); ++i) {
+  for (wtf_size_t i = 0; i < array_buffer_list_.size(); ++i) {
     if (array_buffer_list_[i] == buffer) {
       array_buffer_list_[i]->OnDetached(Context()->ContextGL());
       array_buffer_list_[i] = nullptr;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h
index 18930ea..9b0de361 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h
@@ -33,7 +33,7 @@
   }
   void SetElementArrayBuffer(WebGLBuffer*);
 
-  WebGLBuffer* GetArrayBufferForAttrib(size_t);
+  WebGLBuffer* GetArrayBufferForAttrib(GLuint);
   void SetArrayBufferForAttrib(GLuint, WebGLBuffer*);
   void SetAttribEnabled(GLuint, bool);
   bool GetAttribEnabled(GLuint) const;
diff --git a/third_party/blink/renderer/modules/webmidi/midi_input.cc b/third_party/blink/renderer/modules/webmidi/midi_input.cc
index 6539538..fcf6d14 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_input.cc
+++ b/third_party/blink/renderer/modules/webmidi/midi_input.cc
@@ -35,6 +35,7 @@
 #include "third_party/blink/renderer/modules/webmidi/midi_access.h"
 #include "third_party/blink/renderer/modules/webmidi/midi_message_event.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 namespace blink {
 
@@ -98,7 +99,8 @@
   // the current process has an explicit permission to handle sysex message.
   if (data[0] == 0xf0 && !midiAccess()->sysexEnabled())
     return;
-  DOMUint8Array* array = DOMUint8Array::Create(data, length);
+  DOMUint8Array* array =
+      DOMUint8Array::Create(data, SafeCast<unsigned>(length));
   DispatchEvent(*MIDIMessageEvent::Create(time_stamp, array));
 
   UseCounter::Count(*To<Document>(GetExecutionContext()),
diff --git a/third_party/blink/renderer/modules/xr/PRESUBMIT.py b/third_party/blink/renderer/modules/xr/PRESUBMIT.py
deleted file mode 100644
index 81cd49bc..0000000
--- a/third_party/blink/renderer/modules/xr/PRESUBMIT.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (c) 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for third_party/blink/renderer/modules/xr.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-
-def PostUploadHook(cl, change, output_api):  # pylint: disable=C0103,W0613
-    """git cl upload will call this hook after the issue is created/modified.
-
-    This hook modifies the CL description in order to run extra GPU
-    tests (in particular, WebXR and WebVR browser tests) in addition
-    to the regular CQ try bots. This test suite is too large to run
-    against all Chromium commits, but should be run against changes
-    likely to affect these tests.
-    """
-    return output_api.EnsureCQIncludeTrybotsAreAdded(
-        cl,
-        ['luci.chromium.try:win_optional_gpu_tests_rel'],
-        'Automatically added optional GPU tests to run on CQ.')
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 7bc85372..10525767 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -793,6 +793,8 @@
     "geometry/layout_rect_outsets.h",
     "geometry/layout_size.cc",
     "geometry/layout_size.h",
+    "geometry/layout_unit.cc",
+    "geometry/layout_unit.h",
     "geometry/length.cc",
     "geometry/length.h",
     "geometry/length_box.h",
@@ -1167,8 +1169,6 @@
     "language.h",
     "layout_test_support.cc",
     "layout_test_support.h",
-    "layout_unit.cc",
-    "layout_unit.h",
     "lifecycle_notifier.h",
     "lifecycle_observer.h",
     "link_hash.cc",
@@ -1709,6 +1709,7 @@
     "geometry/int_rect_test.cc",
     "geometry/layout_rect_test.cc",
     "geometry/layout_size_test.cc",
+    "geometry/layout_unit_test.cc",
     "geometry/region_test.cc",
     "graphics/accelerated_static_bitmap_image_test.cc",
     "graphics/bitmap_image_test.cc",
@@ -1764,7 +1765,6 @@
     "image-decoders/webp/webp_image_decoder_test.cc",
     "json/json_parser_test.cc",
     "json/json_values_test.cc",
-    "layout_unit_test.cc",
     "lifecycle_context_test.cc",
     "mac/graphics_context_canvas_test.mm",
     "mac/version_util_mac_test.mm",
diff --git a/third_party/blink/renderer/platform/animation/DEPS b/third_party/blink/renderer/platform/animation/DEPS
index d15d7b3..7ec486a 100644
--- a/third_party/blink/renderer/platform/animation/DEPS
+++ b/third_party/blink/renderer/platform/animation/DEPS
@@ -10,7 +10,6 @@
     "+third_party/blink/renderer/platform/geometry",
     "+third_party/blink/renderer/platform/graphics",
     "+third_party/blink/renderer/platform/heap",
-    "+third_party/blink/renderer/platform/layout_unit.h",
     "+third_party/blink/renderer/platform/platform_export.h",
     "+third_party/blink/renderer/platform/runtime_enabled_features.h",
     "+third_party/blink/renderer/platform/testing",
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string.cc b/third_party/blink/renderer/platform/bindings/parkable_string.cc
index 98b53c7..f3051063f 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string.cc
@@ -178,7 +178,7 @@
   return impl_ ? impl_->ToString() : String();
 }
 
-unsigned ParkableString::CharactersSizeInBytes() const {
+wtf_size_t ParkableString::CharactersSizeInBytes() const {
   return impl_ ? impl_->CharactersSizeInBytes() : 0;
 }
 
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string.h b/third_party/blink/renderer/platform/bindings/parkable_string.h
index 12c1dff..ced4437 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string.h
+++ b/third_party/blink/renderer/platform/bindings/parkable_string.h
@@ -133,7 +133,7 @@
   // The string is guaranteed to be valid for
   // max(lifetime of a copy of the returned reference, current thread task).
   String ToString() const;
-  unsigned CharactersSizeInBytes() const;
+  wtf_size_t CharactersSizeInBytes() const;
 
   // Causes the string to be unparked. Note that the pointer must not be
   // cached.
diff --git a/third_party/blink/renderer/platform/fonts/DEPS b/third_party/blink/renderer/platform/fonts/DEPS
index 971791e..941f8cd 100644
--- a/third_party/blink/renderer/platform/fonts/DEPS
+++ b/third_party/blink/renderer/platform/fonts/DEPS
@@ -14,7 +14,6 @@
     "+third_party/blink/renderer/platform/instrumentation",
     "+third_party/blink/renderer/platform/language.h",
     "+third_party/blink/renderer/platform/layout_test_support.h",
-    "+third_party/blink/renderer/platform/layout_unit.h",
     "+third_party/blink/renderer/platform/mac/version_util_mac.h",
     "+third_party/blink/renderer/platform/platform_export.h",
     "+third_party/blink/renderer/platform/resolution_units.h",
diff --git a/third_party/blink/renderer/platform/fonts/font.cc b/third_party/blink/renderer/platform/fonts/font.cc
index def231a9..7345bf8 100644
--- a/third_party/blink/renderer/platform/fonts/font.cc
+++ b/third_party/blink/renderer/platform/fonts/font.cc
@@ -37,7 +37,7 @@
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
 #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/text/bidi_resolver.h"
 #include "third_party/blink/renderer/platform/text/character.h"
 #include "third_party/blink/renderer/platform/text/text_run.h"
diff --git a/third_party/blink/renderer/platform/fonts/font.h b/third_party/blink/renderer/platform/fonts/font.h
index 559bd97f..313afb7 100644
--- a/third_party/blink/renderer/platform/fonts/font.h
+++ b/third_party/blink/renderer/platform/fonts/font.h
@@ -29,7 +29,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_fallback_list.h"
 #include "third_party/blink/renderer/platform/fonts/font_fallback_priority.h"
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/text/tab_size.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
diff --git a/third_party/blink/renderer/platform/fonts/font_metrics.h b/third_party/blink/renderer/platform/fonts/font_metrics.h
index fbacc8cf..c994c46 100644
--- a/third_party/blink/renderer/platform/fonts/font_metrics.h
+++ b/third_party/blink/renderer/platform/fonts/font_metrics.h
@@ -21,7 +21,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_METRICS_H_
 
 #include "third_party/blink/renderer/platform/fonts/font_baseline.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index 214f256..0364e391 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -35,7 +35,7 @@
 #include "third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h"
 #include "third_party/blink/renderer/platform/fonts/glyph.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h b/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h
index e58db43..c0c274c9 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPING_LINE_BREAKER_H_
 
 #include "third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
diff --git a/third_party/blink/renderer/platform/geometry/DEPS b/third_party/blink/renderer/platform/geometry/DEPS
index 9b2fc5f..6eb877b 100644
--- a/third_party/blink/renderer/platform/geometry/DEPS
+++ b/third_party/blink/renderer/platform/geometry/DEPS
@@ -8,7 +8,6 @@
     # Dependencies.
     "+cc/base/region.h",
     "+third_party/blink/renderer/platform/json",
-    "+third_party/blink/renderer/platform/layout_unit.h",
     "+third_party/blink/renderer/platform/platform_export.h",
     "+third_party/blink/renderer/platform/wtf",
     "+ui/gfx/geometry",
diff --git a/third_party/blink/renderer/platform/geometry/blend.h b/third_party/blink/renderer/platform/geometry/blend.h
index 6db4f3c..f0aaa48 100644
--- a/third_party/blink/renderer/platform/geometry/blend.h
+++ b/third_party/blink/renderer/platform/geometry/blend.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/platform/geometry/float_point.h"
 #include "third_party/blink/renderer/platform/geometry/int_point.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 
diff --git a/third_party/blink/renderer/platform/geometry/layout_rect.cc b/third_party/blink/renderer/platform/geometry/layout_rect.cc
index 50af328..3ef7c93 100644
--- a/third_party/blink/renderer/platform/geometry/layout_rect.cc
+++ b/third_party/blink/renderer/platform/geometry/layout_rect.cc
@@ -34,7 +34,7 @@
 #include <algorithm>
 #include "third_party/blink/renderer/platform/geometry/double_rect.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h b/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h
index 9f9c4bc..3f3eccf4 100644
--- a/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h
+++ b/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h
@@ -34,7 +34,7 @@
 #include "third_party/blink/renderer/platform/geometry/float_rect_outsets.h"
 #include "third_party/blink/renderer/platform/geometry/int_rect_outsets.h"
 #include "third_party/blink/renderer/platform/geometry/layout_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
diff --git a/third_party/blink/renderer/platform/geometry/layout_size.h b/third_party/blink/renderer/platform/geometry/layout_size.h
index ef1381db..e007b6c0 100644
--- a/third_party/blink/renderer/platform/geometry/layout_size.h
+++ b/third_party/blink/renderer/platform/geometry/layout_size.h
@@ -36,7 +36,7 @@
 #include "third_party/blink/renderer/platform/geometry/float_point.h"
 #include "third_party/blink/renderer/platform/geometry/float_size.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/third_party/blink/renderer/platform/layout_unit.cc b/third_party/blink/renderer/platform/geometry/layout_unit.cc
similarity index 94%
rename from third_party/blink/renderer/platform/layout_unit.cc
rename to third_party/blink/renderer/platform/geometry/layout_unit.cc
index e27c262..f6d46bf 100644
--- a/third_party/blink/renderer/platform/layout_unit.cc
+++ b/third_party/blink/renderer/platform/geometry/layout_unit.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 "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
 #include <ostream>
 #include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
diff --git a/third_party/blink/renderer/platform/layout_unit.h b/third_party/blink/renderer/platform/geometry/layout_unit.h
similarity index 98%
rename from third_party/blink/renderer/platform/layout_unit.h
rename to third_party/blink/renderer/platform/geometry/layout_unit.h
index c4c248e2b..58bbadf 100644
--- a/third_party/blink/renderer/platform/layout_unit.h
+++ b/third_party/blink/renderer/platform/geometry/layout_unit.h
@@ -28,8 +28,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LAYOUT_UNIT_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LAYOUT_UNIT_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LAYOUT_UNIT_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LAYOUT_UNIT_H_
 
 #include <iosfwd>
 #include <limits>
@@ -711,4 +711,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LAYOUT_UNIT_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LAYOUT_UNIT_H_
diff --git a/third_party/blink/renderer/platform/layout_unit_test.cc b/third_party/blink/renderer/platform/geometry/layout_unit_test.cc
similarity index 99%
rename from third_party/blink/renderer/platform/layout_unit_test.cc
rename to third_party/blink/renderer/platform/geometry/layout_unit_test.cc
index 5eadbe8e..cf5509f 100644
--- a/third_party/blink/renderer/platform/layout_unit_test.cc
+++ b/third_party/blink/renderer/platform/geometry/layout_unit_test.cc
@@ -28,10 +28,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
-#include "testing/gtest/include/gtest/gtest.h"
 #include <limits.h>
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/geometry/length.h b/third_party/blink/renderer/platform/geometry/length.h
index 5be6397..c8d5b02 100644
--- a/third_party/blink/renderer/platform/geometry/length.h
+++ b/third_party/blink/renderer/platform/geometry/length.h
@@ -23,7 +23,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LENGTH_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LENGTH_H_
 
-#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
diff --git a/third_party/blink/renderer/platform/geometry/length_functions.cc b/third_party/blink/renderer/platform/geometry/length_functions.cc
index 75b5c16..b61d48f 100644
--- a/third_party/blink/renderer/platform/geometry/length_functions.cc
+++ b/third_party/blink/renderer/platform/geometry/length_functions.cc
@@ -25,9 +25,9 @@
 
 #include "third_party/blink/renderer/platform/geometry/float_point.h"
 #include "third_party/blink/renderer/platform/geometry/float_size.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/geometry/length_point.h"
 #include "third_party/blink/renderer/platform/geometry/length_size.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/PRESUBMIT.py b/third_party/blink/renderer/platform/graphics/gpu/PRESUBMIT.py
deleted file mode 100644
index 2efada7..0000000
--- a/third_party/blink/renderer/platform/graphics/gpu/PRESUBMIT.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (c) 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for third_party/blink/renderer/platform/graphics/gpu.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-
-def PostUploadHook(cl, change, output_api):  # pylint: disable=C0103,W0613
-    """git cl upload will call this hook after the issue is created/modified.
-
-    This hook modifies the CL description in order to run extra GPU
-    tests (in particular, WebXR and WebVR browser tests) in addition
-    to the regular CQ try bots. This test suite is too large to run
-    against all Chromium commits, but should be run against changes
-    likely to affect these tests.
-    """
-    return output_api.EnsureCQIncludeTrybotsAreAdded(
-        cl,
-        ['luci.chromium.try:win_optional_gpu_tests_rel'],
-        'Automatically added optional GPU tests to run on CQ.')
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 78ab05dc..1094eb76 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -585,6 +585,10 @@
       status: "stable",
     },
     {
+      name: "IDBGetDatabases",
+      status: "experimental",
+    },
+    {
       name: "IDBObserver",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/testing/empty_web_media_player.h b/third_party/blink/renderer/platform/testing/empty_web_media_player.h
index 6e577183..d82b4e1 100644
--- a/third_party/blink/renderer/platform/testing/empty_web_media_player.h
+++ b/third_party/blink/renderer/platform/testing/empty_web_media_player.h
@@ -34,6 +34,9 @@
       const std::vector<PictureInPictureControlInfo>&) override {}
   void RegisterPictureInPictureWindowResizeCallback(
       PipWindowResizedCallback) override {}
+  SurfaceLayerMode GetVideoSurfaceLayerMode() const override {
+    return SurfaceLayerMode::kNever;
+  }
   WebTimeRanges Buffered() const override;
   WebTimeRanges Seekable() const override;
   void SetSinkId(const WebString& sink_id,
diff --git a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
index 0a55b6f..190ab13 100644
--- a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
+++ b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
@@ -42,8 +42,7 @@
 
 
 def lint(host, options):
-    ports_to_lint = [host.port_factory.get(name)
-                     for name in host.port_factory.all_port_names(options.platform)]
+    ports_to_lint = [host.port_factory.get(name) for name in host.port_factory.all_port_names(options.platform)]
     files_linted = set()
 
     # In general, the set of TestExpectation files should be the same for
@@ -81,7 +80,7 @@
 
 
 def check_virtual_test_suites(host, options):
-    port = host.port_factory.get()
+    port = host.port_factory.get(options=options)
     fs = host.filesystem
     layout_tests_dir = port.layout_tests_dir()
     virtual_suites = port.virtual_test_suites()
@@ -100,7 +99,7 @@
 
 
 def check_smoke_tests(host, options):
-    port = host.port_factory.get()
+    port = host.port_factory.get(options=options)
     smoke_tests_file = host.filesystem.join(port.layout_tests_dir(), 'SmokeTests')
     failures = []
     if not host.filesystem.exists(smoke_tests_file):
diff --git a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
index 34497d1..55952a07 100644
--- a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations_unittest.py
@@ -171,7 +171,7 @@
         host = MockHost()
         options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False})
         orig_get = host.port_factory.get
-        host.port_factory.get = lambda : orig_get('test', options=options)
+        host.port_factory.get = lambda options: orig_get('test', options=options)
 
         res = lint_test_expectations.check_virtual_test_suites(host, options)
         self.assertTrue(res)
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/android.py b/third_party/blink/tools/blinkpy/web_tests/port/android.py
index f96662c6..632d46e 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/android.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/android.py
@@ -242,13 +242,12 @@
 
     def __init__(self, host, port_name, **kwargs):
         _import_android_packages_if_necessary()
-        self._driver_details = ContentShellDriverDetails()
-        self._host_port = factory.PortFactory(host).get(**kwargs)
         super(AndroidPort, self).__init__(host, port_name, **kwargs)
 
         self._operating_system = 'android'
         self._version = 'kitkat'
 
+        self._host_port = factory.PortFactory(host).get(**kwargs)
         self.server_process_constructor = self._android_server_process_constructor
 
         if not self.get_option('disable_breakpad'):
@@ -257,6 +256,7 @@
         if self.driver_name() != self.CONTENT_SHELL_NAME:
             raise AssertionError('Layout tests on Android only support content_shell as the driver.')
 
+        self._driver_details = ContentShellDriverDetails()
 
         # Initialize the AndroidDevices class which tracks available devices.
         default_devices = None
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/android_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/android_unittest.py
index 1aae22d..ba4f5d1 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/android_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/android_unittest.py
@@ -94,8 +94,7 @@
 
     def test_check_build(self):
         host = MockSystemHost()
-        port = self.make_port(host=host, options=optparse.Values(
-            {'child_processes': 1, 'target': 'Release'}))
+        port = self.make_port(host=host, options=optparse.Values({'child_processes': 1}))
         # Checking the devices is not tested in this unit test.
         port._check_devices = lambda _: None
         host.filesystem.exists = lambda p: True
@@ -108,14 +107,12 @@
     # Test that content_shell currently is the only supported driver.
     def test_non_content_shell_driver(self):
         with self.assertRaises(Exception):
-          self.make_port(options=optparse.Values({'driver_name': 'foobar', 'target': 'Release'}))
+            self.make_port(options=optparse.Values({'driver_name': 'foobar'}))
 
     # Test that the number of child processes to create depends on the devices.
     def test_default_child_processes(self):
         port_default = self.make_port(device_count=5)
-        port_fixed_device = self.make_port(
-            device_count=5,
-            options=optparse.Values({'adb_devices': ['123456789ABCDEF9'], 'target': 'Release'}))
+        port_fixed_device = self.make_port(device_count=5, options=optparse.Values({'adb_devices': ['123456789ABCDEF9']}))
 
         self.assertEquals(6, port_default.default_child_processes())
         self.assertEquals(1, port_fixed_device.default_child_processes())
@@ -126,8 +123,8 @@
 
     # Tests the default timeouts for Android, which are different than the rest of Chromium.
     def test_default_timeout_ms(self):
-        self.assertEqual(self.make_port(options=optparse.Values({'target': 'Release'})).default_timeout_ms(), 10000)
-        self.assertEqual(self.make_port(options=optparse.Values({'target': 'Debug'})).default_timeout_ms(), 10000)
+        self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Release'})).default_timeout_ms(), 10000)
+        self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Debug'})).default_timeout_ms(), 10000)
 
     def test_path_to_apache_config_file(self):
         port = self.make_port()
@@ -152,9 +149,7 @@
             'devil.android.perf.perf_control.PerfControl')
         self._mock_perf_control.start()
 
-        self._port = android.AndroidPort(
-            MockSystemHost(executive=MockExecutive()), 'android',
-            options=optparse.Values({'target': 'Release'}))
+        self._port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android')
         self._driver = android.ChromiumAndroidDriver(
             self._port,
             worker_number=0,
@@ -204,8 +199,7 @@
         self._mock_perf_control.stop()
 
     def test_two_drivers(self):
-        options = optparse.Values({'target': 'Release'})
-        port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android', options=options)
+        port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android')
         driver0 = android.ChromiumAndroidDriver(port, worker_number=0,
                                                 driver_details=android.ContentShellDriverDetails(), android_devices=port._devices)
         driver1 = android.ChromiumAndroidDriver(port, worker_number=1,
@@ -241,12 +235,10 @@
     def test_options_with_two_ports(self):
         port0 = android.AndroidPort(
             MockSystemHost(executive=MockExecutive()), 'android',
-            options=optparse.Values(
-                {'additional_driver_flag': ['--foo=bar'], 'target': 'Release'}))
+            options=optparse.Values({'additional_driver_flag': ['--foo=bar']}))
         port1 = android.AndroidPort(
             MockSystemHost(executive=MockExecutive()), 'android',
-            options=optparse.Values(
-                {'driver_name': 'content_shell', 'target': 'Release'}))
+            options=optparse.Values({'driver_name': 'content_shell'}))
 
         self.assertEqual(1, port0.driver_cmd_line().count('--foo=bar'))
         self.assertEqual(0, port1.driver_cmd_line().count('--create-stdin-fifo'))
@@ -266,9 +258,7 @@
             return_value={'level': 100})
         self._mock_battery.start()
 
-        self._port = android.AndroidPort(
-            MockSystemHost(executive=MockExecutive()), 'android',
-            options=optparse.Values({'target': 'Release'}))
+        self._port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android')
         self._driver = android.ChromiumAndroidDriver(
             self._port,
             worker_number=0,
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py
index 014db58e..36b7eb9 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -58,7 +58,6 @@
 from blinkpy.web_tests.port import driver
 from blinkpy.web_tests.port import server_process
 from blinkpy.web_tests.port.factory import PortFactory
-from blinkpy.web_tests.port.factory import check_configuration_and_target
 from blinkpy.web_tests.servers import apache_http
 from blinkpy.web_tests.servers import pywebsocket
 from blinkpy.web_tests.servers import wptserve
@@ -218,10 +217,11 @@
         self.server_process_constructor = server_process.ServerProcess  # This can be overridden for testing.
         self._http_lock = None  # FIXME: Why does this live on the port object?
         self._dump_reader = None
-        if not hasattr(options, 'target') or not options.target:
-            self.set_option_default('target', self.default_target())
-        self.check_configuration_and_target()
 
+        if not hasattr(options, 'configuration') or not options.configuration:
+            self.set_option_default('configuration', self.default_configuration())
+        if not hasattr(options, 'target') or not options.target:
+            self.set_option_default('target', self._options.configuration)
         self._test_configuration = None
         self._reftest_list = {}
         self._results_directory = None
@@ -1448,25 +1448,8 @@
         """Returns the repository path for the chromium code base."""
         return self._path_from_chromium_base('build')
 
-    def default_target(self):
-      runnable_targets = []
-      for possible_target in ('Release', 'Default', 'Debug'):
-          if self._filesystem.exists(self._path_to_driver(possible_target)):
-              runnable_targets.append(possible_target)
-      if len(runnable_targets) == 0:
-          _log.error('Driver cannot be found in common build directories.')
-          sys.exit(1)
-      elif len(runnable_targets) == 1:
-          _log.info('Automatically picked a target: %s', runnable_targets[0])
-          return runnable_targets[0]
-      else:
-          _log.error('Multiple runnable targets are found: %s. '
-                     'Specify the exact target with --target flag.',
-                     ', '.join(repr(runnable_targets)))
-          sys.exit(1)
-
-    def check_configuration_and_target(self):
-      check_configuration_and_target(self._filesystem, self._options)
+    def default_configuration(self):
+        return 'Release'
 
     def clobber_old_port_specific_results(self):
         pass
@@ -1770,10 +1753,7 @@
 
     def _build_path(self, *comps):
         """Returns a path from the build directory."""
-        target = None
-        if 'target' in comps:
-          target = comps.pop('target')
-        return self._build_path_with_target(target, *comps)
+        return self._build_path_with_target(self._options.target, *comps)
 
     def _build_path_with_target(self, target, *comps):
         target = target or self.get_option('target')
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
index 7f95109e..a77d830 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
@@ -49,10 +49,8 @@
 
 class PortTest(LoggingTestCase):
 
-    def make_port(self, executive=None, with_tests=False, port_name=None, host=None, **kwargs):
-        if not 'options' in kwargs:
-            kwargs['options'] = optparse.Values({'target': 'Release', 'configuration': 'Release'})
-        host = host or MockSystemHost()
+    def make_port(self, executive=None, with_tests=False, port_name=None, **kwargs):
+        host = MockSystemHost()
         if executive:
             host.executive = executive
         if with_tests:
@@ -76,7 +74,6 @@
     def test_get_option__set(self):
         options, _ = optparse.OptionParser().parse_args([])
         options.foo = 'bar'
-        options.target = 'Release'
         port = self.make_port(options=options)
         self.assertEqual(port.get_option('foo'), 'bar')
 
@@ -88,30 +85,6 @@
         port = self.make_port()
         self.assertEqual(port.get_option('foo', 'bar'), 'bar')
 
-    def test_get_option__default_target(self):
-        temp_port = self.make_port(options=optparse.Values(
-            {'target': 'Default', 'configuration': 'Release'}))
-        fake_driver_path = temp_port._path_to_driver()
-        host = MockSystemHost()
-        host.filesystem.write_binary_file(fake_driver_path, 'DeathStar')
-        options, _ = optparse.OptionParser().parse_args([])
-        port = self.make_port(host=host, options=options)
-        self.assertEqual(port.get_option('target'), 'Default')
-
-    def test_get_option__default_configuration(self):
-        temp_port = self.make_port(
-            options=optparse.Values({'target': 'Default', 'configuration': 'Debug'}))
-        fake_driver_path = temp_port._path_to_driver()
-        host = MockSystemHost()
-        host.filesystem.write_binary_file(fake_driver_path, 'DeathStar')
-        fake_arg_gn_path = host.filesystem.normpath(
-            host.filesystem.join(fake_driver_path, '..', 'args.gn'))
-        host.filesystem.write_text_file(fake_arg_gn_path, 'is_debug=True')
-        options, _ = optparse.OptionParser().parse_args([])
-        port = self.make_port(host=host, options=options)
-        self.assertEqual(port.get_option('target'), 'Default')
-        self.assertEqual(port.get_option('configuration'), 'Debug')
-
     def test_output_filename(self):
         port = self.make_port()
 
@@ -392,13 +365,11 @@
         # --additional-driver-flag. additional_driver_flags() excludes primary_driver_flag().
 
         port_a = self.make_port(options=optparse.Values(
-            {'additional_driver_flag': [], 'target': 'Release', 'configuration': 'Release'}))
+            {'additional_driver_flag': []}))
         port_b = self.make_port(options=optparse.Values(
-            {'additional_driver_flag': ['--bb'], 'target': 'Release',
-             'configuration': 'Release'}))
+            {'additional_driver_flag': ['--bb']}))
         port_c = self.make_port(options=optparse.Values(
-            {'additional_driver_flag': ['--bb', '--cc'], 'target': 'Release',
-             'configuration': 'Release'}))
+            {'additional_driver_flag': ['--bb', '--cc']}))
 
         self.assertEqual(port_a.primary_driver_flag(), None)
         self.assertEqual(port_b.primary_driver_flag(), '--bb')
@@ -425,9 +396,7 @@
                          ['--cc'] + default_flags)
 
     def test_additional_env_var(self):
-        port = self.make_port(options=optparse.Values(
-            {'additional_env_var': ['FOO=BAR', 'BAR=FOO'], 'target': 'Release',
-             'configuration': 'Release'}))
+        port = self.make_port(options=optparse.Values({'additional_env_var': ['FOO=BAR', 'BAR=FOO']}))
         self.assertEqual(port.get_option('additional_env_var'), ['FOO=BAR', 'BAR=FOO'])
         environment = port.setup_environ_for_server()
         self.assertTrue(('FOO' in environment) & ('BAR' in environment))
@@ -635,14 +604,12 @@
 
     def test_should_run_as_pixel_test_with_no_pixel_tests_in_args(self):
         # With the --no-pixel-tests flag, no tests should run as pixel tests.
-        options = optparse.Values(
-            {'pixel_tests': False, 'target': 'Release', 'configuration': 'Release'})
+        options = optparse.Values({'pixel_tests': False})
         port = self.make_port(options=options)
         self.assertFalse(port.should_run_as_pixel_test('fast/css/001.html'))
 
     def test_should_run_as_pixel_test_default(self):
-        options = optparse.Values(
-            {'pixel_tests': True, 'target': 'Release', 'configuration': 'Release'})
+        options = optparse.Values({'pixel_tests': True})
         port = self.make_port(options=options)
         self.assertFalse(port.should_run_as_pixel_test('external/wpt/dom/interfaces.html'))
         self.assertFalse(port.should_run_as_pixel_test('virtual/a-name/external/wpt/dom/interfaces.html'))
@@ -824,13 +791,11 @@
     def test_build_path(self):
         # Test for a protected method - pylint: disable=protected-access
         # Test that optional paths are used regardless of whether they exist.
-        options = optparse.Values({'target': 'Release', 'build_directory': 'xcodebuild',
-                                   'configuration': 'Release'})
+        options = optparse.Values({'configuration': 'Release', 'build_directory': 'xcodebuild'})
         self.assertEqual(self.make_port(options=options)._build_path(), '/mock-checkout/xcodebuild/Release')
 
         # Test that "out" is used as the default.
-        options = optparse.Values({'target': 'Release', 'build_directory': None,
-                                   'configuration': 'Release'})
+        options = optparse.Values({'configuration': 'Release', 'build_directory': None})
         self.assertEqual(self.make_port(options=options)._build_path(), '/mock-checkout/out/Release')
 
     def test_dont_require_http_server(self):
@@ -838,8 +803,7 @@
         self.assertEqual(port.requires_http_server(), False)
 
     def test_can_load_actual_virtual_test_suite_file(self):
-        port = Port(SystemHost(), 'baseport', options=optparse.Values(
-            {'target': 'Release', 'configuration': 'Release'}))
+        port = Port(SystemHost(), 'baseport')
 
         # If this call returns successfully, we found and loaded the LayoutTests/VirtualTestSuites.
         _ = port.virtual_test_suites()
@@ -881,10 +845,7 @@
         self.assertEqual(port.default_results_directory(), '/mock-checkout/out/Default/layout-test-results')
 
     def test_results_directory(self):
-        options = options=optparse.Values({
-            'results_directory': 'some-directory/results', 'target': 'Release',
-            'configuration': 'Release'})
-        port = self.make_port(options=options)
+        port = self.make_port(options=optparse.Values({'results_directory': 'some-directory/results'}))
         # A results directory can be given as an option, and it is relative to current working directory.
         self.assertEqual(port.host.filesystem.cwd, '/')
         self.assertEqual(port.results_directory(), '/some-directory/results')
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py
index 5d8bf629..71e9f80e 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/browser_test_unittest.py
@@ -42,15 +42,14 @@
         self.assertTrue(self.make_port()._path_to_driver().endswith(self.driver_name_endswith))
 
     def test_default_timeout_ms(self):
-        options = optparse.Values({'target': 'Release', 'configuration': 'Release'})
-        self.assertEqual(self.make_port(options=options).default_timeout_ms(), self.timeout_ms)
-        options = optparse.Values({'target': 'Debug', 'configuration': 'Debug'})
-        self.assertEqual(self.make_port(options=options).default_timeout_ms(), 3 * self.timeout_ms)
+        self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Release'})).default_timeout_ms(),
+                         self.timeout_ms)
+        self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Debug'})).default_timeout_ms(),
+                         3 * self.timeout_ms)
 
     def test_driver_type(self):
-        port = self.make_port(options=optparse.Values(
-            {'driver_name': 'browser_tests', 'target': 'Release', 'configuration': 'Release'}))
-        self.assertTrue(isinstance(port.create_driver(1), browser_test_driver.BrowserTestDriver))
+        self.assertTrue(isinstance(self.make_port(options=optparse.Values({'driver_name': 'browser_tests'})
+                                                  ).create_driver(1), browser_test_driver.BrowserTestDriver))
 
     def test_layout_tests_dir(self):
         self.assertTrue(self.make_port().layout_tests_dir().endswith('chrome/test/data/printing/layout_tests'))
@@ -91,7 +90,5 @@
     timeout_ms = 20 * 1000
 
     def test_driver_path(self):
-        options = optparse.Values(
-            {'driver_name': 'browser_tests', 'target': 'Release', 'configuration': 'Release'})
-        test_port = self.make_port(options=options)
+        test_port = self.make_port(options=optparse.Values({'driver_name': 'browser_tests'}))
         self.assertNotIn('.app/Contents/MacOS', test_port._path_to_driver())
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py
index 5228bde..964deaf3 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/driver_unittest.py
@@ -38,8 +38,7 @@
 class DriverTest(unittest.TestCase):
 
     def make_port(self):
-        return Port(MockSystemHost(), 'test',
-                    optparse.Values({'configuration': 'Release', 'target': 'Release'}))
+        return Port(MockSystemHost(), 'test', optparse.Values({'configuration': 'Release'}))
 
     def _assert_wrapper(self, wrapper_string, expected_wrapper):
         wrapper = Driver(self.make_port(), None)._command_wrapper(wrapper_string)
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/factory.py b/third_party/blink/tools/blinkpy/web_tests/port/factory.py
index 43f3e66..0aeaa03 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/factory.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/factory.py
@@ -59,19 +59,15 @@
             return 'win'
         raise NotImplementedError('unknown platform: %s' % platform)
 
-    def _default_options(self):
-        return optparse.Values({'configuration': 'Release', 'target': 'Release'})
-
     def get(self, port_name=None, options=None, **kwargs):
         """Returns an object implementing the Port interface.
 
         If port_name is None, this routine attempts to guess at the most
         appropriate port on this platform.
         """
-        options = options or self._default_options()
         port_name = port_name or self._default_port()
 
-        check_configuration_and_target(self._host.filesystem, options)
+        _check_configuration_and_target(self._host.filesystem, options)
 
         if 'browser_test' in port_name:
             module_name, class_name = port_name.rsplit('.', 1)
@@ -134,29 +130,28 @@
 
 
 def _builder_options(builder_name):
-    configuration = 'Debug' if re.search(r'[d|D](ebu|b)g', builder_name) else 'Release'
     return optparse.Values({
         'builder_name': builder_name,
-        'configuration': configuration,
-        'target': configuration,
+        'configuration': 'Debug' if re.search(r'[d|D](ebu|b)g', builder_name) else 'Release',
+        'target': None,
     })
 
 
-def check_configuration_and_target(host, options):
+def _check_configuration_and_target(host, options):
     """Updates options.configuration based on options.target."""
     if not options or not getattr(options, 'target', None):
         return
 
     gn_configuration = _read_configuration_from_gn(host, options)
     if gn_configuration:
-        expected_configuration = getattr(options, 'configuration', None)
+        expected_configuration = getattr(options, 'configuration')
         if expected_configuration not in (None, gn_configuration):
             raise ValueError('Configuration does not match the GN build args. '
                              'Expected "%s" but got "%s".' % (gn_configuration, expected_configuration))
         options.configuration = gn_configuration
         return
 
-    if options.target in ('Default', 'Debug', 'Debug_x64'):
+    if options.target in ('Debug', 'Debug_x64'):
         options.configuration = 'Debug'
     elif options.target in ('Release', 'Release_x64'):
         options.configuration = 'Release'
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/factory_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/factory_unittest.py
index aba6def..2e241d38 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/factory_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/factory_unittest.py
@@ -45,7 +45,7 @@
     # instead of passing generic "options".
 
     def setUp(self):
-      self.webkit_options = optparse.Values({'pixel_tests': False, 'configuration': 'Release'})
+        self.webkit_options = optparse.Values({'pixel_tests': False})
 
     def assert_port(self, port_name=None, os_name=None, os_version=None, options=None, cls=None):
         host = MockHost(os_name=os_name, os_version=os_version)
@@ -98,35 +98,32 @@
         return factory.PortFactory(host).get(options=options)
 
     def test_default_target_and_configuration(self):
-        # Generate a fake 'content shell' binary in 'Debug' target
-        temp_port = self.get_port(target='Debug', configuration='Debug')
-        path_to_fake_driver = temp_port._path_to_driver()
-        port = self.get_port(files={path_to_fake_driver: 'blah'})
-        self.assertEqual(port._options.configuration, 'Debug')
-        self.assertEqual(port._options.target, 'Debug')
+        port = self.get_port()
+        self.assertEqual(port._options.configuration, 'Release')
+        self.assertEqual(port._options.target, 'Release')
 
     def test_debug_configuration(self):
-        port = self.get_port(target='Debug', configuration='Debug')
+        port = self.get_port(configuration='Debug')
         self.assertEqual(port._options.configuration, 'Debug')
         self.assertEqual(port._options.target, 'Debug')
 
     def test_release_configuration(self):
-        port = self.get_port(target='Release', configuration='Release')
+        port = self.get_port(configuration='Release')
         self.assertEqual(port._options.configuration, 'Release')
         self.assertEqual(port._options.target, 'Release')
 
     def test_debug_target(self):
-        port = self.get_port(target='Debug', configuration='Debug')
+        port = self.get_port(target='Debug')
         self.assertEqual(port._options.configuration, 'Debug')
         self.assertEqual(port._options.target, 'Debug')
 
     def test_debug_x64_target(self):
-        port = self.get_port(target='Debug_x64', configuration='Debug')
+        port = self.get_port(target='Debug_x64')
         self.assertEqual(port._options.configuration, 'Debug')
         self.assertEqual(port._options.target, 'Debug_x64')
 
     def test_release_x64_target(self):
-        port = self.get_port(target='Release_x64', configuration='Release')
+        port = self.get_port(target='Release_x64')
         self.assertEqual(port._options.configuration, 'Release')
         self.assertEqual(port._options.target, 'Release_x64')
 
@@ -161,7 +158,7 @@
 
     def test_unknown_dir(self):
         with self.assertRaises(ValueError):
-            self.get_port(target='unknown', configuration='Debug')
+            self.get_port(target='unknown')
 
     def test_both_configuration_and_target_is_an_error(self):
         with self.assertRaises(ValueError):
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py
index 6bfcf74..76199443 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py
@@ -79,17 +79,14 @@
         # FIXME: Check that, for now, these are illegal port names.
         # Eventually we should be able to do the right thing here.
         with self.assertRaises(AssertionError):
-          linux.LinuxPort(
-              MockSystemHost(), port_name='linux-x86',
-              options=optparse.Values({'configuration': 'Release', 'target': 'Release'}))
+            linux.LinuxPort(MockSystemHost(), port_name='linux-x86')
 
     def test_operating_system(self):
         self.assertEqual('linux', self.make_port().operating_system())
 
     def test_driver_name_option(self):
         self.assertTrue(self.make_port()._path_to_driver().endswith('content_shell'))
-        port = self.make_port(options=optparse.Values(
-          {'driver_name': 'OtherDriver', 'configuration': 'Release', 'target': 'Release'}))
+        port = self.make_port(options=optparse.Values({'driver_name': 'OtherDriver'}))
         self.assertTrue(port._path_to_driver().endswith('OtherDriver'))  # pylint: disable=protected-access
 
     def test_path_to_image_diff(self):
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py
index 55fbdff..7cf62d3b 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py
@@ -48,8 +48,7 @@
 
     def test_driver_name_option(self):
         self.assertTrue(self.make_port()._path_to_driver().endswith('Content Shell'))
-        port = self.make_port(options=optparse.Values(
-            {'driver_name': 'OtherDriver', 'configuration': 'Release', 'target': 'Release'}))
+        port = self.make_port(options=optparse.Values(dict(driver_name='OtherDriver')))
         self.assertTrue(port._path_to_driver().endswith('OtherDriver'))  # pylint: disable=protected-access
 
     def test_path_to_image_diff(self):
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/mock_drt_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/mock_drt_unittest.py
index 944fe41..4103cae 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/mock_drt_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/mock_drt_unittest.py
@@ -41,8 +41,7 @@
 
 class MockDRTPortTest(port_testcase.PortTestCase):
 
-    def make_port(self, host=None,
-                  options=optparse.Values({'configuration': 'Release', 'target': 'Release'})):
+    def make_port(self, host=None, options=optparse.Values({'configuration': 'Release'})):
         host = host or MockSystemHost()
         test.add_unit_tests_to_mock_filesystem(host.filesystem)
         return mock_drt.MockDRTPort(host, port_name='mock-mac', options=options)
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py b/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py
index e9d0415..8628e69 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/port_testcase.py
@@ -66,9 +66,7 @@
 
     def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=None, **kwargs):
         host = host or MockSystemHost(os_name=(os_name or self.os_name), os_version=(os_version or self.os_version))
-        options = options or optparse.Values(
-            {'target': 'Release', 'configuration': 'Release'})
-
+        options = options or optparse.Values({'configuration': 'Release'})
         port_name = port_name or self.port_name
         port_name = self.port_maker.determine_full_port_name(host, options, port_name)
         return self.port_maker(host, port_name, options=options, **kwargs)
@@ -119,18 +117,14 @@
         self.assertEqual(port.default_max_locked_shards(), 1)
 
     def test_default_timeout_ms(self):
-        options = optparse.Values({'configuration': 'Release', 'target': 'Release'})
-        self.assertEqual(self.make_port(options=options).default_timeout_ms(), 6000)
-        options = optparse.Values({'configuration': 'Debug', 'target': 'Debug'})
-        self.assertEqual(self.make_port(options=options).default_timeout_ms(), 18000)
+        self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Release'})).default_timeout_ms(), 6000)
+        self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Debug'})).default_timeout_ms(), 18000)
 
     def test_driver_cmd_line(self):
         port = self.make_port()
         self.assertTrue(len(port.driver_cmd_line()))
 
-        options = optparse.Values({
-            'additional_driver_flag': ['--foo=bar', '--foo=baz'],
-            'configuration': 'Release', 'target': 'Release'})
+        options = optparse.Values(dict(additional_driver_flag=['--foo=bar', '--foo=baz']))
         port = self.make_port(options=options)
         cmd_line = port.driver_cmd_line()
         self.assertTrue('--foo=bar' in cmd_line)
@@ -267,9 +261,7 @@
         ordered_dict = port.expectations_dict()
         self.assertEqual(port.path_to_generic_test_expectations_file(), ordered_dict.keys()[0])
 
-        options = optparse.Values(
-            {'additional_expectations': ['/tmp/foo', '/tmp/bar'],
-             'configuration': 'Release', 'target': 'Release'})
+        options = optparse.Values(dict(additional_expectations=['/tmp/foo', '/tmp/bar']))
         port = self.make_port(options=options)
         for path in port.expectations_files():
             port.host.filesystem.write_text_file(path, '')
@@ -302,9 +294,7 @@
         self.assertEqual(port.path_to_apache_config_file(), '/existing/httpd.conf')
 
     def test_additional_platform_directory(self):
-        port = self.make_port(options=optparse.Values(
-            {'additional_platform_directory': ['/tmp/foo'],
-             'configuration': 'Release', 'target': 'Release'}))
+        port = self.make_port(options=optparse.Values(dict(additional_platform_directory=['/tmp/foo'])))
         self.assertEqual(port.baseline_search_path()[0], '/tmp/foo')
 
     def test_virtual_test_suites(self):
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/test.py b/third_party/blink/tools/blinkpy/web_tests/port/test.py
index cc7a63b..24ef1d7b 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/test.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/test.py
@@ -447,10 +447,9 @@
             'linux': ['precise', 'trusty']
         }
 
-    def _path_to_driver(self, target=None):
+    def _path_to_driver(self):
         # This routine shouldn't normally be called, but it is called by
         # the mock_drt Driver. We return something, but make sure it's useless.
-        del target  # Unused
         return 'MOCK _path_to_driver'
 
     def default_child_processes(self):
@@ -462,13 +461,9 @@
     def check_sys_deps(self, needs_http):
         return exit_codes.OK_EXIT_STATUS
 
-    def default_target(self):
+    def default_configuration(self):
         return 'Release'
 
-    def check_configuration_and_target(self):
-        if not getattr(self._options, 'configuration', None):
-             self._options.configuration = 'Release'
-
     def diff_image(self, expected_contents, actual_contents):
         diffed = actual_contents != expected_contents
         if not actual_contents and not expected_contents:
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py
index 7cb1653..5c73f13 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py
@@ -105,9 +105,8 @@
 
     def test_driver_name_option(self):
         self.assertTrue(self.make_port()._path_to_driver().endswith('content_shell.exe'))
-        port = self.make_port(options=optparse.Values(
-            {'driver_name': 'OtherDriver', 'configuration': 'Release', 'target': 'Release'}))
-        self.assertTrue(port._path_to_driver().endswith('OtherDriver.exe'))
+        self.assertTrue(
+            self.make_port(options=optparse.Values({'driver_name': 'OtherDriver'}))._path_to_driver().endswith('OtherDriver.exe'))
 
     def test_path_to_image_diff(self):
         self.assertEqual(self.make_port()._path_to_image_diff(), '/mock-checkout/out/Release/image_diff.exe')
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py
index 42de0bd..ddcdeb9 100644
--- a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py
+++ b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py
@@ -544,7 +544,7 @@
             'WEBKIT_TEST_MAX_LOCKED_SHARDS', str(port.default_max_locked_shards())))
 
     if not options.configuration:
-        options.configuration = 'Release'
+        options.configuration = port.default_configuration()
 
     if not options.time_out_ms:
         options.time_out_ms = str(port.default_timeout_ms())
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py
index 89ce75f..153ffa83 100644
--- a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py
@@ -1631,18 +1631,15 @@
         stderr = StringIO.StringIO()
         try:
             run_webkit_tests._run_tests = interrupting_run
-            res = run_webkit_tests.main(
-                ['--release', '--target=Release'], stdout, stderr)
+            res = run_webkit_tests.main([], stdout, stderr)
             self.assertEqual(res, exit_codes.INTERRUPTED_EXIT_STATUS)
 
             run_webkit_tests._run_tests = successful_run
-            res = run_webkit_tests.main(
-                ['--platform', 'test', '--release', '--target=Release'], stdout, stderr)
+            res = run_webkit_tests.main(['--platform', 'test'], stdout, stderr)
             self.assertEqual(res, exit_codes.UNEXPECTED_ERROR_EXIT_STATUS)
 
             run_webkit_tests._run_tests = exception_raising_run
-            res = run_webkit_tests.main(
-                ['--release', '--target=Release'], stdout, stderr)
+            res = run_webkit_tests.main([], stdout, stderr)
             self.assertEqual(res, exit_codes.UNEXPECTED_ERROR_EXIT_STATUS)
         finally:
             run_webkit_tests._run_tests = orig_run_fn
diff --git a/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py b/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
index a0a3581..dd6d965a 100644
--- a/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
+++ b/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
@@ -61,9 +61,6 @@
     logger.setLevel(logging.DEBUG if options.verbose else logging.INFO)
 
     host = Host()
-    # Constructing a port requires explicitly setting the configuration & target.
-    options.configuration = 'Release'
-    options.target = 'Release'
     port_obj = host.port_factory.get(options=options)
     if not options.output_dir:
         options.output_dir = port_obj.default_results_directory()
diff --git a/third_party/boringssl/BUILD.generated.gni b/third_party/boringssl/BUILD.generated.gni
index db2877d..435198a 100644
--- a/third_party/boringssl/BUILD.generated.gni
+++ b/third_party/boringssl/BUILD.generated.gni
@@ -307,7 +307,6 @@
   "src/include/openssl/hmac.h",
   "src/include/openssl/is_boringssl.h",
   "src/include/openssl/lhash.h",
-  "src/include/openssl/lhash_macros.h",
   "src/include/openssl/md4.h",
   "src/include/openssl/md5.h",
   "src/include/openssl/mem.h",
@@ -331,7 +330,6 @@
   "src/include/openssl/safestack.h",
   "src/include/openssl/sha.h",
   "src/include/openssl/span.h",
-  "src/include/openssl/srtp.h",
   "src/include/openssl/stack.h",
   "src/include/openssl/thread.h",
   "src/include/openssl/type_check.h",
@@ -382,6 +380,7 @@
 
 ssl_headers = [
   "src/include/openssl/dtls1.h",
+  "src/include/openssl/srtp.h",
   "src/include/openssl/ssl.h",
   "src/include/openssl/ssl3.h",
   "src/include/openssl/tls1.h",
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn
index 256aca0..da1eef8 100644
--- a/third_party/boringssl/BUILD.gn
+++ b/third_party/boringssl/BUILD.gn
@@ -31,7 +31,6 @@
     # TODO(davidben): Fix size_t truncations in BoringSSL.
     # https://crbug.com/boringssl/22
     "//build/config/compiler:no_size_t_to_int_warning",
-    "//build/config/sanitizers:cfi_icall_generalize_pointers",
   ]
   if (is_posix || is_fuchsia) {
     cflags_c = [ "-std=c99" ]
diff --git a/third_party/closure_compiler/PRESUBMIT.py b/third_party/closure_compiler/PRESUBMIT.py
deleted file mode 100644
index af7a56f..0000000
--- a/third_party/closure_compiler/PRESUBMIT.py
+++ /dev/null
@@ -1,11 +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.
-
-def PostUploadHook(cl, change, output_api):
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:closure_compilation',
-    ],
-    'Automatically added optional Closure bots to run on CQ.')
diff --git a/third_party/crc32c/BUILD.gn b/third_party/crc32c/BUILD.gn
index e286afd..3632b99e 100644
--- a/third_party/crc32c/BUILD.gn
+++ b/third_party/crc32c/BUILD.gn
@@ -67,7 +67,7 @@
     "config/crc32c/crc32c_config.h",
     "src/include/crc32c/crc32c.h",
     "src/src/crc32c.cc",
-    "src/src/crc32c_arm_linux_check.h",
+    "src/src/crc32c_arm64_linux_check.h",
     "src/src/crc32c_internal.h",
     "src/src/crc32c_portable.cc",
     "src/src/crc32c_prefetch.h",
diff --git a/third_party/fuchsia-sdk/BUILD.gn b/third_party/fuchsia-sdk/BUILD.gn
index d5a749f..8fad6c5a 100644
--- a/third_party/fuchsia-sdk/BUILD.gn
+++ b/third_party/fuchsia-sdk/BUILD.gn
@@ -41,7 +41,6 @@
     "include/lib/fdio/module.modulemap",
     "include/lib/fdio/namespace.h",
     "include/lib/fdio/remoteio.h",
-    "include/lib/fdio/socket.h",
     "include/lib/fdio/spawn.h",
     "include/lib/fdio/unsafe.h",
     "include/lib/fdio/util.h",
diff --git a/third_party/openh264/BUILD.gn b/third_party/openh264/BUILD.gn
index 0147b75..7624dda 100644
--- a/third_party/openh264/BUILD.gn
+++ b/third_party/openh264/BUILD.gn
@@ -10,11 +10,12 @@
 # Config shared by all openh264 targets.
 config("config") {
   cflags = []
+  defines = []
 
   if (is_chromeos && target_cpu == "arm") {
     # HAVE_NEON and __chromeos__ are needed for enabling NEON on ChromeOS
     # devices.
-    defines = [
+    defines += [
       "HAVE_NEON",
       "__chromeos__",
     ]
diff --git a/third_party/polymer/PRESUBMIT.py b/third_party/polymer/PRESUBMIT.py
deleted file mode 100644
index af7a56f..0000000
--- a/third_party/polymer/PRESUBMIT.py
+++ /dev/null
@@ -1,11 +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.
-
-def PostUploadHook(cl, change, output_api):
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:closure_compilation',
-    ],
-    'Automatically added optional Closure bots to run on CQ.')
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c1ebf06d..5c53326 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -11768,6 +11768,24 @@
   </int>
 </enum>
 
+<enum name="DownloadFrameGesture">
+  <summary>
+    The type of frame in which a download occurs and whether the download
+    involves a transient user gesture. It is only recorded for downloads
+    originated from navigations or from HTML anchor download attributes.
+  </summary>
+  <int value="0" label="MainFrame_NoGesture"/>
+  <int value="1" label="MainFrame_Gesture"/>
+  <int value="2" label="SameOriginAdSubframe_NoGesture"/>
+  <int value="3" label="SameOriginAdSubframe_Gesture"/>
+  <int value="4" label="SameOriginNonAdSubframe_NoGesture"/>
+  <int value="5" label="SameOriginNonAdSubframe_Gesture"/>
+  <int value="6" label="CrossOriginAdSubframe_NoGesture"/>
+  <int value="7" label="CrossOriginAdSubframe_Gesture"/>
+  <int value="8" label="CrossOriginNonAdSubframe_NoGesture"/>
+  <int value="9" label="CrossOriginNonAdSubframe_Gesture"/>
+</enum>
+
 <enum name="DownloadFunctions">
   <int value="0" label="download"/>
   <int value="1" label="search"/>
@@ -16688,7 +16706,7 @@
   <int value="937" label="DELETED_COPRESENCEENDPOINTS_CREATELOCALENDPOINT"/>
   <int value="938" label="DELETED_COPRESENCEENDPOINTS_DESTROYLOCALENDPOINT"/>
   <int value="939" label="DELETED_COPRESENCEENDPOINTS_SEND"/>
-  <int value="940" label="INLINE_INSTALL_PRIVATE_INSTALL"/>
+  <int value="940" label="DELETED_INLINE_INSTALL_PRIVATE_INSTALL"/>
   <int value="941" label="LAUNCHERPAGE_SETENABLED"/>
   <int value="942" label="DELETED_CRYPTOTOKENPRIVATE_REQUESTPERMISSION"/>
   <int value="943" label="BLUETOOTHPRIVATE_DISCONNECTALL"/>
@@ -17392,7 +17410,7 @@
   <int value="88" label="kIdltest"/>
   <int value="89" label="kIdle"/>
   <int value="90" label="kImeWindowEnabled"/>
-  <int value="91" label="kInlineInstallPrivate"/>
+  <int value="91" label="kDeleted_InlineInstallPrivate"/>
   <int value="92" label="kInput"/>
   <int value="93" label="kInputMethodPrivate"/>
   <int value="94" label="kDeleted_InterceptAllKeys"/>
@@ -30749,7 +30767,6 @@
   <int value="1689183477" label="enable-merge-key-char-events"/>
   <int value="1690837904" label="save-previous-document-resources"/>
   <int value="1691568199" label="AndroidSpellCheckerNonLowEnd:disabled"/>
-  <int value="1694562245" label="UseSurfaceLayerForVideoMS:disabled"/>
   <int value="1694766748"
       label="AutofillRestrictUnownedFieldsToFormlessCheckout:enabled"/>
   <int value="1694798717" label="NewNetErrorPageUI:enabled"/>
@@ -30840,7 +30857,6 @@
   <int value="1862207743" label="enable-android-spellchecker"/>
   <int value="1863622457" label="WebAuthentication:enabled"/>
   <int value="1865068568" label="disable-audio-support-for-desktop-share"/>
-  <int value="1865702649" label="UseSurfaceLayerForVideoMS:enabled"/>
   <int value="1865799183" label="javascript-harmony"/>
   <int value="1865963858" label="tls13-variant"/>
   <int value="1866079109" label="team-drives"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cbf55a8..225ee13 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -22602,6 +22602,15 @@
   </summary>
 </histogram>
 
+<histogram name="Download.FrameGesture" enum="DownloadFrameGesture">
+  <owner>yaoxia@chromium.org</owner>
+  <summary>
+    The type of frame in which a download occurs and whether the download
+    involves a transient user gesture. It is only recorded for downloads
+    originated from navigations or from HTML anchor download attributes.
+  </summary>
+</histogram>
+
 <histogram name="Download.HistorySize">
   <owner>dtrainor@chromium.org</owner>
   <summary>
@@ -109987,6 +109996,12 @@
 
 <histogram name="TaskScheduler.BlockShutdownTasksPostedDuringShutdown"
     units="tasks">
+  <obsolete>
+    Deprecated 10/2018. Instead of recording a histogram with the number of
+    BLOCK_SHUTDOWN tasks posted during shutdown, we generate a crash when too
+    many BLOCK_SHUTDOWN tasks are posted during shutdown. A crash dump is more
+    actionnable than a histogram.
+  </obsolete>
   <owner>fdoray@chromium.org</owner>
   <summary>
     Number of BLOCK_SHUTDOWN tasks that were posted to a base::TaskScheduler
diff --git a/tools/perf/core/perf_benchmark_unittest.py b/tools/perf/core/perf_benchmark_unittest.py
index da74b7d..876e781 100644
--- a/tools/perf/core/perf_benchmark_unittest.py
+++ b/tools/perf/core/perf_benchmark_unittest.py
@@ -62,7 +62,8 @@
     benchmark = perf_benchmark.PerfBenchmark()
     options = options_for_unittests.GetCopy()
     options.chrome_root = self._output_dir
-    options.browser_type = "any"
+    if not options.browser_type:
+      options.browser_type = "any"
     possible_browser = browser_finder.FindBrowser(options)
     if possible_browser is None:
       return
diff --git a/tools/perf/measurements/clock_domain_test.py b/tools/perf/measurements/clock_domain_test.py
index 46c1919..2f6ef4f 100644
--- a/tools/perf/measurements/clock_domain_test.py
+++ b/tools/perf/measurements/clock_domain_test.py
@@ -13,10 +13,10 @@
 
 class ClockDomainTest(tab_test_case.TabTestCase):
 
-  # Don't run this test on Android; it's not supposed to work on Android
-  # (since when doing Android tracing there are two different devices,
-  # so the clock domains will be different)
-  @decorators.Disabled('android')
+  # Don't run this test on Android and remote Chrome OS; it won't work
+  # because there are two different devices, so the clock domains will
+  # be different.
+  @decorators.Disabled('android', 'cros-chrome')
   @decorators.Isolated
   def testTelemetryUsesChromeClockDomain(self):
 
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index 43210147..8777021 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -714,21 +714,23 @@
   // deletion. The connection to the server is about to be dropped and the
   // server will take appropriate action.
   // TODO: decide how to deal with windows not owned by this client.
+  base::Optional<uint32_t> delete_change_id;
   if (!in_shutdown_ && origin == Origin::CLIENT &&
       (WasCreatedByThisClient(window) || IsRoot(window))) {
-    const uint32_t change_id =
+    delete_change_id =
         ScheduleInFlightChange(std::make_unique<CrashInFlightChange>(
             window, ChangeType::DELETE_WINDOW));
-    tree_->DeleteWindow(change_id, window->server_id());
+    tree_->DeleteWindow(delete_change_id.value(), window->server_id());
   }
 
   windows_.erase(window->server_id());
 
-  // Remove any InFlightChanges associated with the window.
+  // Remove any InFlightChanges associated with the window, except the delete.
   std::set<uint32_t> in_flight_change_ids_to_remove;
   for (const auto& pair : in_flight_map_) {
-    if (pair.second->window() == window)
-      in_flight_change_ids_to_remove.insert(pair.first);
+    const uint32_t change_id = pair.first;
+    if (pair.second->window() == window && change_id != delete_change_id)
+      in_flight_change_ids_to_remove.insert(change_id);
   }
   for (auto change_id : in_flight_change_ids_to_remove)
     in_flight_map_.erase(change_id);
diff --git a/ui/gl/PRESUBMIT.py b/ui/gl/PRESUBMIT.py
deleted file mode 100644
index 290b06c..0000000
--- a/ui/gl/PRESUBMIT.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (c) 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Presubmit script for //ui/gl.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
-  """git cl upload will call this hook after the issue is created/modified.
-
-  This hook modifies the CL description in order to run extra GPU
-  tests (in particular, the WebGL 2.0 conformance tests) in addition
-  to the regular CQ try bots. This test suite is too large to run
-  against all Chromium commits, but should be run against changes
-  likely to affect these tests.
-
-  When adding/removing tests here, ensure that both gpu/PRESUBMIT.py and
-  ui/gl/PRESUBMIT.py are updated.
-  """
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:linux_optional_gpu_tests_rel',
-      'luci.chromium.try:mac_optional_gpu_tests_rel',
-      'luci.chromium.try:win_optional_gpu_tests_rel',
-      'luci.chromium.try:android_optional_gpu_tests_rel',
-    ],
-    'Automatically added optional GPU tests to run on CQ.')