diff --git a/DEPS b/DEPS
index c9eae12..82e67db 100644
--- a/DEPS
+++ b/DEPS
@@ -121,11 +121,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': '1a0126f61a9867a97a1c05972e6142c296d3e7de',
+  'skia_revision': '26ccfcc96f989d90db388ddd7fb8604b7511db48',
   # 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': 'b2d4354186e3e44425b94f1bea9cf0f1e1bc60c3',
+  'v8_revision': 'd5b026733ee422f3f4e1a23a922aae7216e0ec14',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -141,11 +141,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'debaacab10b59cdd5a6e636be23e9ab560a7cec7',
+  'swiftshader_revision': 'cd610c9a9dbc9a827900725a0ae2645e37a8a4b2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '0e08d591129048435706e2b7e7abd7164714233a',
+  'pdfium_revision': '33cc9c60892a0d527bf7aee95c8be8d298119efd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -153,7 +153,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': '6c1b376e1d502eff365028fe054115f1b46d19b5',
+  'boringssl_revision': '1a51a5b4a6bdf7ee11b443f21f08dc2ba2de9815',
   # 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.
@@ -514,7 +514,7 @@
   },
 
   'src/third_party/android_tools': {
-      'url': Var('chromium_git') + '/android_tools.git' + '@' + 'e958d6ea74442d4e0849bb8a018d215a0e78981d',
+      'url': Var('chromium_git') + '/android_tools.git' + '@' + '347a7c8078a009e98995985b7ab6ec6b35696dea',
       'condition': 'checkout_android_native_support',
   },
 
@@ -694,7 +694,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'da18f31f960fc44382cb333d91b07058e07ddc07',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '45c7f2def3e9c454ccc988ff3445feb5ddd3d4ba',
       'condition': 'checkout_linux',
   },
 
@@ -719,7 +719,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4f738c1fe58170ab1bc849381d62d28222920815',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'a1fbdff17736899759ae1d320ac684122bef21bd',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1054,7 +1054,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '11f908788289acc0e395bdfc38fdf19fecfeec26',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '1bc7c76b73c8e305bb66b1dbfd40d43bc2d2f245',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1258,7 +1258,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7b80b951e0bf9a55999b4c4acf51f0d121e8d006',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b4138ddf946e15269718c688bc2a2d3927a3f322',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 93f9ea74..4251fa8d 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1342,6 +1342,7 @@
     "//ui/base",
     "//ui/base:ui_data_pack",
     "//ui/base/ime",
+    "//ui/base/user_activity",
     "//ui/chromeos",
     "//ui/chromeos/events",
     "//ui/chromeos/resources",
@@ -1534,6 +1535,7 @@
     "accessibility/touch_exploration_manager_unittest.cc",
     "app_launch_unittest.cc",
     "app_list/app_list_presenter_delegate_unittest.cc",
+    "app_list/app_list_unittest.cc",
     "app_list/home_launcher_gesture_handler_unittest.cc",
     "app_list/model/app_list_item_list_unittest.cc",
     "app_list/model/app_list_model_unittest.cc",
@@ -1579,6 +1581,7 @@
     "display/window_tree_host_manager_unittest.cc",
     "drag_drop/drag_drop_controller_unittest.cc",
     "drag_drop/drag_drop_tracker_unittest.cc",
+    "drag_drop/drag_drop_unittest.cc",
     "drag_drop/drag_image_view_unittest.cc",
     "events/keyboard_driven_event_rewriter_unittest.cc",
     "events/select_to_speak_event_handler_unittest.cc",
@@ -1901,6 +1904,7 @@
     "//ui/base",
     "//ui/base:test_support",
     "//ui/base/ime",
+    "//ui/base/user_activity",
     "//ui/chromeos",
     "//ui/chromeos/events",
     "//ui/compositor",
@@ -2184,30 +2188,6 @@
   ]
 }
 
-static_library("interactive_ui_test_support") {
-  testonly = true
-  configs += [ "//build/config:precompiled_headers" ]
-  public_deps = [
-    ":test_support",
-    "//ash",
-  ]
-  sources = [
-    "test/ash_interactive_ui_test_base.cc",
-    "test/ash_interactive_ui_test_base.h",
-  ]
-  deps = [
-    ":test_support",
-    "//base",
-    "//mojo/core/embedder",
-    "//skia",
-    "//testing/gtest",
-    "//ui/aura",
-    "//ui/base",
-    "//ui/base:test_support",
-    "//ui/gl:test_support",
-  ]
-}
-
 service_executable("ash_service") {
   output_name = "ash"
 
diff --git a/ash/accelerators/accelerator_interactive_uitest_chromeos.cc b/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
deleted file mode 100644
index 2d6666ef8..0000000
--- a/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/accelerators/accelerator_controller.h"
-
-#include "ash/app_list/test/app_list_test_helper.h"
-#include "ash/shell.h"
-#include "ash/shell_observer.h"
-#include "ash/system/network/network_observer.h"
-#include "ash/system/tray/system_tray_notifier.h"
-#include "ash/test/ash_interactive_ui_test_base.h"
-#include "ash/test_screenshot_delegate.h"
-#include "ash/wm/window_state.h"
-#include "ash/wm/window_util.h"
-#include "base/run_loop.h"
-#include "base/test/metrics/user_action_tester.h"
-#include "chromeos/network/network_handler.h"
-#include "ui/base/test/ui_controls.h"
-
-namespace ash {
-
-namespace {
-
-// A network observer to watch for the toggle wifi events.
-class TestNetworkObserver : public NetworkObserver {
- public:
-  TestNetworkObserver() : wifi_enabled_status_(false) {}
-
-  // ash::NetworkObserver:
-  void RequestToggleWifi() override {
-    wifi_enabled_status_ = !wifi_enabled_status_;
-  }
-
-  bool wifi_enabled_status() const { return wifi_enabled_status_; }
-
- private:
-  bool wifi_enabled_status_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestNetworkObserver);
-};
-
-}  // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-
-// This is intended to test few samples from each category of accelerators to
-// make sure they work properly. The test is done as an interactive ui test
-// using ui_controls::Send*() functions.
-// This is to catch any future regressions (crbug.com/469235).
-class AcceleratorInteractiveUITest : public AshInteractiveUITestBase,
-                                     public ShellObserver {
- public:
-  AcceleratorInteractiveUITest() : is_in_overview_mode_(false) {}
-
-  void SetUp() override {
-    AshInteractiveUITestBase::SetUp();
-
-    Shell::Get()->AddShellObserver(this);
-
-    chromeos::NetworkHandler::Initialize();
-  }
-
-  void TearDown() override {
-    chromeos::NetworkHandler::Shutdown();
-
-    Shell::Get()->RemoveShellObserver(this);
-
-    AshInteractiveUITestBase::TearDown();
-  }
-
-  // Sends a key press event and waits synchronously until it's completely
-  // processed.
-  void SendKeyPressSync(ui::KeyboardCode key,
-                        bool control,
-                        bool shift,
-                        bool alt) {
-    base::RunLoop loop;
-    ui_controls::SendKeyPressNotifyWhenDone(Shell::GetPrimaryRootWindow(), key,
-                                            control, shift, alt, false,
-                                            loop.QuitClosure());
-    loop.Run();
-  }
-
-  // ash::ShellObserver:
-  void OnOverviewModeStarting() override { is_in_overview_mode_ = true; }
-  void OnOverviewModeEnded() override { is_in_overview_mode_ = false; }
-
- protected:
-  bool is_in_overview_mode_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AcceleratorInteractiveUITest);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-#if defined(OFFICIAL_BUILD)
-#define MAYBE_NonRepeatableNeedingWindowActions \
-  DISABLED_NonRepeatableNeedingWindowActions
-#define MAYBE_ChromeOsAccelerators DISABLED_ChromeOsAccelerators
-#define MAYBE_ToggleAppList DISABLED_ToggleAppList
-#else
-#define MAYBE_NonRepeatableNeedingWindowActions \
-  NonRepeatableNeedingWindowActions
-#define MAYBE_ChromeOsAccelerators ChromeOsAccelerators
-#define MAYBE_ToggleAppList ToggleAppList
-#endif  // defined(OFFICIAL_BUILD)
-
-// Tests a sample of the non-repeatable accelerators that need windows to be
-// enabled.
-TEST_F(AcceleratorInteractiveUITest, MAYBE_NonRepeatableNeedingWindowActions) {
-  // Create a bunch of windows to work with.
-  aura::Window* window_1 =
-      CreateTestWindowInShellWithBounds(gfx::Rect(0, 0, 100, 100));
-  aura::Window* window_2 =
-      CreateTestWindowInShellWithBounds(gfx::Rect(0, 0, 100, 100));
-  window_1->Show();
-  wm::ActivateWindow(window_1);
-  window_2->Show();
-  wm::ActivateWindow(window_2);
-
-  // Test TOGGLE_OVERVIEW.
-  EXPECT_FALSE(is_in_overview_mode_);
-  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, false, false, false);
-  EXPECT_TRUE(is_in_overview_mode_);
-  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, false, false, false);
-  EXPECT_FALSE(is_in_overview_mode_);
-
-  // Test CYCLE_FORWARD_MRU and CYCLE_BACKWARD_MRU.
-  wm::ActivateWindow(window_1);
-  EXPECT_TRUE(wm::IsActiveWindow(window_1));
-  EXPECT_FALSE(wm::IsActiveWindow(window_2));
-  SendKeyPressSync(ui::VKEY_TAB, false, false, true);  // CYCLE_FORWARD_MRU.
-  EXPECT_TRUE(wm::IsActiveWindow(window_2));
-  EXPECT_FALSE(wm::IsActiveWindow(window_1));
-  SendKeyPressSync(ui::VKEY_TAB, false, true, true);  // CYCLE_BACKWARD_MRU.
-  EXPECT_TRUE(wm::IsActiveWindow(window_1));
-  EXPECT_FALSE(wm::IsActiveWindow(window_2));
-
-  // Test TOGGLE_FULLSCREEN.
-  wm::WindowState* active_window_state = wm::GetActiveWindowState();
-  EXPECT_FALSE(active_window_state->IsFullscreen());
-  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP2, false, false, false);
-  EXPECT_TRUE(active_window_state->IsFullscreen());
-  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP2, false, false, false);
-  EXPECT_FALSE(active_window_state->IsFullscreen());
-}
-
-// Tests a sample of ChromeOS specific accelerators.
-TEST_F(AcceleratorInteractiveUITest, MAYBE_ChromeOsAccelerators) {
-  // Test TAKE_SCREENSHOT and TAKE_PARTIAL_SCREENSHOT.
-  TestScreenshotDelegate* screenshot_delegate = GetScreenshotDelegate();
-  screenshot_delegate->set_can_take_screenshot(true);
-  EXPECT_EQ(0, screenshot_delegate->handle_take_screenshot_count());
-  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, true, false, false);
-  EXPECT_EQ(1, screenshot_delegate->handle_take_screenshot_count());
-  SendKeyPressSync(ui::VKEY_SNAPSHOT, false, false, false);
-  EXPECT_EQ(2, screenshot_delegate->handle_take_screenshot_count());
-  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, true, true, false);
-  EXPECT_EQ(2, screenshot_delegate->handle_take_screenshot_count());
-  // Press ESC to go out of the partial screenshot mode.
-  SendKeyPressSync(ui::VKEY_ESCAPE, false, false, false);
-
-  // Test VOLUME_MUTE.
-  base::UserActionTester user_action_tester;
-  EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
-  SendKeyPressSync(ui::VKEY_VOLUME_MUTE, false, false, false);
-  EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
-  // Test VOLUME_DOWN.
-  EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
-  SendKeyPressSync(ui::VKEY_VOLUME_DOWN, false, false, false);
-  EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
-  // Test VOLUME_UP.
-  EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
-  SendKeyPressSync(ui::VKEY_VOLUME_UP, false, false, false);
-  EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
-
-  // Test TOGGLE_WIFI.
-  TestNetworkObserver network_observer;
-  Shell::Get()->system_tray_notifier()->AddNetworkObserver(&network_observer);
-
-  EXPECT_FALSE(network_observer.wifi_enabled_status());
-  SendKeyPressSync(ui::VKEY_WLAN, false, false, false);
-  EXPECT_TRUE(network_observer.wifi_enabled_status());
-  SendKeyPressSync(ui::VKEY_WLAN, false, false, false);
-  EXPECT_FALSE(network_observer.wifi_enabled_status());
-
-  Shell::Get()->system_tray_notifier()->RemoveNetworkObserver(
-      &network_observer);
-}
-
-// Tests the app list accelerator.
-TEST_F(AcceleratorInteractiveUITest, MAYBE_ToggleAppList) {
-  GetAppListTestHelper()->CheckVisibility(false);
-  SendKeyPressSync(ui::VKEY_LWIN, false, false, false);
-  base::RunLoop().RunUntilIdle();
-  GetAppListTestHelper()->CheckVisibility(true);
-  SendKeyPressSync(ui::VKEY_LWIN, false, false, false);
-  base::RunLoop().RunUntilIdle();
-  GetAppListTestHelper()->CheckVisibility(false);
-}
-
-}  // namespace ash
diff --git a/ash/accelerators/accelerator_unittest.cc b/ash/accelerators/accelerator_unittest.cc
index 8d71c775..9241056 100644
--- a/ash/accelerators/accelerator_unittest.cc
+++ b/ash/accelerators/accelerator_unittest.cc
@@ -1,22 +1,205 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// 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 "ui/base/accelerators/accelerator.h"
 #include "ash/accelerators/accelerator_controller.h"
+
+#include "ash/app_list/test/app_list_test_helper.h"
 #include "ash/shell.h"
+#include "ash/shell_observer.h"
+#include "ash/system/network/network_observer.h"
+#include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/ui_controls_factory_ash.h"
+#include "ash/test_screenshot_delegate.h"
+#include "ash/wm/window_state.h"
+#include "ash/wm/window_util.h"
+#include "base/run_loop.h"
+#include "base/test/metrics/user_action_tester.h"
+#include "chromeos/network/network_handler.h"
 #include "services/ws/public/mojom/window_tree_constants.mojom.h"
 #include "services/ws/test_window_tree_client.h"
 #include "ui/aura/window.h"
+#include "ui/base/accelerators/accelerator.h"
 #include "ui/base/accelerators/test_accelerator_target.h"
+#include "ui/base/test/ui_controls.h"
 #include "ui/events/event.h"
 #include "ui/events/test/event_generator.h"
 
 namespace ash {
-namespace accelerators {
 
-using AcceleratorTest = AshTestBase;
+namespace {
+
+// A network observer to watch for the toggle wifi events.
+class TestNetworkObserver : public NetworkObserver {
+ public:
+  TestNetworkObserver() = default;
+  ~TestNetworkObserver() override = default;
+
+  // ash::NetworkObserver:
+  void RequestToggleWifi() override {
+    wifi_enabled_status_ = !wifi_enabled_status_;
+  }
+
+  bool wifi_enabled_status() const { return wifi_enabled_status_; }
+
+ private:
+  bool wifi_enabled_status_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(TestNetworkObserver);
+};
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+// This is intended to test few samples from each category of accelerators to
+// make sure they work properly. The test is done as an interactive ui test
+// using ui_controls::Send*() functions.
+// This is to catch any future regressions (crbug.com/469235).
+class AcceleratorTest : public AshTestBase, public ShellObserver {
+ public:
+  AcceleratorTest() : is_in_overview_mode_(false) {}
+
+  void SetUp() override {
+    ui_controls::InstallUIControlsAura(test::CreateAshUIControls());
+
+    AshTestBase::SetUp();
+
+    Shell::Get()->AddShellObserver(this);
+
+    chromeos::NetworkHandler::Initialize();
+  }
+
+  void TearDown() override {
+    chromeos::NetworkHandler::Shutdown();
+
+    Shell::Get()->RemoveShellObserver(this);
+
+    AshTestBase::TearDown();
+
+    ui_controls::InstallUIControlsAura(nullptr);
+  }
+
+  // Sends a key press event and waits synchronously until it's completely
+  // processed.
+  void SendKeyPressSync(ui::KeyboardCode key,
+                        bool control,
+                        bool shift,
+                        bool alt) {
+    base::RunLoop loop;
+    ui_controls::SendKeyPressNotifyWhenDone(Shell::GetPrimaryRootWindow(), key,
+                                            control, shift, alt, false,
+                                            loop.QuitClosure());
+    loop.Run();
+  }
+
+  // ash::ShellObserver:
+  void OnOverviewModeStarting() override { is_in_overview_mode_ = true; }
+  void OnOverviewModeEnded() override { is_in_overview_mode_ = false; }
+
+ protected:
+  bool is_in_overview_mode_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AcceleratorTest);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Tests a sample of accelerators.
+TEST_F(AcceleratorTest, Basic) {
+  // Test TAKE_SCREENSHOT and TAKE_PARTIAL_SCREENSHOT.
+  TestScreenshotDelegate* screenshot_delegate = GetScreenshotDelegate();
+  screenshot_delegate->set_can_take_screenshot(true);
+  EXPECT_EQ(0, screenshot_delegate->handle_take_screenshot_count());
+  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, true, false, false);
+  EXPECT_EQ(1, screenshot_delegate->handle_take_screenshot_count());
+  SendKeyPressSync(ui::VKEY_SNAPSHOT, false, false, false);
+  EXPECT_EQ(2, screenshot_delegate->handle_take_screenshot_count());
+  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, true, true, false);
+  EXPECT_EQ(2, screenshot_delegate->handle_take_screenshot_count());
+  // Press ESC to go out of the partial screenshot mode.
+  SendKeyPressSync(ui::VKEY_ESCAPE, false, false, false);
+
+  // Test VOLUME_MUTE.
+  base::UserActionTester user_action_tester;
+  EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
+  SendKeyPressSync(ui::VKEY_VOLUME_MUTE, false, false, false);
+  EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
+  // Test VOLUME_DOWN.
+  EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
+  SendKeyPressSync(ui::VKEY_VOLUME_DOWN, false, false, false);
+  EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
+  // Test VOLUME_UP.
+  EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
+  SendKeyPressSync(ui::VKEY_VOLUME_UP, false, false, false);
+  EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
+
+  // Test TOGGLE_WIFI.
+  TestNetworkObserver network_observer;
+  Shell::Get()->system_tray_notifier()->AddNetworkObserver(&network_observer);
+
+  EXPECT_FALSE(network_observer.wifi_enabled_status());
+  SendKeyPressSync(ui::VKEY_WLAN, false, false, false);
+  EXPECT_TRUE(network_observer.wifi_enabled_status());
+  SendKeyPressSync(ui::VKEY_WLAN, false, false, false);
+  EXPECT_FALSE(network_observer.wifi_enabled_status());
+
+  Shell::Get()->system_tray_notifier()->RemoveNetworkObserver(
+      &network_observer);
+}
+
+// Tests a sample of the non-repeatable accelerators that need windows to be
+// enabled.
+TEST_F(AcceleratorTest, NonRepeatableNeedingWindowActions) {
+  // Create a bunch of windows to work with.
+  aura::Window* window_1 =
+      CreateTestWindowInShellWithBounds(gfx::Rect(0, 0, 100, 100));
+  aura::Window* window_2 =
+      CreateTestWindowInShellWithBounds(gfx::Rect(0, 0, 100, 100));
+  window_1->Show();
+  wm::ActivateWindow(window_1);
+  window_2->Show();
+  wm::ActivateWindow(window_2);
+
+  // Test TOGGLE_OVERVIEW.
+  EXPECT_FALSE(is_in_overview_mode_);
+  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, false, false, false);
+  EXPECT_TRUE(is_in_overview_mode_);
+  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP1, false, false, false);
+  EXPECT_FALSE(is_in_overview_mode_);
+
+  // Test CYCLE_FORWARD_MRU and CYCLE_BACKWARD_MRU.
+  wm::ActivateWindow(window_1);
+  EXPECT_TRUE(wm::IsActiveWindow(window_1));
+  EXPECT_FALSE(wm::IsActiveWindow(window_2));
+  SendKeyPressSync(ui::VKEY_TAB, false, false, true);  // CYCLE_FORWARD_MRU.
+  EXPECT_TRUE(wm::IsActiveWindow(window_2));
+  EXPECT_FALSE(wm::IsActiveWindow(window_1));
+  SendKeyPressSync(ui::VKEY_TAB, false, true, true);  // CYCLE_BACKWARD_MRU.
+  EXPECT_TRUE(wm::IsActiveWindow(window_1));
+  EXPECT_FALSE(wm::IsActiveWindow(window_2));
+
+  // Test TOGGLE_FULLSCREEN.
+  wm::WindowState* active_window_state = wm::GetActiveWindowState();
+  EXPECT_FALSE(active_window_state->IsFullscreen());
+  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP2, false, false, false);
+  EXPECT_TRUE(active_window_state->IsFullscreen());
+  SendKeyPressSync(ui::VKEY_MEDIA_LAUNCH_APP2, false, false, false);
+  EXPECT_FALSE(active_window_state->IsFullscreen());
+}
+
+// Tests the app list accelerator.
+TEST_F(AcceleratorTest, ToggleAppList) {
+  GetAppListTestHelper()->CheckVisibility(false);
+  SendKeyPressSync(ui::VKEY_LWIN, false, false, false);
+  base::RunLoop().RunUntilIdle();
+  GetAppListTestHelper()->CheckVisibility(true);
+  SendKeyPressSync(ui::VKEY_LWIN, false, false, false);
+  base::RunLoop().RunUntilIdle();
+  GetAppListTestHelper()->CheckVisibility(false);
+}
 
 // This is meant to exercise an end to end test of an accelerator that happens
 // *after* the remote client is given a chance to handle it.
@@ -45,5 +228,4 @@
   EXPECT_EQ(1, test_target.accelerator_count());
 }
 
-}  // namespace accelerators
 }  // namespace ash
diff --git a/ash/app_list/app_list_interactive_uitest.cc b/ash/app_list/app_list_unittest.cc
similarity index 77%
rename from ash/app_list/app_list_interactive_uitest.cc
rename to ash/app_list/app_list_unittest.cc
index bb3d90d..d4b26a7 100644
--- a/ash/app_list/app_list_interactive_uitest.cc
+++ b/ash/app_list/app_list_unittest.cc
@@ -13,30 +13,31 @@
 #include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
-#include "ash/test/ash_interactive_ui_test_base.h"
+#include "ash/test/ash_test_base.h"
 #include "ui/aura/window.h"
 #include "ui/events/test/event_generator.h"
 
-using AppListTest = ash::AshInteractiveUITestBase;
+namespace ash {
+
+using AppListTest = AshTestBase;
 
 // An integration test to toggle the app list by pressing the shelf button.
 TEST_F(AppListTest, PressAppListButtonToShowAndDismiss) {
-  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
-  ash::Shelf* shelf = ash::Shelf::ForWindow(root_window);
-  ash::ShelfWidget* shelf_widget = shelf->shelf_widget();
-  ash::ShelfView* shelf_view = shelf->GetShelfViewForTesting();
-  ash::ShelfViewTestAPI(shelf_view).RunMessageLoopUntilAnimationsDone();
-  ash::AppListButton* app_list_button = shelf_widget->GetAppListButton();
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
+  Shelf* shelf = Shelf::ForWindow(root_window);
+  ShelfWidget* shelf_widget = shelf->shelf_widget();
+  ShelfView* shelf_view = shelf->GetShelfViewForTesting();
+  ShelfViewTestAPI(shelf_view).RunMessageLoopUntilAnimationsDone();
+  AppListButton* app_list_button = shelf_widget->GetAppListButton();
   // Ensure animations progressed to give the app list button a non-empty size.
   ASSERT_GT(app_list_button->GetBoundsInScreen().height(), 0);
 
   aura::Window* app_list_container =
-      root_window->GetChildById(ash::kShellWindowId_AppListContainer);
+      root_window->GetChildById(kShellWindowId_AppListContainer);
   ui::test::EventGenerator generator(root_window);
 
   // Click the app list button to show the app list.
-  ash::Shell* shell = ash::Shell::Get();
-  auto* controller = shell->app_list_controller();
+  auto* controller = Shell::Get()->app_list_controller();
   auto* presenter = controller->presenter();
   EXPECT_FALSE(controller->GetTargetVisibility());
   EXPECT_FALSE(presenter->GetTargetVisibility());
@@ -63,3 +64,5 @@
   EXPECT_EQ(1u, app_list_container->children().size());
   EXPECT_FALSE(app_list_button->is_showing_app_list());
 }
+
+}  // namespace ash
diff --git a/ash/app_list/home_launcher_gesture_handler.cc b/ash/app_list/home_launcher_gesture_handler.cc
index ff5151d7..80b42fd 100644
--- a/ash/app_list/home_launcher_gesture_handler.cc
+++ b/ash/app_list/home_launcher_gesture_handler.cc
@@ -475,16 +475,20 @@
     window2_->ResetOpacityAndTransform();
 
   if (is_final_state_show) {
-    wm::HideAndMinimizeWithoutAnimation(GetWindow1());
+    std::vector<aura::Window*> windows_to_hide_minimize;
+    windows_to_hide_minimize.push_back(GetWindow1());
 
     if (window2_)
-      wm::HideAndMinimizeWithoutAnimation(GetWindow2());
+      windows_to_hide_minimize.push_back(GetWindow2());
 
     // Minimize the hidden windows so they can be used normally with alt+tab
     // and overview. Minimize in reverse order to preserve mru ordering.
-    std::reverse(hidden_windows_.begin(), hidden_windows_.end());
-    for (auto* window : hidden_windows_)
-      wm::HideAndMinimizeWithoutAnimation(window);
+    windows_to_hide_minimize.resize(windows_to_hide_minimize.size() +
+                                    hidden_windows_.size());
+    std::copy(hidden_windows_.rbegin(), hidden_windows_.rend(),
+              windows_to_hide_minimize.end() - hidden_windows_.size());
+    wm::HideAndMaybeMinimizeWithoutAnimation(windows_to_hide_minimize,
+                                             /*minimize=*/true);
   } else {
     // Reshow all windows previously hidden.
     for (auto* window : hidden_windows_) {
@@ -825,9 +829,10 @@
       if (window->IsVisible()) {
         hidden_windows_.push_back(window);
         window->AddObserver(this);
-        wm::HideWithoutAnimation(window);
       }
     }
+    wm::HideAndMaybeMinimizeWithoutAnimation(hidden_windows_,
+                                             /*minimize=*/false);
   }
 
   return true;
diff --git a/ash/assistant/ui/BUILD.gn b/ash/assistant/ui/BUILD.gn
index f67666f1..1a707a0 100644
--- a/ash/assistant/ui/BUILD.gn
+++ b/ash/assistant/ui/BUILD.gn
@@ -38,6 +38,9 @@
     "assistant_main_view.h",
     "assistant_mini_view.cc",
     "assistant_mini_view.h",
+    "assistant_notification_overlay.cc",
+    "assistant_notification_overlay.h",
+    "assistant_overlay.h",
     "assistant_view_delegate.h",
     "assistant_web_view.cc",
     "assistant_web_view.h",
@@ -87,6 +90,7 @@
     "//ash/strings",
     "//base",
     "//chromeos/assistant:buildflags",
+    "//chromeos/services/assistant/public:feature_flags",
     "//chromeos/services/assistant/public/mojom",
     "//services/content/public/cpp",
     "//ui/aura",
diff --git a/ash/assistant/ui/DEPS b/ash/assistant/ui/DEPS
index 21c4373c..d93a1786 100644
--- a/ash/assistant/ui/DEPS
+++ b/ash/assistant/ui/DEPS
@@ -11,7 +11,7 @@
   "+build/buildflag.h",
   "+cc/paint",
   "+chromeos/assistant",
-  "+chromeos/services/assistant/public/mojom",
+  "+chromeos/services/assistant/public",
   "+mojo/public/cpp",
   "+services/content/public",
   "+third_party/skia/include/core",
diff --git a/ash/assistant/ui/assistant_container_view.cc b/ash/assistant/ui/assistant_container_view.cc
index 9e29f7b9..f2782a8 100644
--- a/ash/assistant/ui/assistant_container_view.cc
+++ b/ash/assistant/ui/assistant_container_view.cc
@@ -5,11 +5,14 @@
 #include "ash/assistant/ui/assistant_container_view.h"
 
 #include <algorithm>
+#include <set>
+#include <vector>
 
 #include "ash/assistant/model/assistant_ui_model.h"
 #include "ash/assistant/ui/assistant_container_view_animator.h"
 #include "ash/assistant/ui/assistant_main_view.h"
 #include "ash/assistant/ui/assistant_mini_view.h"
+#include "ash/assistant/ui/assistant_overlay.h"
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
 #include "ash/assistant/ui/assistant_web_view.h"
@@ -26,6 +29,7 @@
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/layout/layout_manager.h"
 #include "ui/views/view.h"
+#include "ui/views/window/dialog_client_view.h"
 
 namespace ash {
 
@@ -37,6 +41,76 @@
 // Window properties.
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kOnlyAllowMouseClickEvents, false);
 
+// AssistantContainerClientView ------------------------------------------------
+
+// AssistantContainerClientView is the client view for AssistantContainerView
+// which provides support for adding overlays to the Assistant view hierarchy.
+// Because overlays are added to the AssistantContainerView client view, they
+// paint to a higher level in the layer tree than do direct children of
+// AssistantContainerView. This allows AssistantMainView, for example, to
+// pseudo-parent overlays that draw over top of Assistant cards.
+class AssistantContainerClientView : public views::DialogClientView,
+                                     public views::ViewObserver {
+ public:
+  AssistantContainerClientView(views::Widget* widget,
+                               views::View* contents_view)
+      : views::DialogClientView(widget, contents_view) {}
+
+  ~AssistantContainerClientView() override = default;
+
+  // views::DialogClientView:
+  const char* GetClassName() const override {
+    return "AssistantContainerClientView";
+  }
+
+  void Layout() override {
+    views::DialogClientView::Layout();
+    for (AssistantOverlay* overlay : overlays_) {
+      AssistantOverlay::LayoutParams layout_params = overlay->GetLayoutParams();
+      gfx::Size preferred_size = overlay->GetPreferredSize();
+
+      int left = layout_params.margins.left();
+      int top = layout_params.margins.top();
+      int width = preferred_size.width();
+      int height = preferred_size.height();
+
+      // Gravity::kBottom.
+      using Gravity = AssistantOverlay::LayoutParams::Gravity;
+      if ((layout_params.gravity & Gravity::kBottom) != 0)
+        top = this->height() - height - layout_params.margins.bottom();
+
+      // Gravity::kCenterHorizontal.
+      if ((layout_params.gravity & Gravity::kCenterHorizontal) != 0)
+        left = (this->width() - width) / 2 - layout_params.margins.left();
+
+      overlay->SetBounds(left, top, width, height);
+    }
+  }
+
+  // views::ViewObserver:
+  void OnViewIsDeleting(views::View* view) override {
+    view->RemoveObserver(this);
+
+    // We need to keep |overlays_| in sync with the view hierarchy.
+    auto it = overlays_.find(static_cast<AssistantOverlay*>(view));
+    DCHECK(it != overlays_.end());
+    overlays_.erase(it);
+  }
+
+  void AddOverlays(std::vector<AssistantOverlay*> overlays) {
+    for (AssistantOverlay* overlay : overlays) {
+      overlays_.insert(overlay);
+      overlay->AddObserver(this);
+      AddChildView(overlay);
+    }
+  }
+
+ private:
+  std::set<AssistantOverlay*> overlays_;
+
+  DISALLOW_COPY_AND_ASSIGN(AssistantContainerClientView);
+};
+
 // AssistantContainerEventTargeter ---------------------------------------------
 
 class AssistantContainerEventTargeter : public aura::WindowTargeter {
@@ -251,6 +325,14 @@
   params->keep_on_top = true;
 }
 
+views::ClientView* AssistantContainerView::CreateClientView(
+    views::Widget* widget) {
+  AssistantContainerClientView* client_view =
+      new AssistantContainerClientView(widget, GetContentsView());
+  client_view->AddOverlays(assistant_main_view_->GetOverlays());
+  return client_view;
+}
+
 void AssistantContainerView::Init() {
   SetLayoutManager(std::make_unique<AssistantContainerLayout>(delegate_));
 
diff --git a/ash/assistant/ui/assistant_container_view.h b/ash/assistant/ui/assistant_container_view.h
index 20cedc1d..dc00d04 100644
--- a/ash/assistant/ui/assistant_container_view.h
+++ b/ash/assistant/ui/assistant_container_view.h
@@ -50,6 +50,7 @@
   void SizeToContents() override;
   void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
                                 views::Widget* widget) const override;
+  views::ClientView* CreateClientView(views::Widget* widget) override;
   void Init() override;
   void RequestFocus() override;
 
diff --git a/ash/assistant/ui/assistant_main_view.cc b/ash/assistant/ui/assistant_main_view.cc
index c5abdaa..4b0baa7d 100644
--- a/ash/assistant/ui/assistant_main_view.cc
+++ b/ash/assistant/ui/assistant_main_view.cc
@@ -5,10 +5,11 @@
 #include "ash/assistant/ui/assistant_main_view.h"
 
 #include <algorithm>
-#include <memory>
+#include <utility>
 
 #include "ash/assistant/model/assistant_interaction_model.h"
 #include "ash/assistant/model/assistant_ui_model.h"
+#include "ash/assistant/ui/assistant_notification_overlay.h"
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
 #include "ash/assistant/ui/caption_bar.h"
@@ -17,6 +18,7 @@
 #include "ash/assistant/util/animation_util.h"
 #include "ash/assistant/util/assistant_util.h"
 #include "base/time/time.h"
+#include "chromeos/services/assistant/public/features.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer_animation_element.h"
 #include "ui/compositor/layer_animator.h"
@@ -95,6 +97,14 @@
   min_height_dip_ = std::max(min_height_dip_, height());
 }
 
+void AssistantMainView::VisibilityChanged(views::View* starting_from,
+                                          bool visible) {
+  // Overlays behave like children of AssistantMainView so they should only be
+  // visible while AssistantMainView is visible.
+  for (std::unique_ptr<AssistantOverlay>& overlay : overlays_)
+    overlay->SetVisible(visible);
+}
+
 void AssistantMainView::ChildPreferredSizeChanged(views::View* child) {
   PreferredSizeChanged();
 
@@ -118,6 +128,13 @@
   return dialog_plate_->FindFirstFocusableView();
 }
 
+std::vector<AssistantOverlay*> AssistantMainView::GetOverlays() {
+  std::vector<AssistantOverlay*> overlays;
+  for (std::unique_ptr<AssistantOverlay>& overlay : overlays_)
+    overlays.push_back(overlay.get());
+  return overlays;
+}
+
 void AssistantMainView::InitLayout() {
   views::BoxLayout* layout_manager =
       SetLayoutManager(std::make_unique<views::BoxLayout>(
@@ -147,6 +164,14 @@
   dialog_plate_->layer()->SetFillsBoundsOpaquely(false);
 
   AddChildView(dialog_plate_);
+
+  // Notification overlay.
+  if (chromeos::assistant::features::IsInAssistantNotificationsEnabled()) {
+    auto notification_overlay =
+        std::make_unique<AssistantNotificationOverlay>();
+    notification_overlay->set_owned_by_client();
+    overlays_.push_back(std::move(notification_overlay));
+  }
 }
 
 void AssistantMainView::OnUiVisibilityChanged(
diff --git a/ash/assistant/ui/assistant_main_view.h b/ash/assistant/ui/assistant_main_view.h
index 623339e..c3426c0 100644
--- a/ash/assistant/ui/assistant_main_view.h
+++ b/ash/assistant/ui/assistant_main_view.h
@@ -5,6 +5,9 @@
 #ifndef ASH_ASSISTANT_UI_ASSISTANT_MAIN_VIEW_H_
 #define ASH_ASSISTANT_UI_ASSISTANT_MAIN_VIEW_H_
 
+#include <memory>
+#include <vector>
+
 #include "ash/assistant/model/assistant_ui_model_observer.h"
 #include "base/component_export.h"
 #include "base/macros.h"
@@ -13,6 +16,7 @@
 namespace ash {
 
 class AssistantMainStage;
+class AssistantOverlay;
 class AssistantViewDelegate;
 class CaptionBar;
 class DialogPlate;
@@ -31,6 +35,7 @@
   void ChildPreferredSizeChanged(views::View* child) override;
   void ChildVisibilityChanged(views::View* child) override;
   void OnBoundsChanged(const gfx::Rect& prev_bounds) override;
+  void VisibilityChanged(views::View* starting_from, bool visible) override;
   void RequestFocus() override;
 
   // AssistantUiModelObserver:
@@ -43,6 +48,9 @@
   // Returns the first focusable view or nullptr to defer to views::FocusSearch.
   views::View* FindFirstFocusableView();
 
+  // Returns the overlays that behave as pseudo-children of AssistantMainView.
+  std::vector<AssistantOverlay*> GetOverlays();
+
  private:
   void InitLayout();
 
@@ -52,6 +60,11 @@
   DialogPlate* dialog_plate_;                       // Owned by view hierarchy.
   AssistantMainStage* main_stage_;                  // Owned by view hierarchy.
 
+  // Overlays behave as pseudo-children of AssistantMainView. They paint to a
+  // higher lever in the layer tree so they are visible over the top of
+  // Assistant cards.
+  std::vector<std::unique_ptr<AssistantOverlay>> overlays_;
+
   int min_height_dip_;
 
   DISALLOW_COPY_AND_ASSIGN(AssistantMainView);
diff --git a/ash/assistant/ui/assistant_notification_overlay.cc b/ash/assistant/ui/assistant_notification_overlay.cc
new file mode 100644
index 0000000..6f8133f
--- /dev/null
+++ b/ash/assistant/ui/assistant_notification_overlay.cc
@@ -0,0 +1,57 @@
+// 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 "ash/assistant/ui/assistant_notification_overlay.h"
+
+#include "ui/gfx/canvas.h"
+
+namespace ash {
+
+namespace {
+
+// Appearance.
+constexpr int kMarginBottomDip = 64;
+constexpr int kPreferredHeightDip = 60;
+constexpr int kPreferredWidthDip = 576;
+
+}  // namespace
+
+AssistantNotificationOverlay::AssistantNotificationOverlay() {
+  InitLayout();
+}
+
+AssistantNotificationOverlay::~AssistantNotificationOverlay() = default;
+
+const char* AssistantNotificationOverlay::GetClassName() const {
+  return "AssistantNotificationOverlay";
+}
+
+gfx::Size AssistantNotificationOverlay::CalculatePreferredSize() const {
+  return gfx::Size(kPreferredWidthDip, GetHeightForWidth(kPreferredWidthDip));
+}
+
+int AssistantNotificationOverlay::GetHeightForWidth(int width) const {
+  return kPreferredHeightDip;
+}
+
+AssistantOverlay::LayoutParams AssistantNotificationOverlay::GetLayoutParams()
+    const {
+  using Gravity = AssistantOverlay::LayoutParams::Gravity;
+  AssistantOverlay::LayoutParams layout_params;
+  layout_params.gravity = Gravity::kBottom | Gravity::kCenterHorizontal;
+  layout_params.margins = gfx::Insets(0, 0, kMarginBottomDip, 0);
+  return layout_params;
+}
+
+// TODO(dmblack): Remove when notification views have been implemented.
+void AssistantNotificationOverlay::OnPaintBackground(gfx::Canvas* canvas) {
+  canvas->DrawColor(0x20000000);
+}
+
+void AssistantNotificationOverlay::InitLayout() {
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+}
+
+};  // namespace ash
diff --git a/ash/assistant/ui/assistant_notification_overlay.h b/ash/assistant/ui/assistant_notification_overlay.h
new file mode 100644
index 0000000..1f6a1037
--- /dev/null
+++ b/ash/assistant/ui/assistant_notification_overlay.h
@@ -0,0 +1,37 @@
+// 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 ASH_ASSISTANT_UI_ASSISTANT_NOTIFICATION_OVERLAY_H_
+#define ASH_ASSISTANT_UI_ASSISTANT_NOTIFICATION_OVERLAY_H_
+
+#include "ash/assistant/ui/assistant_overlay.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+
+namespace ash {
+
+// AssistantNotificationOverlay is a pseudo-child of AssistantMainView which is
+// responsible for parenting in-Assistant notifications.
+class COMPONENT_EXPORT(ASSISTANT_UI) AssistantNotificationOverlay
+    : public AssistantOverlay {
+ public:
+  AssistantNotificationOverlay();
+  ~AssistantNotificationOverlay() override;
+
+  // AssistantOverlay:
+  const char* GetClassName() const override;
+  gfx::Size CalculatePreferredSize() const override;
+  int GetHeightForWidth(int width) const override;
+  LayoutParams GetLayoutParams() const override;
+  void OnPaintBackground(gfx::Canvas* canvas) override;
+
+ private:
+  void InitLayout();
+
+  DISALLOW_COPY_AND_ASSIGN(AssistantNotificationOverlay);
+};
+
+}  // namespace ash
+
+#endif  // ASH_ASSISTANT_UI_ASSISTANT_NOTIFICATION_OVERLAY_H_
diff --git a/ash/assistant/ui/assistant_overlay.h b/ash/assistant/ui/assistant_overlay.h
new file mode 100644
index 0000000..b647312
--- /dev/null
+++ b/ash/assistant/ui/assistant_overlay.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 ASH_ASSISTANT_UI_ASSISTANT_OVERLAY_H_
+#define ASH_ASSISTANT_UI_ASSISTANT_OVERLAY_H_
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "ui/views/view.h"
+
+namespace ash {
+
+// AssistantOverlays are children of AssistantContainerView's client view that
+// behave as pseudo-children of AssistantContainerView's own child views. This
+// allows children of AssistantContainerView to pseudo-parent views that paint
+// to a layer that is higher up in the layer tree than themselves. In the case
+// of AssistantMainView, an overlay is used to parent in-Assistant notification
+// views that need to be drawn over top of Assistant cards.
+class COMPONENT_EXPORT(ASSISTANT_UI) AssistantOverlay : public views::View {
+ public:
+  // Defines parameters for how an overlay should be laid out.
+  struct LayoutParams {
+    enum Gravity {
+      kUnspecified = 0,
+      kBottom = 1 << 0,
+      kCenterHorizontal = 1 << 1,
+    };
+    int gravity = Gravity::kUnspecified;
+    gfx::Insets margins;
+  };
+
+  AssistantOverlay() = default;
+  ~AssistantOverlay() override = default;
+
+  // Returns parameters for how an overlay should be laid out.
+  virtual LayoutParams GetLayoutParams() const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AssistantOverlay);
+};
+
+}  // namespace ash
+
+#endif  // ASH_ASSISTANT_UI_ASSISTANT_OVERLAY_H_
diff --git a/ash/drag_drop/drag_drop_interactive_uitest.cc b/ash/drag_drop/drag_drop_unittest.cc
similarity index 93%
rename from ash/drag_drop/drag_drop_interactive_uitest.cc
rename to ash/drag_drop/drag_drop_unittest.cc
index 6871093..e668d0b 100644
--- a/ash/drag_drop/drag_drop_interactive_uitest.cc
+++ b/ash/drag_drop/drag_drop_unittest.cc
@@ -5,13 +5,15 @@
 #include "ash/drag_drop/drag_drop_controller.h"
 
 #include "ash/shell.h"
-#include "ash/test/ash_interactive_ui_test_base.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test/ui_controls_factory_ash.h"
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/test/ui_controls.h"
+#include "ui/base/test/ui_controls_aura.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
@@ -111,11 +113,13 @@
 
 }  // namespace
 
-using DragDropTest = AshInteractiveUITestBase;
+using DragDropTest = AshTestBase;
 
 // Test if the mouse gets moved properly to another display
 // during drag & drop operation.
 TEST_F(DragDropTest, DragDropAcrossMultiDisplay) {
+  ui_controls::InstallUIControlsAura(test::CreateAshUIControls());
+
   UpdateDisplay("400x400,400x400");
   aura::Window::Windows root_windows = Shell::Get()->GetAllRootWindows();
   views::View* draggable_view = new DraggableView();
@@ -142,6 +146,8 @@
 
   source->Close();
   target->Close();
+
+  ui_controls::InstallUIControlsAura(nullptr);
 }
 
 }  // namespace ash
diff --git a/ash/test/ash_interactive_ui_test_base.cc b/ash/test/ash_interactive_ui_test_base.cc
deleted file mode 100644
index db319388..0000000
--- a/ash/test/ash_interactive_ui_test_base.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/test/ash_interactive_ui_test_base.h"
-
-#include "ash/test/ui_controls_factory_ash.h"
-#include "base/lazy_instance.h"
-#include "base/path_service.h"
-#include "mojo/core/embedder/embedder.h"
-#include "ui/aura/env.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/test/ui_controls_aura.h"
-#include "ui/base/ui_base_features.h"
-#include "ui/base/ui_base_paths.h"
-#include "ui/gl/test/gl_surface_test_support.h"
-
-namespace ash {
-
-namespace {
-
-class MojoInitializer {
- public:
-  MojoInitializer() { mojo::core::Init(); }
-};
-
-base::LazyInstance<MojoInitializer>::Leaky mojo_initializer;
-
-// Initialize mojo once per process.
-void InitializeMojo() {
-  mojo_initializer.Get();
-}
-
-}  // namespace
-
-AshInteractiveUITestBase::AshInteractiveUITestBase() = default;
-
-AshInteractiveUITestBase::~AshInteractiveUITestBase() = default;
-
-void AshInteractiveUITestBase::SetUp() {
-  InitializeMojo();
-
-  gl::GLSurfaceTestSupport::InitializeOneOff();
-
-  ui::RegisterPathProvider();
-  ui::ResourceBundle::InitSharedInstanceWithLocale(
-      "en-US", NULL, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
-  base::FilePath resources_pack_path;
-  base::PathService::Get(base::DIR_MODULE, &resources_pack_path);
-  resources_pack_path =
-      resources_pack_path.Append(FILE_PATH_LITERAL("resources.pak"));
-  ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
-      resources_pack_path, ui::SCALE_FACTOR_NONE);
-  env_ = aura::Env::CreateInstance(features::IsSingleProcessMash()
-                                       ? aura::Env::Mode::MUS
-                                       : aura::Env::Mode::LOCAL);
-  ui_controls::InstallUIControlsAura(test::CreateAshUIControls());
-
-  AshTestBase::SetUp();
-}
-
-void AshInteractiveUITestBase::TearDown() {
-  AshTestBase::TearDown();
-  env_.reset();
-}
-
-}  // namespace ash
diff --git a/ash/test/ash_interactive_ui_test_base.h b/ash/test/ash_interactive_ui_test_base.h
deleted file mode 100644
index 7e5b0a4..0000000
--- a/ash/test/ash_interactive_ui_test_base.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_TEST_ASH_INTERACTIVE_UI_TEST_BASE_H_
-#define ASH_TEST_ASH_INTERACTIVE_UI_TEST_BASE_H_
-
-#include <memory>
-#include <string>
-
-#include "ash/test/ash_test_base.h"
-#include "base/macros.h"
-
-namespace aura {
-class Env;
-}
-
-namespace ash {
-
-class AshInteractiveUITestBase : public AshTestBase {
- public:
-  AshInteractiveUITestBase();
-  ~AshInteractiveUITestBase() override;
-
- protected:
-  // testing::Test:
-  void SetUp() override;
-  void TearDown() override;
-
- private:
-  std::unique_ptr<aura::Env> env_;
-
-  DISALLOW_COPY_AND_ASSIGN(AshInteractiveUITestBase);
-};
-
-}  // namespace ash
-
-#endif  // ASH_TEST_ASH_INTERACTIVE_UI_TEST_BASE_H_
diff --git a/ash/wm/native_cursor_manager_ash_interactive_uitest.cc b/ash/wm/native_cursor_manager_ash_interactive_uitest.cc
deleted file mode 100644
index 3b96204..0000000
--- a/ash/wm/native_cursor_manager_ash_interactive_uitest.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/wm/native_cursor_manager_ash.h"
-
-#include "ash/shell.h"
-#include "ash/test/ash_interactive_ui_test_base.h"
-#include "ash/wm/cursor_manager_test_api.h"
-#include "base/run_loop.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/test/ui_controls.h"
-#include "ui/display/manager/display_manager.h"
-#include "ui/display/manager/managed_display_info.h"
-
-namespace ash {
-
-using NativeCursorManagerAshTest = AshInteractiveUITestBase;
-
-namespace {
-
-display::ManagedDisplayInfo CreateDisplayInfo(int64_t id,
-                                              const gfx::Rect& bounds,
-                                              float device_scale_factor) {
-  display::ManagedDisplayInfo info(id, "", false);
-  info.SetBounds(bounds);
-  info.set_device_scale_factor(device_scale_factor);
-  return info;
-}
-
-void MoveMouseSync(aura::Window* window, int x, int y) {
-  // Send and wait for a key event to make sure that mouse
-  // events are fully processed.
-  base::RunLoop loop;
-  ui_controls::SendKeyPressNotifyWhenDone(window, ui::VKEY_SPACE, false, false,
-                                          false, false, loop.QuitClosure());
-  loop.Run();
-}
-
-}  // namespace
-
-// Disabled on non-X11 before X11 was deprecated.
-TEST_F(NativeCursorManagerAshTest, DISABLED_CursorChangeOnEnterNotify) {
-  ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
-  CursorManagerTestApi test_api(cursor_manager);
-
-  display::ManagedDisplayInfo display_info1 =
-      CreateDisplayInfo(10, gfx::Rect(0, 0, 500, 300), 1.0f);
-  display::ManagedDisplayInfo display_info2 =
-      CreateDisplayInfo(20, gfx::Rect(500, 0, 500, 300), 2.0f);
-  std::vector<display::ManagedDisplayInfo> display_info_list;
-  display_info_list.push_back(display_info1);
-  display_info_list.push_back(display_info2);
-  display_manager()->OnNativeDisplaysChanged(display_info_list);
-
-  MoveMouseSync(Shell::GetAllRootWindows()[0], 10, 10);
-  EXPECT_EQ(1.0f, test_api.GetCurrentCursor().device_scale_factor());
-
-  MoveMouseSync(Shell::GetAllRootWindows()[0], 600, 10);
-  EXPECT_EQ(2.0f, test_api.GetCurrentCursor().device_scale_factor());
-}
-
-}  // namespace ash
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc
index 65cf63f..4e361502 100644
--- a/ash/wm/overview/overview_controller.cc
+++ b/ash/wm/overview/overview_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/wm/overview/overview_controller.h"
 
+#include <algorithm>
 #include <vector>
 
 #include "ash/app_list/app_list_controller_impl.h"
@@ -333,11 +334,15 @@
       // those widgets will be slid out of overview. Otherwise,
       // HomeLauncherGestureHandler will handle sliding the windows out and when
       // this function is called, we do not need to create minimized widgets.
-      for (aura::Window* window : windows) {
-        if (wm::GetWindowState(window)->IsMinimized())
-          continue;
-        wm::HideAndMinimizeWithoutAnimation(window);
-      }
+      std::vector<aura::Window*> windows_to_hide_minimize(windows.size());
+      auto it = std::copy_if(
+          windows.begin(), windows.end(), windows_to_hide_minimize.begin(),
+          [](aura::Window* window) {
+            return !wm::GetWindowState(window)->IsMinimized();
+          });
+      windows_to_hide_minimize.resize(
+          std::distance(windows_to_hide_minimize.begin(), it));
+      wm::HideAndMaybeMinimizeWithoutAnimation(windows_to_hide_minimize, true);
     }
 
     OnSelectionEnded();
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index 5c14180..359fa181 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -312,21 +312,28 @@
   }
 }
 
-void HideAndMinimizeWithoutAnimation(aura::Window* window) {
-  // Disable the animations using |disable|. However, doing so will skip
-  // detaching and recreating layers that animating does which has memory
-  // implications, so use recreate layers to get the same effect. See
-  // crbug.com/924802.
-  ScopedAnimationDisabler disable(window);
-  window->Hide();
-  wm::GetWindowState(window)->Minimize();
-  std::unique_ptr<ui::LayerTreeOwner> owner = ::wm::RecreateLayers(window);
-}
+void HideAndMaybeMinimizeWithoutAnimation(std::vector<aura::Window*> windows,
+                                          bool minimize) {
+  for (auto* window : windows) {
+    ScopedAnimationDisabler disable(window);
 
-void HideWithoutAnimation(aura::Window* window) {
-  ScopedAnimationDisabler disable(window);
-  window->Hide();
-  std::unique_ptr<ui::LayerTreeOwner> owner = ::wm::RecreateLayers(window);
+    // ARC windows are minimized asynchronously, so hide here now.
+    // TODO(oshima): Investigate better way to handle ARC apps immediately.
+    window->Hide();
+
+    if (minimize)
+      wm::GetWindowState(window)->Minimize();
+  }
+  if (windows.size()) {
+    // Disable the animations using |disable|. However, doing so will skip
+    // detaching the resources associated with the layer. So we have to trick
+    // the compositor into releasing the resources.
+    // crbug.com/924802.
+    auto* compositor = windows[0]->layer()->GetCompositor();
+    bool was_visible = compositor->IsVisible();
+    compositor->SetVisible(false);
+    compositor->SetVisible(was_visible);
+  }
 }
 
 }  // namespace wm
diff --git a/ash/wm/window_util.h b/ash/wm/window_util.h
index 1121290721..5ea393d 100644
--- a/ash/wm/window_util.h
+++ b/ash/wm/window_util.h
@@ -116,10 +116,12 @@
 ASH_EXPORT void RemoveTransientDescendants(
     std::vector<aura::Window*>* out_window_list);
 
-// Minimizes or hides |window| without any animations, in case users what it to
-// hide right away or apply their own animations.
-ASH_EXPORT void HideAndMinimizeWithoutAnimation(aura::Window* window);
-ASH_EXPORT void HideWithoutAnimation(aura::Window* window);
+// Hides a list of |windows| without any animations, in case users wants to hide
+// them right away or apply their own animations. Setting |minimize| to true
+// will result in also setting the window states to minimized.
+ASH_EXPORT void HideAndMaybeMinimizeWithoutAnimation(
+    std::vector<aura::Window*> windows,
+    bool minimize);
 
 }  // namespace wm
 }  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 6773a02..b74dc76 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -238,6 +238,9 @@
     "debug/task_annotator.h",
     "deferred_sequenced_task_runner.cc",
     "deferred_sequenced_task_runner.h",
+    "enterprise_util.h",
+    "enterprise_util_mac.mm",
+    "enterprise_util_win.cc",
     "environment.cc",
     "environment.h",
     "export_template.h",
@@ -1692,6 +1695,7 @@
       "bsm",
       "CoreFoundation.framework",
       "IOKit.framework",
+      "OpenDirectory.framework",
       "Security.framework",
     ]
   }
diff --git a/base/enterprise_util.h b/base/enterprise_util.h
new file mode 100644
index 0000000..d5ecbde
--- /dev/null
+++ b/base/enterprise_util.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ENTERPRISE_UTIL_H_
+#define BASE_ENTERPRISE_UTIL_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Returns true if an outside entity manages the current machine. This includes
+// but is not limited to the presence of user accounts from a centralized
+// directory or the presence of dynamically updatable machine policies from an
+// outside administrator.
+BASE_EXPORT bool IsMachineExternallyManaged();
+
+}  // namespace base
+
+#endif  // BASE_ENTERPRISE_UTIL_H_
diff --git a/base/enterprise_util_mac.mm b/base/enterprise_util_mac.mm
new file mode 100644
index 0000000..8d5c732
--- /dev/null
+++ b/base/enterprise_util_mac.mm
@@ -0,0 +1,117 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/enterprise_util.h"
+
+#import <OpenDirectory/OpenDirectory.h>
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/sdk_forward_declarations.h"
+
+namespace base {
+
+bool IsMachineExternallyManaged() {
+  @autoreleasepool {
+    ODSession* session = [ODSession defaultSession];
+    if (session == nil) {
+      DLOG(WARNING) << "ODSession default session is nil.";
+      return false;
+    }
+
+    NSError* error = nil;
+
+    NSArray<NSString*>* all_node_names =
+        [session nodeNamesAndReturnError:&error];
+    if (!all_node_names) {
+      DLOG(WARNING) << "ODSession failed to give node names: "
+                    << error.localizedDescription.UTF8String;
+      return false;
+    }
+
+    NSUInteger num_nodes = all_node_names.count;
+    if (num_nodes < 3) {
+      DLOG(WARNING) << "ODSession returned too few node names: "
+                    << all_node_names.description.UTF8String;
+      return false;
+    }
+
+    if (num_nodes > 3) {
+      // Non-enterprise machines have:"/Search", "/Search/Contacts",
+      // "/Local/Default". Everything else would be enterprise management.
+      return true;
+    }
+
+    ODNode* node = [ODNode nodeWithSession:session
+                                      type:kODNodeTypeAuthentication
+                                     error:&error];
+    if (node == nil) {
+      DLOG(WARNING) << "ODSession cannot obtain the authentication node: "
+                    << error.localizedDescription.UTF8String;
+      return false;
+    }
+
+    // Now check the currently logged on user.
+    ODQuery* query = [ODQuery queryWithNode:node
+                             forRecordTypes:kODRecordTypeUsers
+                                  attribute:kODAttributeTypeRecordName
+                                  matchType:kODMatchEqualTo
+                                queryValues:NSUserName()
+                           returnAttributes:kODAttributeTypeAllAttributes
+                             maximumResults:0
+                                      error:&error];
+    if (query == nil) {
+      DLOG(WARNING) << "ODSession cannot create user query: "
+                    << base::mac::NSToCFCast(error);
+      return false;
+    }
+
+    NSArray* results = [query resultsAllowingPartial:NO error:&error];
+    if (!results) {
+      DLOG(WARNING) << "ODSession cannot obtain current user node: "
+                    << error.localizedDescription.UTF8String;
+      return false;
+    }
+    if (results.count != 1) {
+      DLOG(WARNING) << @"ODSession unexpected number of user nodes: "
+                    << results.count;
+    }
+    for (id element in results) {
+      ODRecord* record = base::mac::ObjCCastStrict<ODRecord>(element);
+      NSArray* attributes =
+          [record valuesForAttribute:kODAttributeTypeMetaRecordName error:nil];
+      for (id attribute in attributes) {
+        NSString* attribute_value =
+            base::mac::ObjCCastStrict<NSString>(attribute);
+        // Example: "uid=johnsmith,ou=People,dc=chromium,dc=org
+        NSRange domain_controller =
+            [attribute_value rangeOfString:@"(^|,)\\s*dc="
+                                   options:NSRegularExpressionSearch];
+        if (domain_controller.length > 0) {
+          return true;
+        }
+      }
+
+      // Scan alternative identities.
+      attributes =
+          [record valuesForAttribute:kODAttributeTypeAltSecurityIdentities
+                               error:nil];
+      for (id attribute in attributes) {
+        NSString* attribute_value =
+            base::mac::ObjCCastStrict<NSString>(attribute);
+        NSRange icloud =
+            [attribute_value rangeOfString:@"CN=com.apple.idms.appleid.prd"
+                                   options:NSCaseInsensitiveSearch];
+        if (!icloud.length) {
+          // Any alternative identity that is not iCloud is likely enterprise
+          // management.
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+}  // namespace base
diff --git a/base/enterprise_util_win.cc b/base/enterprise_util_win.cc
new file mode 100644
index 0000000..be378bf
--- /dev/null
+++ b/base/enterprise_util_win.cc
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/enterprise_util.h"
+
+#include "base/win/win_util.h"
+
+namespace base {
+
+bool IsMachineExternallyManaged() {
+  // TODO(rogerta): this function should really be:
+  //
+  //    return IsEnrolledToDomain() || IsDeviceRegisteredWithManagement();
+  //
+  // However, for now it is decided to collect some UMA metrics about
+  // IsDeviceRegisteredWithMdm() before changing chrome's behavior.
+  return base::win::IsEnrolledToDomain();
+}
+
+}  // namespace base
diff --git a/base/fuchsia/default_job.cc b/base/fuchsia/default_job.cc
index c26aeb34..b23d1d1 100644
--- a/base/fuchsia/default_job.cc
+++ b/base/fuchsia/default_job.cc
@@ -25,4 +25,16 @@
   g_job = job.release();
 }
 
+ScopedDefaultJobForTest::ScopedDefaultJobForTest(zx::job new_default_job) {
+  DCHECK(new_default_job.is_valid());
+  old_default_job_.reset(g_job);
+  g_job = new_default_job.release();
+}
+
+ScopedDefaultJobForTest::~ScopedDefaultJobForTest() {
+  DCHECK_NE(g_job, ZX_HANDLE_INVALID);
+  zx::job my_default_job(g_job);
+  g_job = old_default_job_.release();
+}
+
 }  // namespace base
diff --git a/base/fuchsia/default_job.h b/base/fuchsia/default_job.h
index 9417f1c3..8921bfd9 100644
--- a/base/fuchsia/default_job.h
+++ b/base/fuchsia/default_job.h
@@ -8,6 +8,7 @@
 #include <lib/zx/job.h>
 
 #include "base/base_export.h"
+#include "base/macros.h"
 
 namespace base {
 
@@ -18,6 +19,19 @@
 BASE_EXPORT zx::unowned_job GetDefaultJob();
 BASE_EXPORT void SetDefaultJob(zx::job job);
 
+// Replaces the current default job (if any) with the specified zx::job, and
+// restores the original default job when going out-of-scope.
+// Note that replacing the default job is not thread-safe!
+class BASE_EXPORT ScopedDefaultJobForTest {
+ public:
+  ScopedDefaultJobForTest(zx::job new_default_job);
+  ~ScopedDefaultJobForTest();
+
+ private:
+  zx::job old_default_job_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedDefaultJobForTest);
+};
+
 }  // namespace base
 
 #endif  // BASE_FUCHSIA_DEFAULT_JOB_H_
diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc
index 6b924bc..92a383f 100644
--- a/base/message_loop/message_pump_libevent.cc
+++ b/base/message_loop/message_pump_libevent.cc
@@ -33,13 +33,6 @@
 // StopWatchingFileDescriptor().
 // It is moved into and out of lists in struct event_base by
 // the libevent functions event_add() and event_del().
-//
-// TODO(dkegel):
-// At the moment bad things happen if a FdWatchController
-// is active after its MessagePumpLibevent has been destroyed.
-// See MessageLoopTest.FdWatchControllerOutlivesMessageLoop
-// Not clear yet whether that situation occurs in practice,
-// but if it does, we need to fix it.
 
 namespace base {
 
@@ -49,7 +42,7 @@
 
 MessagePumpLibevent::FdWatchController::~FdWatchController() {
   if (event_) {
-    StopWatchingFileDescriptor();
+    CHECK(StopWatchingFileDescriptor());
   }
   if (was_destroyed_) {
     DCHECK(!*was_destroyed_);
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl.cc b/base/task/task_scheduler/scheduler_worker_pool_impl.cc
index 75a542f..e7aca3c 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl.cc
@@ -840,10 +840,7 @@
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::BlockingStarted(
     BlockingType blocking_type) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-
-  // Blocking calls made outside of tasks should not influence the max tasks.
-  if (!worker_only().is_running_task)
-    return;
+  DCHECK(worker_only().is_running_task);
 
   switch (blocking_type) {
     case BlockingType::MAY_BLOCK:
@@ -858,6 +855,7 @@
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
     BlockingTypeUpgraded() {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
+  DCHECK(worker_only().is_running_task);
 
   {
     AutoSchedulerLock auto_lock(outer_->lock_);
@@ -882,10 +880,7 @@
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::BlockingEnded() {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-
-  // Ignore blocking calls made outside of tasks.
-  if (!worker_only().is_running_task)
-    return;
+  DCHECK(worker_only().is_running_task);
 
   AutoSchedulerLock auto_lock(outer_->lock_);
   if (incremented_max_tasks_since_blocked_) {
@@ -904,6 +899,7 @@
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::MayBlockEntered() {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
+  DCHECK(worker_only().is_running_task);
 
   bool must_schedule_adjust_max_tasks = false;
   {
@@ -925,6 +921,7 @@
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::WillBlockEntered() {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
+  DCHECK(worker_only().is_running_task);
 
   bool must_schedule_adjust_max_tasks = false;
   SchedulerWorkerActionExecutor executor(outer_);
diff --git a/base/test/scoped_task_environment.h b/base/test/scoped_task_environment.h
index 69aa387..e5ae30d 100644
--- a/base/test/scoped_task_environment.h
+++ b/base/test/scoped_task_environment.h
@@ -100,11 +100,12 @@
   };
 
   enum class NowSource {
-    // base::TimeTicks::Now is real time.
+    // base::Time::Now() and base::TimeTicks::Now() are real time.
     REAL_TIME,
 
-    // base::TimeTicks::Now is driven from the main thread's MOCK_TIME. This
-    // may alter the order of delayed and non-delayed tasks on other threads.
+    // base::Time::Now() and base::TimeTicks::Now() are driven from the main
+    // thread's MOCK_TIME. This may alter the order of delayed and non-delayed
+    // tasks on other threads.
     //
     // Warning some platform APIs are still real time, and don't interact with
     // MOCK_TIME as expected, e.g.:
diff --git a/base/test/scoped_task_environment_unittest.cc b/base/test/scoped_task_environment_unittest.cc
index c1c0441..89d777e 100644
--- a/base/test/scoped_task_environment_unittest.cc
+++ b/base/test/scoped_task_environment_unittest.cc
@@ -322,6 +322,28 @@
   EXPECT_EQ(start_time + kDelay, clock->Now());
 }
 
+TEST_F(ScopedTaskEnvironmentTest, FastForwardAdvanceTime) {
+  constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+  ScopedTaskEnvironment scoped_task_environment(
+      ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
+      ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME);
+
+  const Time start_time = base::Time::Now();
+  scoped_task_environment.FastForwardBy(kDelay);
+  EXPECT_EQ(start_time + kDelay, base::Time::Now());
+}
+
+TEST_F(ScopedTaskEnvironmentTest, FastForwardAdvanceTimeTicks) {
+  constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+  ScopedTaskEnvironment scoped_task_environment(
+      ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
+      ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME);
+
+  const TimeTicks start_time = base::TimeTicks::Now();
+  scoped_task_environment.FastForwardBy(kDelay);
+  EXPECT_EQ(start_time + kDelay, base::TimeTicks::Now());
+}
+
 #if defined(OS_WIN)
 // Regression test to ensure that ScopedTaskEnvironment enables the MTA in the
 // thread pool (so that the test environment matches that of the browser process
diff --git a/base/time/time.cc b/base/time/time.cc
index 30acde5..3e46f17 100644
--- a/base/time/time.cc
+++ b/base/time/time.cc
@@ -137,24 +137,44 @@
 
 namespace time_internal {
 
-int64_t SaturatedAdd(TimeDelta delta, int64_t value) {
-  CheckedNumeric<int64_t> rv(delta.delta_);
-  rv += value;
+int64_t SaturatedAdd(int64_t value, TimeDelta delta) {
+  // Treat Min/Max() as +/- infinity (additions involving two infinities are
+  // only valid if signs match).
+  if (delta.is_max()) {
+    CHECK_GT(value, std::numeric_limits<int64_t>::min());
+    return std::numeric_limits<int64_t>::max();
+  } else if (delta.is_min()) {
+    CHECK_LT(value, std::numeric_limits<int64_t>::max());
+    return std::numeric_limits<int64_t>::min();
+  }
+
+  CheckedNumeric<int64_t> rv(value);
+  rv += delta.delta_;
   if (rv.IsValid())
     return rv.ValueOrDie();
   // Positive RHS overflows. Negative RHS underflows.
-  if (value < 0)
+  if (delta.delta_ < 0)
     return std::numeric_limits<int64_t>::min();
   return std::numeric_limits<int64_t>::max();
 }
 
-int64_t SaturatedSub(TimeDelta delta, int64_t value) {
-  CheckedNumeric<int64_t> rv(delta.delta_);
-  rv -= value;
+int64_t SaturatedSub(int64_t value, TimeDelta delta) {
+  // Treat Min/Max() as +/- infinity (subtractions involving two infinities are
+  // only valid if signs are opposite).
+  if (delta.is_max()) {
+    CHECK_LT(value, std::numeric_limits<int64_t>::max());
+    return std::numeric_limits<int64_t>::min();
+  } else if (delta.is_min()) {
+    CHECK_GT(value, std::numeric_limits<int64_t>::min());
+    return std::numeric_limits<int64_t>::max();
+  }
+
+  CheckedNumeric<int64_t> rv(value);
+  rv -= delta.delta_;
   if (rv.IsValid())
     return rv.ValueOrDie();
   // Negative RHS overflows. Positive RHS underflows.
-  if (value < 0)
+  if (delta.delta_ < 0)
     return std::numeric_limits<int64_t>::max();
   return std::numeric_limits<int64_t>::min();
 }
diff --git a/base/time/time.h b/base/time/time.h
index 4fd41a6..de4a34f 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -97,10 +97,12 @@
 // time classes instead.
 namespace time_internal {
 
-// Add or subtract |value| from a TimeDelta. The int64_t argument and return
-// value are in terms of a microsecond timebase.
-BASE_EXPORT int64_t SaturatedAdd(TimeDelta delta, int64_t value);
-BASE_EXPORT int64_t SaturatedSub(TimeDelta delta, int64_t value);
+// Add or subtract a TimeDelta from |value|. TimeDelta::Min()/Max() are treated
+// as infinity and will always saturate the return value (infinity math applies
+// if |value| also is at either limit of its spectrum). The int64_t argument and
+// return value are in terms of a microsecond timebase.
+BASE_EXPORT int64_t SaturatedAdd(int64_t value, TimeDelta delta);
+BASE_EXPORT int64_t SaturatedSub(int64_t value, TimeDelta delta);
 
 }  // namespace time_internal
 
@@ -204,10 +206,10 @@
   // __builtin_(add|sub)_overflow in safe_math_clang_gcc_impl.h :
   // https://chromium-review.googlesource.com/c/chromium/src/+/873352#message-59594ab70827795a67e0780404adf37b4b6c2f14
   TimeDelta operator+(TimeDelta other) const {
-    return TimeDelta(time_internal::SaturatedAdd(*this, other.delta_));
+    return TimeDelta(time_internal::SaturatedAdd(delta_, other));
   }
   TimeDelta operator-(TimeDelta other) const {
-    return TimeDelta(time_internal::SaturatedSub(*this, other.delta_));
+    return TimeDelta(time_internal::SaturatedSub(delta_, other));
   }
 
   TimeDelta& operator+=(TimeDelta other) {
@@ -279,8 +281,8 @@
   }
 
  private:
-  friend int64_t time_internal::SaturatedAdd(TimeDelta delta, int64_t value);
-  friend int64_t time_internal::SaturatedSub(TimeDelta delta, int64_t value);
+  friend int64_t time_internal::SaturatedAdd(int64_t value, TimeDelta delta);
+  friend int64_t time_internal::SaturatedSub(int64_t value, TimeDelta delta);
 
   // Constructs a delta given the duration in microseconds. This is private
   // to avoid confusion by callers with an integer constructor. Use
@@ -393,10 +395,10 @@
 
   // Return a new time modified by some delta.
   TimeClass operator+(TimeDelta delta) const {
-    return TimeClass(time_internal::SaturatedAdd(delta, us_));
+    return TimeClass(time_internal::SaturatedAdd(us_, delta));
   }
   TimeClass operator-(TimeDelta delta) const {
-    return TimeClass(-time_internal::SaturatedSub(delta, us_));
+    return TimeClass(time_internal::SaturatedSub(us_, delta));
   }
 
   // Modify by some time delta.
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index 7b51d15..401f2017 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/gtest_util.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time_override.h"
 #include "build/build_config.h"
@@ -1542,6 +1543,62 @@
   EXPECT_EQ(kOneSecond, (ticks_now + kOneSecond) - ticks_now);
 }
 
+TEST(TimeBase, AddSubDeltaSaturates) {
+  constexpr TimeTicks kLargeTimeTicks =
+      TimeTicks::FromInternalValue(std::numeric_limits<int64_t>::max() - 1);
+
+  constexpr TimeTicks kLargeNegativeTimeTicks =
+      TimeTicks::FromInternalValue(std::numeric_limits<int64_t>::min() + 1);
+
+  EXPECT_TRUE((kLargeTimeTicks + TimeDelta::Max()).is_max())
+      << (kLargeTimeTicks + TimeDelta::Max());
+  EXPECT_TRUE((kLargeNegativeTimeTicks + TimeDelta::Max()).is_max())
+      << (kLargeNegativeTimeTicks + TimeDelta::Max());
+  EXPECT_TRUE((kLargeTimeTicks - TimeDelta::Max()).is_min())
+      << (kLargeTimeTicks - TimeDelta::Max());
+  EXPECT_TRUE((kLargeNegativeTimeTicks - TimeDelta::Max()).is_min())
+      << (kLargeNegativeTimeTicks - TimeDelta::Max());
+  EXPECT_TRUE((TimeTicks() + TimeDelta::Max()).is_max())
+      << (TimeTicks() + TimeDelta::Max());
+  EXPECT_TRUE((TimeTicks() - TimeDelta::Max()).is_min())
+      << (TimeTicks() - TimeDelta::Max());
+  EXPECT_TRUE((TimeTicks::Now() + TimeDelta::Max()).is_max())
+      << (TimeTicks::Now() + TimeDelta::Max());
+  EXPECT_TRUE((TimeTicks::Now() - TimeDelta::Max()).is_min())
+      << (TimeTicks::Now() - TimeDelta::Max());
+
+  EXPECT_TRUE((kLargeTimeTicks + TimeDelta::Min()).is_min())
+      << (kLargeTimeTicks + TimeDelta::Min());
+  EXPECT_TRUE((kLargeNegativeTimeTicks + TimeDelta::Min()).is_min())
+      << (kLargeNegativeTimeTicks + TimeDelta::Min());
+  EXPECT_TRUE((kLargeTimeTicks - TimeDelta::Min()).is_max())
+      << (kLargeTimeTicks - TimeDelta::Min());
+  EXPECT_TRUE((kLargeNegativeTimeTicks - TimeDelta::Min()).is_max())
+      << (kLargeNegativeTimeTicks - TimeDelta::Min());
+  EXPECT_TRUE((TimeTicks() + TimeDelta::Min()).is_min())
+      << (TimeTicks() + TimeDelta::Min());
+  EXPECT_TRUE((TimeTicks() - TimeDelta::Min()).is_max())
+      << (TimeTicks() - TimeDelta::Min());
+  EXPECT_TRUE((TimeTicks::Now() + TimeDelta::Min()).is_min())
+      << (TimeTicks::Now() + TimeDelta::Min());
+  EXPECT_TRUE((TimeTicks::Now() - TimeDelta::Min()).is_max())
+      << (TimeTicks::Now() - TimeDelta::Min());
+}
+
+TEST(TimeBase, AddSubInfinities) {
+  // CHECK when adding opposite signs or subtracting same sign.
+  EXPECT_CHECK_DEATH({ TimeTicks::Min() + TimeDelta::Max(); });
+  EXPECT_CHECK_DEATH({ TimeTicks::Max() + TimeDelta::Min(); });
+  EXPECT_CHECK_DEATH({ TimeTicks::Min() - TimeDelta::Min(); });
+  EXPECT_CHECK_DEATH({ TimeTicks::Max() - TimeDelta::Max(); });
+
+  // Saturates when adding same sign or subtracting opposite signs.
+  EXPECT_TRUE((TimeTicks::Max() + TimeDelta::Max()).is_max());
+  EXPECT_TRUE((TimeTicks::Min() + TimeDelta::Min()).is_min());
+  EXPECT_TRUE((TimeTicks::Max() - TimeDelta::Min()).is_max());
+  EXPECT_TRUE((TimeTicks::Min() - TimeDelta::Max()).is_min());
+}
+
 constexpr TimeTicks TestTimeTicksConstexprCopyAssignment() {
   TimeTicks a = TimeTicks::FromInternalValue(12345);
   TimeTicks b;
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index 66c934c..ae689a8 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -594,16 +594,6 @@
   return *GetRegisteredWithManagementStateStorage();
 }
 
-bool IsEnterpriseManaged() {
-  // TODO(rogerta): this function should really be:
-  //
-  //    return IsEnrolledToDomain() || IsDeviceRegisteredWithManagement();
-  //
-  // However, for now it is decided to collect some UMA metrics about
-  // IsDeviceRegisteredWithMdm() before changing chrome's behavior.
-  return IsEnrolledToDomain();
-}
-
 bool IsUser32AndGdi32Available() {
   static auto is_user32_and_gdi32_available = []() {
     // If win32k syscalls aren't disabled, then user32 and gdi32 are available.
diff --git a/base/win/win_util.h b/base/win/win_util.h
index 8ee1ad16..1806689 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -158,11 +158,6 @@
 // Returns true if the machine is being managed by an MDM system.
 BASE_EXPORT bool IsDeviceRegisteredWithManagement();
 
-// Returns true if the current machine is considered enterprise managed in some
-// fashion.  A machine is considered managed if it is either domain enrolled
-// or registered with an MDM.
-BASE_EXPORT bool IsEnterpriseManaged();
-
 // Returns true if the current process can make USER32 or GDI32 calls such as
 // CreateWindow and CreateDC. Windows 8 and above allow the kernel component
 // of these calls to be disabled which can cause undefined behaviour such as
diff --git a/build/config/posix/BUILD.gn b/build/config/posix/BUILD.gn
index a363ab7..9a1c34f 100644
--- a/build/config/posix/BUILD.gn
+++ b/build/config/posix/BUILD.gn
@@ -14,6 +14,25 @@
 # This build configuration is used by both Fuchsia and POSIX systems.
 assert(is_posix || is_fuchsia)
 
+declare_args() {
+  # lldb pretty printing only works when libc++ is built in the __1 (or __ndk1)
+  # namespaces.  For pretty printing to work out-of-the-box on Mac (where lldb
+  # is primarily used), this flag is set to false to build with the __1
+  # namespace (to maintain ABI compatibility, this implies building without
+  # _LIBCPP_ABI_UNSTABLE).  This is not necessary on non-component builds
+  # because we leave the ABI version set to __1 in that case because libc++
+  # symbols are not exported.
+  # TODO(thomasanderson): Set this to true by default once rL352899 is available
+  # in MacOS's lldb.
+  libcxx_abi_unstable = !(is_mac && is_debug && is_component_build)
+}
+
+# TODO(xiaohuic): https://crbug/917533 Crashes on internal ChromeOS build.
+# Do unconditionally once the underlying problem is fixed.
+if (is_chromeos && is_chrome_branded) {
+  libcxx_abi_unstable = false
+}
+
 group("posix") {
   visibility = [ "//:optimize_gn_gen" ]
 }
@@ -35,12 +54,18 @@
   libs = []
 
   if (use_custom_libcxx) {
+    if (libcxx_abi_unstable) {
+      defines += [ "_LIBCPP_ABI_UNSTABLE" ]
+    }
+
     if (is_component_build) {
       # In component builds, symbols from libc++.so are exported for all DSOs to
       # use.  If the system libc++ gets loaded (indirectly through a system
       # library), then it will conflict with our libc++.so.  Add a custom ABI
-      # version to avoid conflicts.
-      defines += [ "_LIBCPP_ABI_VERSION=Cr" ]
+      # version if we're building with _LIBCPP_ABI_UNSTABLE to avoid conflicts.
+      if (libcxx_abi_unstable) {
+        defines += [ "_LIBCPP_ABI_VERSION=Cr" ]
+      }
     } else {
       # Don't leak any symbols on a static build.
       defines += [ "_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS" ]
@@ -59,12 +84,6 @@
       "_LIBCPP_ENABLE_NODISCARD",
     ]
 
-    # TODO(xiaohuic): https://crbug/917533 Crashes on internal ChromeOS build.
-    # Do unconditionally once the underlying problem is fixed.
-    if (!(is_chromeos && is_chrome_branded)) {
-      defines += [ "_LIBCPP_ABI_UNSTABLE" ]
-    }
-
     # Make sure we don't link against libc++ or libstdc++.
     if (is_clang) {
       # //build/config/android:runtime_library adds -nostdlib, which suppresses
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index e6a2712..5884a063 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-cbd2d44f67b0fe018b2ba2fed82e420385c6f1f7
\ No newline at end of file
+590f4e2abc471dca242f054e08dac2e07c5e255b
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 89b3453..1d2b4f0 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-97ad31fed28e73a9e4e123091435e36b604d4aa9
\ No newline at end of file
+8a2c5b509acacad27fcb2f3f288c5736d5a4e057
\ No newline at end of file
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index c4b19ee..224e3ab 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -284,10 +284,18 @@
         PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace());
   }
 
+  // Returns dimensions for an image that will not fit in GPU memory and hence
+  // triggers software fallback.
   gfx::Size GetLargeImageSize() const {
     return gfx::Size(1, max_texture_size_ + 1);
   }
 
+  // Returns dimensions for an image that will fit in GPU memory.
+  gfx::Size GetNormalImageSize() const {
+    size_t dimension = std::min(100, max_texture_size_ - 1);
+    return gfx::Size(dimension, dimension);
+  }
+
   PaintImage CreatePaintImageInternal(
       const gfx::Size& size,
       sk_sp<SkColorSpace> color_space = nullptr,
@@ -365,7 +373,7 @@
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
   auto cache = CreateCache();
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -396,7 +404,7 @@
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
   auto cache = CreateCache();
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -427,7 +435,7 @@
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
   auto cache = CreateCache();
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
 
@@ -459,7 +467,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -469,7 +477,7 @@
   EXPECT_TRUE(first_result.need_unref);
   EXPECT_TRUE(first_result.task);
 
-  PaintImage second_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage second_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage second_draw_image(
       second_image,
       SkIRect::MakeWH(second_image.width(), second_image.height()), quality,
@@ -495,7 +503,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -541,7 +549,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -585,7 +593,7 @@
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
 
-  PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex);
@@ -618,7 +626,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -660,7 +668,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -702,7 +710,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -733,7 +741,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -776,7 +784,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -823,7 +831,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -852,7 +860,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -882,7 +890,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -950,7 +958,7 @@
 
   cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -984,7 +992,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kLow_SkFilterQuality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -1039,7 +1047,7 @@
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable);
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kLow_SkFilterQuality, matrix,
                        PaintImage::kDefaultFrameIndex);
@@ -1091,7 +1099,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable),
@@ -1168,7 +1176,7 @@
 
   cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -1192,7 +1200,9 @@
 
   // Increase memory limit and attempt to use the same image. It should be in
   // available for ref.
-  cache->SetWorkingSetLimitsForTesting(96 * 1024 * 1024 /* max_bytes */,
+  size_t bytes_for_image =
+      SkColorTypeBytesPerPixel(color_type_) * image.width() * image.height();
+  cache->SetWorkingSetLimitsForTesting(bytes_for_image /* max_bytes */,
                                        256 /* max_items */);
   ImageDecodeCache::TaskResult another_result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1209,7 +1219,7 @@
 
   cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -1283,7 +1293,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
@@ -1309,9 +1319,11 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(
-      image, SkIRect::MakeXYWH(150, 150, image.width(), image.height()),
+      image,
+      SkIRect::MakeXYWH(image.width() + 50, image.height() + 50, image.width(),
+                        image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
       PaintImage::kDefaultFrameIndex);
 
@@ -1335,7 +1347,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(
       image, SkIRect::MakeXYWH(0, 0, image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
@@ -1361,7 +1373,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -1423,7 +1435,7 @@
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
   // Create a downscaled image.
-  PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -1471,7 +1483,7 @@
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
   // Create a downscaled image.
-  PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -1513,7 +1525,7 @@
 
 TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
   auto cache = CreateCache();
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
 
@@ -1565,7 +1577,7 @@
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
   // Create an image decode task and cache entry that does not need mips.
-  PaintImage image = CreatePaintImageInternal(gfx::Size(3072, 4096));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -1600,7 +1612,7 @@
 TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
   auto cache = CreateCache();
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(1, 1));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable);
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
@@ -1629,7 +1641,7 @@
 
   // Add an image to the cache-> Due to normal working set, this should produce
   // a task and a ref.
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -1680,13 +1692,13 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
                        PaintImage::kDefaultFrameIndex);
 
-  PaintImage image2 = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image2 = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image2(
       image2, SkIRect::MakeWH(image2.width(), image2.height()), quality,
       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -1763,7 +1775,7 @@
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
   for (int i = 0; i < 10; ++i) {
-    PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+    PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
     DrawImage draw_image(
         image, SkIRect::MakeWH(image.width(), image.height()), quality,
         CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -1793,7 +1805,7 @@
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
   // Create an image but keep it reffed so it can't be immediately freed.
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -1855,7 +1867,10 @@
   };
   sk_sp<FakePaintImageGenerator> generator =
       sk_make_sp<FakePaintImageGenerator>(
-          SkImageInfo::Make(10, 10, color_type_, kPremul_SkAlphaType), frames);
+          SkImageInfo::Make(GetNormalImageSize().width(),
+                            GetNormalImageSize().height(), color_type_,
+                            kPremul_SkAlphaType),
+          frames);
   PaintImage image = PaintImageBuilder::WithDefault()
                          .set_id(PaintImage::GetNextId())
                          .set_paint_image_generator(generator)
@@ -1905,7 +1920,7 @@
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
   // Create a downscaled image.
-  PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -1959,11 +1974,13 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  // Allow a single 10x10 image and lock it.
-  cache->SetWorkingSetLimitsForTesting(
-      SkColorTypeBytesPerPixel(GetParam().first) * 10 * 10 * 10 /* max_bytes */,
-      1 /* max_items */);
-  PaintImage image = CreatePaintImageInternal(gfx::Size(10, 10));
+  // Allow a single small image and lock it.
+  size_t bytes_for_image = SkColorTypeBytesPerPixel(color_type_) *
+                           GetNormalImageSize().width() *
+                           GetNormalImageSize().height();
+  cache->SetWorkingSetLimitsForTesting(bytes_for_image /* max_bytes */,
+                                       1 /* max_items */);
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -1998,9 +2015,12 @@
 
   // Allow a single image by count. Use a high byte limit as we want to test the
   // count restriction.
-  cache->SetWorkingSetLimitsForTesting(96 * 1024 * 1024 /* max_bytes */,
+  size_t bytes_for_image = SkColorTypeBytesPerPixel(color_type_) *
+                           GetNormalImageSize().width() *
+                           GetNormalImageSize().height();
+  cache->SetWorkingSetLimitsForTesting(bytes_for_image * 100 /* max_bytes */,
                                        1 /* max_items */);
-  PaintImage image = CreatePaintImageInternal(gfx::Size(10, 10));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -2015,7 +2035,7 @@
 
   // Try another image, it shouldn't be budgeted and should be at-raster.
   DrawImage second_draw_image(
-      CreatePaintImageInternal(gfx::Size(100, 100)),
+      CreatePaintImageInternal(GetNormalImageSize()),
       SkIRect::MakeWH(image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       PaintImage::kDefaultFrameIndex);
@@ -2039,12 +2059,14 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  // Allow a single 10x10 image by size. Don't restrict the items limit as we
+  // Allow a single small image by size. Don't restrict the items limit as we
   // want to test the size limit.
-  cache->SetWorkingSetLimitsForTesting(
-      SkColorTypeBytesPerPixel(GetParam().first) * 10 * 10 * 10 /* max_bytes */,
-      256 /* max_items */);
-  PaintImage image = CreateDiscardablePaintImage(gfx::Size(10, 10));
+  size_t bytes_for_image = SkColorTypeBytesPerPixel(color_type_) *
+                           GetNormalImageSize().width() *
+                           GetNormalImageSize().height();
+  cache->SetWorkingSetLimitsForTesting(bytes_for_image /* max_bytes */,
+                                       256 /* max_items */);
+  PaintImage image = CreateDiscardablePaintImage(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -2059,7 +2081,7 @@
 
   // Try another image, it shouldn't be budgeted and should be at-raster.
   DrawImage second_draw_image(
-      CreateDiscardablePaintImage(gfx::Size(100, 100)),
+      CreateDiscardablePaintImage(GetNormalImageSize()),
       SkIRect::MakeWH(image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       PaintImage::kDefaultFrameIndex);
@@ -2189,7 +2211,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreateBitmapImageInternal(gfx::Size(10, 10));
+  PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -2210,7 +2232,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreateBitmapImageInternal(gfx::Size(10, 10));
+  PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -2230,7 +2252,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreateBitmapImageInternal(gfx::Size(10, 10));
+  PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
@@ -2281,7 +2303,7 @@
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  PaintImage image = CreateBitmapImageInternal(gfx::Size(10, 10));
+  PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -2296,8 +2318,8 @@
   // cached.
   auto sw_image = cache->GetSWImageDecodeForTesting(draw_image);
   EXPECT_TRUE(sw_image);
-  EXPECT_EQ(sw_image->width(), 5);
-  EXPECT_EQ(sw_image->height(), 5);
+  EXPECT_EQ(sw_image->width(), GetNormalImageSize().width() / 2);
+  EXPECT_EQ(sw_image->height(), GetNormalImageSize().height() / 2);
 }
 
 TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) {
@@ -2312,7 +2334,7 @@
 
   for (int i = 0; i < 10; ++i) {
     PaintImage image = CreatePaintImageInternal(
-        gfx::Size(10, 10), SkColorSpace::MakeSRGB(), paint_image_id);
+        GetNormalImageSize(), SkColorSpace::MakeSRGB(), paint_image_id);
     DrawImage draw_image(
         image, SkIRect::MakeWH(image.width(), image.height()), quality,
         CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
@@ -2427,7 +2449,7 @@
     auto cache = CreateCache(color_space);
     bool is_decomposable = true;
 
-    PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+    PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
     DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                          filter_quality, CreateMatrix(scale, is_decomposable),
                          PaintImage::kDefaultFrameIndex);
@@ -2484,7 +2506,7 @@
   bool is_decomposable = true;
   auto filter_quality = kMedium_SkFilterQuality;
 
-  PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100));
+  PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
 
   // Create an image with no scaling. It will not have mips.
   {
@@ -2558,7 +2580,7 @@
   bool is_decomposable = true;
   auto filter_quality = kMedium_SkFilterQuality;
 
-  PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
+  PaintImage image = CreateDiscardablePaintImage(GetNormalImageSize());
 
   struct Decode {
     DrawImage image;
diff --git a/cc/trees/damage_tracker.cc b/cc/trees/damage_tracker.cc
index dded361..fc245655 100644
--- a/cc/trees/damage_tracker.cc
+++ b/cc/trees/damage_tracker.cc
@@ -395,10 +395,27 @@
     }
   }
 
-  // Property changes from animaiton will not be considered as damage from
-  // contributing content.
-  if (layer_is_new || layer->LayerPropertyChangedNotFromPropertyTrees() ||
-      !layer->update_rect().IsEmpty() || !layer->damage_rect().IsEmpty()) {
+  // Property changes on effect or transform nodes that are shared by the
+  // render target are not considered damage to that target itself.  This
+  // is the case where the render target itself changes opacity or moves.
+  // The damage goes to the target's target instead.  This is not perfect,
+  // as the target and layer could share an effect but not a transform,
+  // but there's no tracking on the layer to differentiate that the
+  // LayerPropertyChangedFromPropertyTrees is for the effect not the transform.
+  bool property_change_on_non_target_node = false;
+  if (layer->LayerPropertyChangedFromPropertyTrees()) {
+    auto effect_id = layer->render_target()->EffectTreeIndex();
+    auto* effect_node =
+        layer->layer_tree_impl()->property_trees()->effect_tree.Node(effect_id);
+    auto transform_id = effect_node->transform_id;
+    property_change_on_non_target_node =
+        layer->effect_tree_index() != effect_id ||
+        layer->transform_tree_index() != transform_id;
+  }
+
+  if (layer_is_new || !layer->update_rect().IsEmpty() ||
+      layer->LayerPropertyChangedNotFromPropertyTrees() ||
+      !layer->damage_rect().IsEmpty() || property_change_on_non_target_node) {
     has_damage_from_contributing_content_ |= !damage_for_this_update_.IsEmpty();
   }
 }
diff --git a/cc/trees/damage_tracker_unittest.cc b/cc/trees/damage_tracker_unittest.cc
index a96cc8c..5623b6d 100644
--- a/cc/trees/damage_tracker_unittest.cc
+++ b/cc/trees/damage_tracker_unittest.cc
@@ -495,6 +495,54 @@
                   ->has_damage_from_contributing_content());
 }
 
+// Regression test for http://crbug.com/923794
+TEST_F(DamageTrackerTest, EffectPropertyChangeNoSurface) {
+  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
+  LayerImpl* child = root->test_properties()->children[0];
+
+  // Create a separate effect node for the child, but no render surface.
+  child->test_properties()->opacity = 0.5;
+  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
+  EmulateDrawingOneFrame(root);
+
+  EXPECT_EQ(root->transform_tree_index(), child->transform_tree_index());
+  EXPECT_NE(root->effect_tree_index(), child->effect_tree_index());
+
+  // Change the child's opacity, which should damage its target.
+  ClearDamageForAllSurfaces(root);
+  root->layer_tree_impl()->SetOpacityMutated(child->element_id(), 0.4f);
+  EmulateDrawingOneFrame(root);
+  EXPECT_TRUE(GetRenderSurface(root)
+                  ->damage_tracker()
+                  ->has_damage_from_contributing_content());
+}
+
+// Regression test for http://crbug.com/923794
+TEST_F(DamageTrackerTest, TransformPropertyChangeNoSurface) {
+  LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
+  LayerImpl* child = root->test_properties()->children[0];
+
+  // Create a separate transform node for the child, but no render surface.
+  gfx::Transform trans1;
+  trans1.Scale(2, 1);
+  child->test_properties()->transform = trans1;
+  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
+  EmulateDrawingOneFrame(root);
+
+  EXPECT_NE(root->transform_tree_index(), child->transform_tree_index());
+  EXPECT_EQ(root->effect_tree_index(), child->effect_tree_index());
+
+  // Change the child's transform , which should damage its target.
+  ClearDamageForAllSurfaces(root);
+  gfx::Transform trans2;
+  trans2.Scale(1, 2);
+  root->layer_tree_impl()->SetTransformMutated(child->element_id(), trans2);
+  EmulateDrawingOneFrame(root);
+  EXPECT_TRUE(GetRenderSurface(root)
+                  ->damage_tracker()
+                  ->has_damage_from_contributing_content());
+}
+
 TEST_F(DamageTrackerTest,
        VerifyDamageForUpdateAndDamageRectsFromContributingContents) {
   LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 4b858663..bbdc75f 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -8664,9 +8664,8 @@
   }
 };
 
-// TODO(crbug.com/851231): Disabled this test due to flakiness.
-// MULTI_THREAD_TEST_F(
-//    LayerTreeHostTestImageAnimationSynchronousSchedulingSoftwareDraw);
+MULTI_THREAD_TEST_F(
+    LayerTreeHostTestImageAnimationSynchronousSchedulingSoftwareDraw);
 
 class LayerTreeHostTestImageDecodingHints : public LayerTreeHostTest {
  public:
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserControllerInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserControllerInputTest.java
index 50bbb9f..bceea2a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserControllerInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserControllerInputTest.java
@@ -11,6 +11,8 @@
 import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_DAYDREAM_OR_STANDALONE;
 
 import android.graphics.PointF;
+import android.os.Build;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
@@ -187,7 +189,7 @@
      * scroll of the same speed scrolls further.
      */
     @Test
-    @MediumTest
+    @LargeTest
     public void testControllerFlingScrolling() throws InterruptedException {
         mVrTestRule.loadUrl(
                 VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_controller_scrolling"),
@@ -203,82 +205,117 @@
             return coord.getScrollXPixInt();
         };
 
-        // Test fling scrolling down.
-        // Perform a fast non-fling scroll and record how far it causes the page to scroll.
-        NativeUiUtils.scrollNonFlingFast(NativeUiUtils.ScrollDirection.DOWN);
-        waitForScrollQuiescence(getYCoord);
-        final AtomicInteger endScrollPoint = new AtomicInteger(coord.getScrollYPixInt());
-        NativeUiUtils.scrollFling(NativeUiUtils.ScrollDirection.DOWN);
-        // Check that we scroll further than we did with the non-fling scroll. This should be a very
-        // violent fling, so we expect the fling to go much further than the non-fling case.
-        // Choose 3 times as far since it's high enough to demonstrate that the fling is actually
-        // working properly, but not high enough to run into flakiness issues.
-        final int diffMultiplier = 3;
-        CriteriaHelper.pollInstrumentationThread(
-                ()
-                        -> {
-                    return coord.getScrollYPixInt() - endScrollPoint.get()
-                            > diffMultiplier * endScrollPoint.get();
-                },
-                "Controller failed to fling scroll down", POLL_TIMEOUT_SHORT_MS,
-                POLL_CHECK_INTERVAL_LONG_MS);
+        // Scrolling can be inconsistent on older/slower devices. So, try each direction up to
+        // 3 times to try to work around flakiness. Only enable this on problematic devices (
+        // currently first generation Pixel devices).
+        int numAttempts = 1;
+        if (Build.DEVICE.equals("marlin") || Build.DEVICE.equals("sailfish")) {
+            numAttempts = 3;
+        }
+        final int diffMultiplier = 2;
 
-        // Scroll the page all the way to the bottom so we can test the fling up.
-        waitForScrollQuiescence(getYCoord);
-        mVrBrowserTestFramework.runJavaScriptOrFail(
-                "window.scrollTo(0, document.documentElement.scrollHeight)", POLL_TIMEOUT_SHORT_MS);
-        waitForScrollQuiescence(getYCoord);
-        final AtomicInteger startScrollPoint = new AtomicInteger(coord.getScrollYPixInt());
+        int startPoint;
+        int nonFlingEndpoint;
+        int nonFlingDistance;
+        boolean succeeded = false;
+
+        // Test fling scrolling down.
+        for (int i = 0; i < numAttempts; ++i) {
+            startPoint = coord.getScrollYPixInt();
+            // Perform a fast non-fling scroll and record how far it causes the page to scroll.
+            NativeUiUtils.scrollNonFlingFast(NativeUiUtils.ScrollDirection.DOWN);
+            waitForScrollQuiescence(getYCoord);
+            nonFlingEndpoint = coord.getScrollYPixInt();
+            nonFlingDistance = nonFlingEndpoint - startPoint;
+            // Perform a fling scroll and check that it goes sufficiently further than the non-fling
+            // scroll.
+            NativeUiUtils.scrollFling(NativeUiUtils.ScrollDirection.DOWN);
+            waitForScrollQuiescence(getYCoord);
+            if (coord.getScrollYPixInt() - nonFlingEndpoint >= diffMultiplier * nonFlingDistance) {
+                succeeded = true;
+                break;
+            }
+            // Reset to the top of the page to try again.
+            mVrBrowserTestFramework.runJavaScriptOrFail(
+                    "window.scrollTo(0, 0)", POLL_TIMEOUT_SHORT_MS);
+            waitForScrollQuiescence(getYCoord);
+        }
+        Assert.assertTrue(
+                "Fling scroll down was unable to go sufficiently further than non-fling scroll",
+                succeeded);
+        succeeded = false;
 
         // Test fling scrolling up.
-        NativeUiUtils.scrollNonFlingFast(NativeUiUtils.ScrollDirection.UP);
-        waitForScrollQuiescence(getYCoord);
-        endScrollPoint.set(coord.getScrollYPixInt());
-        NativeUiUtils.scrollFling(NativeUiUtils.ScrollDirection.UP);
-        CriteriaHelper.pollInstrumentationThread(
-                ()
-                        -> {
-                    return endScrollPoint.get() - coord.getScrollYPixInt()
-                            > diffMultiplier * (startScrollPoint.get() - endScrollPoint.get());
-                },
-                "Controller failed  to fling scroll up", POLL_TIMEOUT_SHORT_MS,
-                POLL_CHECK_INTERVAL_LONG_MS);
+        for (int i = 0; i < numAttempts; ++i) {
+            // Ensure we're at the bottom of the page.
+            mVrBrowserTestFramework.runJavaScriptOrFail(
+                    "window.scrollTo(0, document.documentElement.scrollHeight)",
+                    POLL_TIMEOUT_SHORT_MS);
+            waitForScrollQuiescence(getYCoord);
+            startPoint = coord.getScrollYPixInt();
+            // Perform the actual test.
+            NativeUiUtils.scrollNonFlingFast(NativeUiUtils.ScrollDirection.UP);
+            waitForScrollQuiescence(getYCoord);
+            nonFlingEndpoint = coord.getScrollYPixInt();
+            nonFlingDistance = startPoint - nonFlingEndpoint;
+            NativeUiUtils.scrollFling(NativeUiUtils.ScrollDirection.UP);
+            waitForScrollQuiescence(getYCoord);
+            if (nonFlingEndpoint - coord.getScrollYPixInt() >= diffMultiplier * nonFlingDistance) {
+                succeeded = true;
+                break;
+            }
+        }
+        Assert.assertTrue(
+                "Fling scroll up was unable to go sufficiently further than non-fling scroll",
+                succeeded);
+        succeeded = false;
 
         // Test fling scrolling right.
-        waitForScrollQuiescence(getYCoord);
-        NativeUiUtils.scrollNonFlingFast(NativeUiUtils.ScrollDirection.RIGHT);
-        waitForScrollQuiescence(getXCoord);
-        endScrollPoint.set(coord.getScrollXPixInt());
-        NativeUiUtils.scrollFling(NativeUiUtils.ScrollDirection.RIGHT);
-        CriteriaHelper.pollInstrumentationThread(
-                ()
-                        -> {
-                    return coord.getScrollXPixInt() - endScrollPoint.get()
-                            > diffMultiplier * endScrollPoint.get();
-                },
-                "Controller failed to fling scroll right", POLL_TIMEOUT_SHORT_MS,
-                POLL_CHECK_INTERVAL_LONG_MS);
-
-        // Scroll the page all the way to the right.
-        waitForScrollQuiescence(getYCoord);
-        mVrBrowserTestFramework.runJavaScriptOrFail(
-                "window.scrollTo(document.documentElement.scrollWidth, 0)", POLL_TIMEOUT_SHORT_MS);
-        waitForScrollQuiescence(getXCoord);
-        startScrollPoint.set(coord.getScrollXPixInt());
+        for (int i = 0; i < numAttempts; ++i) {
+            startPoint = coord.getScrollXPixInt();
+            NativeUiUtils.scrollNonFlingFast(NativeUiUtils.ScrollDirection.RIGHT);
+            waitForScrollQuiescence(getXCoord);
+            nonFlingEndpoint = coord.getScrollXPixInt();
+            nonFlingDistance = nonFlingEndpoint - startPoint;
+            NativeUiUtils.scrollFling(NativeUiUtils.ScrollDirection.RIGHT);
+            waitForScrollQuiescence(getXCoord);
+            if (coord.getScrollXPixInt() - nonFlingEndpoint >= diffMultiplier * nonFlingDistance) {
+                succeeded = true;
+                break;
+            }
+            // Reset to the left side to try again
+            mVrBrowserTestFramework.runJavaScriptOrFail(
+                    "window.scrollTo(0, 0)", POLL_TIMEOUT_SHORT_MS);
+            waitForScrollQuiescence(getXCoord);
+        }
+        Assert.assertTrue(
+                "Fling scroll right was unable to go sufficiently further than non-fling scroll",
+                succeeded);
+        succeeded = false;
 
         // Test fling scrolling left.
-        NativeUiUtils.scrollNonFlingFast(NativeUiUtils.ScrollDirection.LEFT);
-        waitForScrollQuiescence(getXCoord);
-        endScrollPoint.set(coord.getScrollXPixInt());
-        NativeUiUtils.scrollFling(NativeUiUtils.ScrollDirection.LEFT);
-        CriteriaHelper.pollInstrumentationThread(
-                ()
-                        -> {
-                    return endScrollPoint.get() - coord.getScrollXPixInt()
-                            > diffMultiplier * (startScrollPoint.get() - endScrollPoint.get());
-                },
-                "Controller failed to fling scroll left", POLL_TIMEOUT_SHORT_MS,
-                POLL_CHECK_INTERVAL_LONG_MS);
+        for (int i = 0; i < numAttempts; ++i) {
+            // Ensure we're on the right side of the page.
+            mVrBrowserTestFramework.runJavaScriptOrFail(
+                    "window.scrollTo(document.documentElement.scrollWidth, 0)",
+                    POLL_TIMEOUT_SHORT_MS);
+            waitForScrollQuiescence(getXCoord);
+            startPoint = coord.getScrollXPixInt();
+            // Perform the actual test.
+            NativeUiUtils.scrollNonFlingFast(NativeUiUtils.ScrollDirection.LEFT);
+            waitForScrollQuiescence(getXCoord);
+            nonFlingEndpoint = coord.getScrollXPixInt();
+            nonFlingDistance = startPoint - nonFlingEndpoint;
+            NativeUiUtils.scrollFling(NativeUiUtils.ScrollDirection.LEFT);
+            waitForScrollQuiescence(getXCoord);
+            if (nonFlingEndpoint - coord.getScrollXPixInt() >= diffMultiplier * nonFlingDistance) {
+                succeeded = true;
+                break;
+            }
+        }
+        Assert.assertTrue(
+                "Fling scroll left was unable to go sufficiently further than non-fling scroll",
+                succeeded);
     }
 
     /**
diff --git a/chrome/app/vector_icons/incognito.icon b/chrome/app/vector_icons/incognito.icon
index 8c3e5c6..29269fd 100644
--- a/chrome/app/vector_icons/incognito.icon
+++ b/chrome/app/vector_icons/incognito.icon
@@ -26,6 +26,8 @@
 R_CUBIC_TO, 2.04f, 0, 3.69f, -1.66f, 3.69f, -3.69f,
 R_CUBIC_TO, 0, -2.04f, -1.66f, -3.69f, -3.69f, -3.69f,
 CLOSE,
+NEW_PATH,
+PATH_MODE_CLEAR,
 MOVE_TO, 24, 33.23f,
 R_CUBIC_TO, 1.72f, 0, 3.15f, 1.18f, 3.56f, 2.77f,
 R_CUBIC_TO, 0.08f, -0.3f, 0.13f, -0.6f, 0.13f, -0.92f,
@@ -33,6 +35,7 @@
 R_CUBIC_TO, -2.04f, 0, -3.69f, 1.65f, -3.69f, 3.69f,
 R_CUBIC_TO, 0, 0.32f, 0.05f, 0.63f, 0.13f, 0.92f,
 R_CUBIC_TO, 0.41f, -1.59f, 1.84f, -2.77f, 3.56f, -2.77f,
+CLOSE,
 MOVE_TO, 33.29f, 20,
 R_LINE_TO, 0.06f, 0.18f,
 LINE_TO, 40.62f, 24,
@@ -75,6 +78,8 @@
 R_CUBIC_TO, 1.11f, 0, 2, -0.89f, 2, -2,
 R_CUBIC_TO, 0, -1.1f, -0.89f, -2, -2, -2,
 CLOSE,
+NEW_PATH,
+PATH_MODE_CLEAR,
 MOVE_TO, 12, 17,
 R_CUBIC_TO, 0.93f, 0, 1.71f, 0.64f, 1.93f, 1.5f,
 R_CUBIC_TO, 0.04f, -0.16f, 0.07f, -0.33f, 0.07f, -0.5f,
@@ -82,6 +87,7 @@
 R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 2,
 R_CUBIC_TO, 0, 0.17f, 0.03f, 0.34f, 0.07f, 0.5f,
 R_CUBIC_TO, 0.22f, -0.86f, 1, -1.5f, 1.93f, -1.5f,
+CLOSE,
 MOVE_TO, 16.39f, 8,
 LINE_TO, 15, 4,
 R_LINE_TO, -3, 1,
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3727f79..5d7dfa8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -438,8 +438,6 @@
     "download/download_location_dialog_type.h",
     "download/download_offline_content_provider.cc",
     "download/download_offline_content_provider.h",
-    "download/download_path_reservation_tracker.cc",
-    "download/download_path_reservation_tracker.h",
     "download/download_permission_request.cc",
     "download/download_permission_request.h",
     "download/download_prefs.cc",
@@ -3010,6 +3008,8 @@
       "search/background/ntp_background_service_factory.cc",
       "search/background/ntp_background_service_factory.h",
       "search/background/ntp_background_service_observer.h",
+      "search/background/onboarding_ntp_backgrounds.cc",
+      "search/background/onboarding_ntp_backgrounds.h",
       "search/iframe_source.cc",
       "search/iframe_source.h",
       "search/instant_service.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index dfc7893..1793b8a 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2838,6 +2838,13 @@
      kOsAll,
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillUpstreamEditableExpirationDate)},
+    {"enable-autofill-import-non-focusable-credit-card-forms",
+     flag_descriptions::kEnableAutofillImportNonFocusableCreditCardFormsName,
+     flag_descriptions::
+         kEnableAutofillImportNonFocusableCreditCardFormsDescription,
+     kOsAll,
+     FEATURE_VALUE_TYPE(
+         autofill::features::kAutofillImportNonFocusableCreditCardForms)},
     {"enable-autofill-local-card-migration-show-feedback",
      flag_descriptions::kEnableAutofillLocalCardMigrationShowFeedbackName,
      flag_descriptions::
diff --git a/chrome/browser/accessibility/accessibility_ui.cc b/chrome/browser/accessibility/accessibility_ui.cc
index 98cf266e..92afb2b 100644
--- a/chrome/browser/accessibility/accessibility_ui.cc
+++ b/chrome/browser/accessibility/accessibility_ui.cc
@@ -326,6 +326,7 @@
     base::ListValue request_args;
     request_args.Append(std::make_unique<base::Value>(process_id_str));
     request_args.Append(std::make_unique<base::Value>(route_id_str));
+    request_args.Append(std::make_unique<base::Value>("showTree"));
     RequestWebContentsTree(&request_args);
   } else {
     // Call accessibility.showTree without a 'tree' field so the row's
diff --git a/chrome/browser/android/download/chrome_duplicate_download_infobar_delegate.cc b/chrome/browser/android/download/chrome_duplicate_download_infobar_delegate.cc
index bbd6620..8f8302b 100644
--- a/chrome/browser/android/download/chrome_duplicate_download_infobar_delegate.cc
+++ b/chrome/browser/android/download/chrome_duplicate_download_infobar_delegate.cc
@@ -11,9 +11,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/android/download/download_controller.h"
-#include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/ui/android/infobars/duplicate_download_infobar.h"
+#include "components/download/public/common/download_path_reservation_tracker.h"
 #include "components/infobars/core/infobar.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -23,10 +23,10 @@
 
 void CreateNewFileDone(
     const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback,
-    PathValidationResult result,
+    download::PathValidationResult result,
     const base::FilePath& target_path) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (result == PathValidationResult::SUCCESS)
+  if (result == download::PathValidationResult::SUCCESS)
     callback.Run(DownloadConfirmationResult::CONFIRMED, target_path);
   else
     callback.Run(DownloadConfirmationResult::FAILED, base::FilePath());
@@ -91,12 +91,10 @@
     return true;
   }
 
-  DownloadPathReservationTracker::GetReservedPath(
-      download_item_,
-      file_path_,
-      download_dir,
-      true,
-      DownloadPathReservationTracker::UNIQUIFY,
+  download::DownloadPathReservationTracker::GetReservedPath(
+      download_item_, file_path_, download_dir,
+      base::FilePath(), /* fallback_directory */
+      true, download::DownloadPathReservationTracker::UNIQUIFY,
       base::Bind(&CreateNewFileDone, file_selected_callback_));
   RecordDuplicateInfobarType(INFOBAR_CREATE_NEW_FILE);
   return true;
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index a9fdb4e..5abf70961 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -16,6 +16,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/enterprise_util.h"
 #include "base/environment.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
@@ -500,7 +501,7 @@
   // be used to better identify whether crashes are from enterprise users.
   static crash_reporter::CrashKeyString<4> is_enterprise_managed(
       "is-enterprise-managed");
-  is_enterprise_managed.Set(base::win::IsEnterpriseManaged() ? "yes" : "no");
+  is_enterprise_managed.Set(base::IsMachineExternallyManaged() ? "yes" : "no");
 
   // Set crash keys containing the registry values used to determine Chrome's
   // update channel at process startup; see https://crbug.com/579504.
@@ -539,7 +540,7 @@
   // What truly controls if the blocking is enabled is the presence of the
   // module blacklist cache file. This means that to disable the feature, the
   // cache must be deleted and the browser relaunched.
-  if (base::win::IsEnterpriseManaged() ||
+  if (base::IsMachineExternallyManaged() ||
       !ModuleDatabase::IsThirdPartyBlockingPolicyEnabled() ||
       !base::FeatureList::IsEnabled(features::kThirdPartyModulesBlocking))
     ThirdPartyConflictsManager::DisableThirdPartyModuleBlocking(
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 167a386..83c7c1d 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -233,6 +233,7 @@
     "//ui/aura",
     "//ui/base",
     "//ui/base/idle",
+    "//ui/base/user_activity",
     "//ui/chromeos",
     "//ui/chromeos/events",
     "//ui/compositor",
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc
index 53d13b8..ed74869 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc
@@ -173,8 +173,9 @@
 
   // Finish the migration by removing the old app now that it has been replaced.
   setup_controller_->RemoveApp(
-      GetAndroidMessagesURLOld(),
-      GetAndroidMessagesURLOld(true /* use_install_url */),
+      GetAndroidMessagesURLOld() /* app_url */,
+      GetAndroidMessagesURLOld(true /* use_install_url */) /* install_url */,
+      GetAndroidMessagesURL() /* migrated_to_app_url */,
       base::BindOnce(&AndroidSmsAppManagerImpl::OnRemoveOldAppResult,
                      weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc
index d8fcd9c..086cfc1 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc
@@ -294,6 +294,7 @@
       GetAndroidMessagesURLOld() /* expected_app_url */,
       GetAndroidMessagesURLOld(
           true /* use_install_url */) /* expected_install_url */,
+      GetAndroidMessagesURL() /* expected_migrated_to_app_url */,
       true /* success */);
   EXPECT_EQ(1u, test_observer()->num_installed_app_url_changed_events());
 }
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller.h b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller.h
index ef6049d..e287c30 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller.h
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller.h
@@ -25,10 +25,11 @@
 
   using SuccessCallback = base::OnceCallback<void(bool)>;
 
-  // Performs the setup process for the app at |url|, which includes:
+  // Performs the setup process for the app at |app_url|, which includes:
   //   (1) Installing the PWA,
   //   (2) Granting permission for the PWA to show notifications, and
-  //   (3) Setting a cookie which defaults the PWA to remember this computer.
+  //   (3) Removing previously set migration cookie, if any.
+  //   (4) Setting a cookie which defaults the PWA to remember this computer.
   // The |app_url|  parameter should have the root URL of the app to install
   // and should be the same as the service worker scope
   // The |install_url| parameter is the url to install the app from and cannot
@@ -37,8 +38,8 @@
                         const GURL& install_url,
                         SuccessCallback callback) = 0;
 
-  // Returns the extension for the PWA at |url|; if no PWA exists, null is
-  // returned.
+  // Returns the extension for the PWA at |install_url|; if no PWA exists, null
+  // is returned.
   virtual const extensions::Extension* GetPwa(const GURL& install_url) = 0;
 
   // Deletes the cookie which causes the PWA to remember this computer by
@@ -49,10 +50,16 @@
       const GURL& app_url,
       SuccessCallback callback) = 0;
 
-  // Uninstalls the app at |url| and deletes relevant cookies from the setup
-  // process.
+  // Uninstalls the app at |app_url| and deletes relevant cookies from the setup
+  // process. This also sets a migration cookie that allows the client to start
+  // redirecting users to the new domain.
+  // The |app_url| parameter should have the root URL of the app to install
+  // and should be the same as the service worker scope
+  // The |install_url| parameter is the url to that was used to install the app.
+  // The |migrated_to_app_url| should be the url that the PWA was migrated to.
   virtual void RemoveApp(const GURL& app_url,
                          const GURL& install_url,
+                         const GURL& migrated_to_app_url,
                          SuccessCallback callback) = 0;
 
  private:
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
index 1e6be1e..1973dd1 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
@@ -32,6 +32,7 @@
 namespace {
 
 const char kDefaultToPersistCookieName[] = "default_to_persist";
+const char kMigrationCookieName[] = "cros_migrated_to";
 const char kDefaultToPersistCookieValue[] = "true";
 
 }  // namespace
@@ -88,7 +89,8 @@
               false /* http_only */, net::CookieSameSite::STRICT_MODE,
               net::COOKIE_PRIORITY_DEFAULT),
           true /* secure_source */, false /* modify_http_only */,
-          base::BindOnce(&AndroidSmsAppSetupControllerImpl::OnSetCookieResult,
+          base::BindOnce(&AndroidSmsAppSetupControllerImpl::
+                             OnSetRememberDeviceByDefaultCookieResult,
                          weak_ptr_factory_.GetWeakPtr(), app_url, install_url,
                          std::move(callback)));
 }
@@ -111,14 +113,17 @@
   pwa_delegate_->GetCookieManager(app_url, profile_)
       ->DeleteCookies(
           std::move(filter),
-          base::BindOnce(
-              &AndroidSmsAppSetupControllerImpl::OnDeleteCookiesResult,
-              weak_ptr_factory_.GetWeakPtr(), app_url, std::move(callback)));
+          base::BindOnce(&AndroidSmsAppSetupControllerImpl::
+                             OnDeleteRememberDeviceByDefaultCookieResult,
+                         weak_ptr_factory_.GetWeakPtr(), app_url,
+                         std::move(callback)));
 }
 
-void AndroidSmsAppSetupControllerImpl::RemoveApp(const GURL& app_url,
-                                                 const GURL& install_url,
-                                                 SuccessCallback callback) {
+void AndroidSmsAppSetupControllerImpl::RemoveApp(
+    const GURL& app_url,
+    const GURL& install_url,
+    const GURL& migrated_to_app_url,
+    SuccessCallback callback) {
   // If there is no app installed at |url|, there is nothing more to do.
   if (!pwa_delegate_->GetPwaForUrl(install_url, profile_)) {
     PA_LOG(VERBOSE) << "AndroidSmsAppSetupControllerImpl::RemoveApp(): No app "
@@ -142,24 +147,45 @@
       std::vector<GURL>{install_url},
       base::BindRepeating(
           &AndroidSmsAppSetupControllerImpl::OnAppUninstallResult,
-          weak_ptr_factory_.GetWeakPtr(), id, app_url));
+          weak_ptr_factory_.GetWeakPtr(), id, app_url, migrated_to_app_url));
 }
 
-void AndroidSmsAppSetupControllerImpl::OnSetCookieResult(
+void AndroidSmsAppSetupControllerImpl::OnSetRememberDeviceByDefaultCookieResult(
     const GURL& app_url,
     const GURL& install_url,
     SuccessCallback callback,
     bool succeeded) {
   if (!succeeded) {
-    PA_LOG(WARNING) << "AndroidSmsAppSetupControllerImpl::"
-                    << "OnSetCookieResult(): Failed to set "
-                    << "DefaultToPersist cookie at " << app_url
-                    << ". Proceeding with installation request.";
+    PA_LOG(WARNING)
+        << "AndroidSmsAppSetupControllerImpl::"
+        << "OnSetRememberDeviceByDefaultCookieResult(): Failed to set "
+        << "DefaultToPersist cookie at " << app_url << ". Proceeding "
+        << "to remove migration cookie.";
   }
 
+  // Delete migration cookie in case it was set by a previous RemoveApp call.
+  network::mojom::CookieDeletionFilterPtr filter(
+      network::mojom::CookieDeletionFilter::New());
+  filter->url = app_url;
+  filter->cookie_name = kMigrationCookieName;
+  pwa_delegate_->GetCookieManager(app_url, profile_)
+      ->DeleteCookies(
+          std::move(filter),
+          base::BindOnce(
+              &AndroidSmsAppSetupControllerImpl::OnDeleteMigrationCookieResult,
+              weak_ptr_factory_.GetWeakPtr(), app_url, install_url,
+              std::move(callback)));
+}
+
+void AndroidSmsAppSetupControllerImpl::OnDeleteMigrationCookieResult(
+    const GURL& app_url,
+    const GURL& install_url,
+    SuccessCallback callback,
+    uint32_t num_deleted) {
   // If the app is already installed at |url|, there is nothing more to do.
   if (pwa_delegate_->GetPwaForUrl(install_url, profile_)) {
-    PA_LOG(VERBOSE) << "AndroidSmsAppSetupControllerImpl::OnSetCookieResult(): "
+    PA_LOG(VERBOSE) << "AndroidSmsAppSetupControllerImpl::"
+                    << "OnDeleteMigrationCookieResult():"
                     << "App is already installed at " << install_url
                     << "; skipping setup process.";
     std::move(callback).Run(true /* success */);
@@ -216,6 +242,7 @@
 void AndroidSmsAppSetupControllerImpl::OnAppUninstallResult(
     const base::UnguessableToken& id,
     const GURL& app_url,
+    const GURL& migrated_to_app_url,
     const GURL& install_url,
     bool succeeded) {
   UMA_HISTOGRAM_BOOLEAN("AndroidSms.PWAUninstallationResult", succeeded);
@@ -234,18 +261,49 @@
     return;
   }
 
+  // Set migration cookie on the client for which the PWA was just uninstalled.
+  // The client checks for this cookie to redirect users to the new domain. This
+  // prevents unwanted connection stealing between old and new clients should
+  // the user try to open old client.
+  pwa_delegate_->GetCookieManager(app_url, profile_)
+      ->SetCanonicalCookie(
+          *net::CanonicalCookie::CreateSanitizedCookie(
+              app_url, kMigrationCookieName, migrated_to_app_url.GetContent(),
+              std::string() /* domain */, std::string() /* path */,
+              base::Time::Now() /* creation_time */,
+              base::Time() /* expiration_time */,
+              base::Time::Now() /* last_access_time */, true /* secure */,
+              false /* http_only */, net::CookieSameSite::STRICT_MODE,
+              net::COOKIE_PRIORITY_DEFAULT),
+          true /* secure_source */, false /* modify_http_only */,
+          base::BindOnce(
+              &AndroidSmsAppSetupControllerImpl::OnSetMigrationCookieResult,
+              weak_ptr_factory_.GetWeakPtr(), app_url, std::move(callback)));
+}
+
+void AndroidSmsAppSetupControllerImpl::OnSetMigrationCookieResult(
+    const GURL& app_url,
+    SuccessCallback callback,
+    bool succeeded) {
+  if (!succeeded) {
+    PA_LOG(ERROR)
+        << "AndroidSmsAppSetupControllerImpl::OnSetMigrationCookieResult(): "
+        << "Failed to set migration cookie for " << app_url << ". Proceeding "
+        << "to remove DefaultToPersist cookie.";
+  }
+
   DeleteRememberDeviceByDefaultCookie(app_url, std::move(callback));
 }
 
-void AndroidSmsAppSetupControllerImpl::OnDeleteCookiesResult(
-    const GURL& app_url,
-    SuccessCallback callback,
-    uint32_t num_deleted) {
+void AndroidSmsAppSetupControllerImpl::
+    OnDeleteRememberDeviceByDefaultCookieResult(const GURL& app_url,
+                                                SuccessCallback callback,
+                                                uint32_t num_deleted) {
   if (num_deleted != 1u) {
     PA_LOG(WARNING) << "AndroidSmsAppSetupControllerImpl::"
-                    << "OnDeleteCookiesResult(): Tried to delete a single "
-                    << "cookie at " << app_url << ", but " << num_deleted << " "
-                    << "cookies were deleted.";
+                    << "OnDeleteRememberDeviceByDefaultCookieResult(): "
+                    << "Tried to delete a single cookie at " << app_url
+                    << ", but " << num_deleted << " cookies were deleted.";
   }
 
   // Even if an unexpected number of cookies was deleted, consider this a
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.h b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.h
index bbf8fbc..51302bb 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.h
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.h
@@ -62,23 +62,33 @@
                                            SuccessCallback callback) override;
   void RemoveApp(const GURL& app_url,
                  const GURL& install_url,
+                 const GURL& migrated_to_app_url,
                  SuccessCallback callback) override;
 
-  void OnSetCookieResult(const GURL& app_url,
-                         const GURL& install_url,
-                         SuccessCallback callback,
-                         bool succeeded);
+  void OnSetRememberDeviceByDefaultCookieResult(const GURL& app_url,
+                                                const GURL& install_url,
+                                                SuccessCallback callback,
+                                                bool succeeded);
+  void OnSetMigrationCookieResult(const GURL& app_url,
+                                  SuccessCallback callback,
+                                  bool succeeded);
+
   void OnAppInstallResult(SuccessCallback callback,
                           const GURL& app_url,
                           const GURL& install_url,
                           web_app::InstallResultCode code);
   void OnAppUninstallResult(const base::UnguessableToken& id,
                             const GURL& app_url,
+                            const GURL& migrated_to_app_url,
                             const GURL& install_url,
                             bool succeeded);
-  void OnDeleteCookiesResult(const GURL& app_url,
-                             SuccessCallback callback,
-                             uint32_t num_deleted);
+  void OnDeleteRememberDeviceByDefaultCookieResult(const GURL& app_url,
+                                                   SuccessCallback callback,
+                                                   uint32_t num_deleted);
+  void OnDeleteMigrationCookieResult(const GURL& app_url,
+                                     const GURL& install_url,
+                                     SuccessCallback callback,
+                                     uint32_t num_deleted);
 
   void SetPwaDelegateForTesting(std::unique_ptr<PwaDelegate> test_pwa_delegate);
 
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
index 9acda9ef..4553f0b 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
@@ -59,6 +59,7 @@
 
   void InvokePendingSetCanonicalCookieCallback(
       const std::string& expected_cookie_name,
+      const std::string& expected_cookie_value,
       bool expected_secure_source,
       bool expected_modify_http_only,
       bool success) {
@@ -67,6 +68,7 @@
     set_canonical_cookie_calls_.erase(set_canonical_cookie_calls_.begin());
 
     EXPECT_EQ(expected_cookie_name, std::get<0>(params).Name());
+    EXPECT_EQ(expected_cookie_value, std::get<0>(params).Value());
     EXPECT_EQ(expected_secure_source, std::get<1>(params));
     EXPECT_EQ(expected_modify_http_only, std::get<2>(params));
 
@@ -223,9 +225,13 @@
 
     fake_cookie_manager_->InvokePendingSetCanonicalCookieCallback(
         "default_to_persist" /* expected_cookie_name */,
-        true /* expected_secure_source */,
+        "true" /* expected_cookie_value */, true /* expected_secure_source */,
         false /* expected_modify_http_only */, true /* success */);
 
+    fake_cookie_manager_->InvokePendingDeleteCookiesCallback(
+        app_url, "cros_migrated_to" /* expected_cookie_name */,
+        true /* success */);
+
     // If the PWA was not already installed at the URL, SetUpApp() should
     // install it.
     if (!test_pwa_delegate_->GetPwaForUrl(install_url, &profile_)) {
@@ -267,6 +273,7 @@
 
   void CallRemoveApp(const GURL& app_url,
                      const GURL& install_url,
+                     const GURL& migrated_to_app_url,
                      size_t num_expected_app_uninstalls) {
     const auto& uninstall_requests =
         test_pending_app_manager_->uninstall_requests();
@@ -276,7 +283,7 @@
     base::HistogramTester histogram_tester;
 
     setup_controller_->RemoveApp(
-        app_url, install_url,
+        app_url, install_url, migrated_to_app_url,
         base::BindOnce(&AndroidSmsAppSetupControllerImplTest::OnRemoveAppResult,
                        base::Unretained(this), run_loop.QuitClosure()));
 
@@ -287,6 +294,12 @@
                 uninstall_requests.size());
       EXPECT_EQ(install_url, uninstall_requests.back());
 
+      fake_cookie_manager_->InvokePendingSetCanonicalCookieCallback(
+          "cros_migrated_to" /* expected_cookie_name */,
+          migrated_to_app_url.GetContent() /* expected_cookie_value */,
+          true /* expected_secure_source */,
+          false /* expected_modify_http_only */, true /* success */);
+
       fake_cookie_manager_->InvokePendingDeleteCookiesCallback(
           app_url, "default_to_persist" /* expected_cookie_name */,
           true /* success */);
@@ -381,6 +394,7 @@
                1u /* num_expected_app_installs */);
   test_pwa_delegate()->SetHasPwa(GURL(kTestInstallUrl1), true);
   CallRemoveApp(GURL(kTestUrl1), GURL(kTestInstallUrl1),
+                GURL(kTestUrl2) /* migrated_to_app_url */,
                 1u /* num_expected_app_uninstalls */);
   test_pwa_delegate()->SetHasPwa(GURL(kTestInstallUrl1), false);
 
@@ -389,6 +403,7 @@
                1u /* num_expected_app_installs */);
   test_pwa_delegate()->SetHasPwa(GURL(kTestInstallUrl1), true);
   CallRemoveApp(GURL(kTestUrl1), GURL(kTestInstallUrl1),
+                GURL(kTestUrl2) /* migrated_to_app_url */,
                 1u /* num_expected_app_uninstalls */);
   test_pwa_delegate()->SetHasPwa(GURL(kTestInstallUrl1), false);
 }
@@ -396,6 +411,7 @@
 TEST_F(AndroidSmsAppSetupControllerImplTest, RemoveApp_NoInstalledApp) {
   // Do not have an installed app before attempting to remove it.
   CallRemoveApp(GURL(kTestUrl1), GURL(kTestInstallUrl1),
+                GURL(kTestUrl2) /* migrated_to_app_url */,
                 0u /* num_expected_app_uninstalls */);
 }
 
diff --git a/chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.cc b/chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.cc
index e81d3be8..542e22c 100644
--- a/chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.cc
+++ b/chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.cc
@@ -96,6 +96,7 @@
 void FakeAndroidSmsAppSetupController::CompleteRemoveAppRequest(
     const GURL& expected_app_url,
     const GURL& expected_install_url,
+    const GURL& expected_migrated_to_app_url,
     bool should_succeed) {
   DCHECK(!pending_remove_app_requests_.empty());
 
@@ -103,17 +104,18 @@
   pending_remove_app_requests_.erase(pending_remove_app_requests_.begin());
   DCHECK_EQ(expected_app_url, std::get<0>(*request));
   DCHECK_EQ(expected_install_url, std::get<1>(*request));
+  DCHECK_EQ(expected_migrated_to_app_url, std::get<2>(*request));
 
   if (should_succeed)
     SetAppAtUrl(expected_install_url, base::nullopt /* id_for_app */);
 
-  std::move(std::get<2>(*request)).Run(should_succeed);
+  std::move(std::get<3>(*request)).Run(should_succeed);
 }
 
 void FakeAndroidSmsAppSetupController::SetUpApp(const GURL& app_url,
                                                 const GURL& install_url,
                                                 SuccessCallback callback) {
-  pending_set_up_app_requests_.push_back(std::make_unique<AppRequestData>(
+  pending_set_up_app_requests_.push_back(std::make_unique<SetUpAppData>(
       app_url, install_url, std::move(callback)));
 }
 
@@ -129,14 +131,16 @@
     const GURL& app_url,
     SuccessCallback callback) {
   pending_delete_cookie_requests_.push_back(
-      std::make_unique<RequestData>(app_url, std::move(callback)));
+      std::make_unique<DeleteCookieData>(app_url, std::move(callback)));
 }
 
-void FakeAndroidSmsAppSetupController::RemoveApp(const GURL& app_url,
-                                                 const GURL& install_url,
-                                                 SuccessCallback callback) {
-  pending_remove_app_requests_.push_back(std::make_unique<AppRequestData>(
-      app_url, install_url, std::move(callback)));
+void FakeAndroidSmsAppSetupController::RemoveApp(
+    const GURL& app_url,
+    const GURL& install_url,
+    const GURL& migrated_to_app_url,
+    SuccessCallback callback) {
+  pending_remove_app_requests_.push_back(std::make_unique<RemoveAppData>(
+      app_url, install_url, migrated_to_app_url, std::move(callback)));
 }
 
 }  // namespace android_sms
diff --git a/chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.h b/chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.h
index 9e9e7ba..e1823ba 100644
--- a/chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.h
+++ b/chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.h
@@ -67,6 +67,7 @@
   // app will remain in place.
   void CompleteRemoveAppRequest(const GURL& expected_app_url,
                                 const GURL& expected_install_url,
+                                const GURL& expected_migrated_to_app_url,
                                 bool success);
 
  private:
@@ -79,14 +80,17 @@
                                            SuccessCallback callback) override;
   void RemoveApp(const GURL& app_url,
                  const GURL& install_url,
+                 const GURL& migrated_to_app_url,
                  SuccessCallback callback) override;
 
-  using AppRequestData = std::tuple<GURL, GURL, SuccessCallback>;
-  using RequestData = std::pair<GURL, SuccessCallback>;
+  using SetUpAppData = std::tuple<GURL, GURL, SuccessCallback>;
+  std::list<std::unique_ptr<SetUpAppData>> pending_set_up_app_requests_;
 
-  std::list<std::unique_ptr<RequestData>> pending_delete_cookie_requests_;
-  std::list<std::unique_ptr<AppRequestData>> pending_set_up_app_requests_;
-  std::list<std::unique_ptr<AppRequestData>> pending_remove_app_requests_;
+  using RemoveAppData = std::tuple<GURL, GURL, GURL, SuccessCallback>;
+  std::list<std::unique_ptr<RemoveAppData>> pending_remove_app_requests_;
+
+  using DeleteCookieData = std::pair<GURL, SuccessCallback>;
+  std::list<std::unique_ptr<DeleteCookieData>> pending_delete_cookie_requests_;
 
   base::flat_map<GURL, AppMetadata> install_url_to_metadata_map_;
 
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index c3c31615..d11c511b 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -1253,7 +1253,7 @@
   const std::string& locale = startup_manifest->initial_locale_default();
 
   const std::string& layout = startup_manifest->keyboard_layout();
-  VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout;
+  VLOG(1) << "Initial locale: " << locale << " keyboard layout: " << layout;
 
   // Determine keyboard layout from OEM customization (if provided) or
   // initial locale and save it in preferences.
diff --git a/chrome/browser/chromeos/network_change_manager_client.cc b/chrome/browser/chromeos/network_change_manager_client.cc
index 214c8f1..29de915 100644
--- a/chrome/browser/chromeos/network_change_manager_client.cc
+++ b/chrome/browser/chromeos/network_change_manager_client.cc
@@ -5,15 +5,14 @@
 #include "chrome/browser/chromeos/network_change_manager_client.h"
 
 #include "base/bind.h"
-#include "base/feature_list.h"
 #include "base/strings/stringprintf.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/network/network_event_log.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "content/public/browser/network_service_instance.h"
+#include "content/public/common/network_service_util.h"
 #include "net/base/network_change_notifier_chromeos.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 
 namespace chromeos {
@@ -26,7 +25,7 @@
   DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
   NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
 
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+  if (content::IsOutOfProcessNetworkService())
     ConnectToNetworkChangeManager();
 
   // Update initial connection state.
@@ -38,7 +37,7 @@
   NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
                                                                  FROM_HERE);
   DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
-};
+}
 
 void NetworkChangeManagerClient::SuspendDone(
     const base::TimeDelta& sleep_duration) {
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index 7426d1d..31d1b99 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -35,7 +35,7 @@
 #include "services/service_manager/public/cpp/connector.h"
 
 #if defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 #include "chrome/install_static/install_util.h"
 #include "chrome/installer/util/google_update_settings.h"
 #endif
@@ -160,7 +160,7 @@
 std::string ChromeConfigurator::GetDownloadPreference() const {
 #if defined(OS_WIN)
   // This group policy is supported only on Windows and only for enterprises.
-  return base::win::IsEnterpriseManaged()
+  return base::IsMachineExternallyManaged()
              ? base::SysWideToUTF8(
                    GoogleUpdateSettings::GetDownloadPreference())
              : std::string();
diff --git a/chrome/browser/conflicts/module_database_win.cc b/chrome/browser/conflicts/module_database_win.cc
index 14d24af3..ba3560c 100644
--- a/chrome/browser/conflicts/module_database_win.cc
+++ b/chrome/browser/conflicts/module_database_win.cc
@@ -14,9 +14,9 @@
 #include "content/public/browser/browser_task_traits.h"
 
 #if defined(GOOGLE_CHROME_BUILD)
+#include "base/enterprise_util.h"
 #include "base/feature_list.h"
 #include "base/task/post_task.h"
-#include "base/win/win_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/conflicts/incompatible_applications_updater_win.h"
 #include "chrome/browser/conflicts/module_load_attempt_log_listener_win.h"
@@ -379,7 +379,7 @@
   // the command-line.
   // TODO(pmonette): Move IAttachmentExecute::Save() to a utility process and
   //                 remove this.
-  if (base::win::IsEnterpriseManaged() &&
+  if (base::IsMachineExternallyManaged() &&
       !AreThirdPartyFeaturesEnabledViaCommandLine()) {
     return;
   }
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
index 7a06431..78756e342 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
@@ -105,7 +105,13 @@
     std::unique_ptr<base::DictionaryValue> command_dict,
     const std::string& message,
     NotHandledCallback callback) {
-  DCHECK(sessions_.find(client) != sessions_.end());
+  if (sessions_.find(client) == sessions_.end()) {
+    std::move(callback).Run(std::move(command_dict), message);
+    // This should not happen, but happens. NOTREACHED tries to get
+    // a repro in some test.
+    NOTREACHED();
+    return;
+  }
   sessions_[client]->HandleCommand(std::move(command_dict), message,
                                    std::move(callback));
 }
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 2f2061b1..a48056ab 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -15,6 +15,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/path_service.h"
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -31,7 +32,6 @@
 #include "chrome/browser/download/download_history.h"
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/download/download_location_dialog_type.h"
-#include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/download/download_request_limiter.h"
 #include "chrome/browser/download/download_stats.h"
@@ -48,6 +48,7 @@
 #include "chrome/common/buildflags.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/pdf_util.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/safe_browsing/file_type_policies.h"
@@ -93,8 +94,10 @@
 #endif
 
 using content::BrowserThread;
-using download::DownloadItem;
 using content::DownloadManager;
+using download::DownloadItem;
+using download::DownloadPathReservationTracker;
+using download::PathValidationResult;
 using safe_browsing::DownloadFileType;
 using safe_browsing::DownloadProtectionService;
 
@@ -814,13 +817,11 @@
     return;
   }
 #endif
+  base::FilePath document_dir;
+  base::PathService::Get(chrome::DIR_USER_DOCUMENTS, &document_dir);
   DownloadPathReservationTracker::GetReservedPath(
-      download,
-      virtual_path,
-      download_prefs_->DownloadPath(),
-      create_directory,
-      conflict_action,
-      callback);
+      download, virtual_path, download_prefs_->DownloadPath(), document_dir,
+      create_directory, conflict_action, callback);
 }
 
 void ChromeDownloadManagerDelegate::RequestConfirmation(
@@ -882,7 +883,8 @@
 
       gfx::NativeWindow native_window = web_contents->GetTopLevelNativeWindow();
       DownloadPathReservationTracker::GetReservedPath(
-          download, suggested_path, download_dir, true,
+          download, suggested_path, download_dir,
+          base::FilePath() /* fallback_directory */, true,
           DownloadPathReservationTracker::UNIQUIFY,
           base::BindRepeating(
               &ChromeDownloadManagerDelegate::GenerateUniqueFileNameDone,
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 967206d..5399d88 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -19,13 +19,13 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
 #include "build/build_config.h"
-#include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "chrome/browser/download/download_target_determiner_delegate.h"
 #include "chrome/browser/download/download_target_info.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
 #include "components/download/public/common/download_danger_type.h"
 #include "components/download/public/common/download_item.h"
+#include "components/download/public/common/download_path_reservation_tracker.h"
 #include "content/public/browser/download_manager_delegate.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -148,7 +148,8 @@
       download::DownloadItem* download,
       const base::FilePath& virtual_path,
       bool create_directory,
-      DownloadPathReservationTracker::FilenameConflictAction conflict_action,
+      download::DownloadPathReservationTracker::FilenameConflictAction
+          conflict_action,
       const ReservedPathCallback& callback) override;
   void RequestConfirmation(download::DownloadItem* download,
                            const base::FilePath& suggested_virtual_path,
@@ -243,7 +244,7 @@
   void GenerateUniqueFileNameDone(
       gfx::NativeWindow native_window,
       const DownloadTargetDeterminerDelegate::ConfirmationCallback& callback,
-      PathValidationResult result,
+      download::PathValidationResult result,
       const base::FilePath& target_path);
 #endif
 
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index 8e9e029..bd41a492 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -62,6 +62,11 @@
 #include "components/infobars/core/infobar_manager.h"
 #endif
 
+using download::DownloadItem;
+using download::DownloadPathReservationTracker;
+using download::PathValidationResult;
+using safe_browsing::DownloadFileType;
+using ::testing::_;
 using ::testing::AnyNumber;
 using ::testing::AtMost;
 using ::testing::DoAll;
@@ -74,9 +79,6 @@
 using ::testing::ReturnRefOfCopy;
 using ::testing::SetArgPointee;
 using ::testing::WithArg;
-using ::testing::_;
-using download::DownloadItem;
-using safe_browsing::DownloadFileType;
 
 namespace {
 
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 816eed3..a820398 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -1228,7 +1228,7 @@
   CheckDownload(browser(), file, file);
 }
 
-#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(OS_WIN)
 // Download a file and confirm that the file is correctly quarantined.
 //
 // TODO(asanka): We should enable the test on Mac as well, but currently
@@ -1252,9 +1252,7 @@
   EXPECT_TRUE(download::IsFileQuarantined(downloaded_file, url, GURL()));
   CheckDownload(browser(), file, file);
 }
-#endif
 
-#if defined(OS_WIN)
 // A couple of Windows specific tests to make sure we respect OS specific
 // restrictions on Mark-Of-The-Web can be applied. While Chrome doesn't directly
 // apply these policies, Chrome still needs to make sure the correct APIs are
diff --git a/chrome/browser/download/download_stats.cc b/chrome/browser/download/download_stats.cc
index f14f6c3..ce4b6e6 100644
--- a/chrome/browser/download/download_stats.cc
+++ b/chrome/browser/download/download_stats.cc
@@ -49,14 +49,14 @@
   }
 }
 
-void RecordDownloadPathValidation(PathValidationResult result,
+void RecordDownloadPathValidation(download::PathValidationResult result,
                                   bool is_transient) {
   if (is_transient) {
     UMA_HISTOGRAM_ENUMERATION("Download.PathValidationResult.Transient", result,
-                              PathValidationResult::COUNT);
+                              download::PathValidationResult::COUNT);
   } else {
     UMA_HISTOGRAM_ENUMERATION("Download.PathValidationResult.UserDownload",
-                              result, PathValidationResult::COUNT);
+                              result, download::PathValidationResult::COUNT);
   }
 }
 
diff --git a/chrome/browser/download/download_stats.h b/chrome/browser/download/download_stats.h
index 84b3963..17b31f4 100644
--- a/chrome/browser/download/download_stats.h
+++ b/chrome/browser/download/download_stats.h
@@ -6,8 +6,8 @@
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STATS_H_
 
 #include "build/build_config.h"
-#include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "components/download/public/common/download_danger_type.h"
+#include "components/download/public/common/download_path_reservation_tracker.h"
 
 // Used for counting UMA stats. Similar to content's
 // download_stats::DownloadCountTypes but from the chrome layer.
@@ -114,7 +114,7 @@
                                   bool is_transient);
 
 // Record path validation result.
-void RecordDownloadPathValidation(PathValidationResult result,
+void RecordDownloadPathValidation(download::PathValidationResult result,
                                   bool is_transient);
 
 // Records drags of completed downloads from the shelf. Used in UMA, do not
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc
index 78c91f1..25de150 100644
--- a/chrome/browser/download/download_target_determiner.cc
+++ b/chrome/browser/download/download_target_determiner.cc
@@ -58,6 +58,7 @@
 
 using content::BrowserThread;
 using download::DownloadItem;
+using download::DownloadPathReservationTracker;
 using safe_browsing::DownloadFileType;
 
 namespace {
@@ -368,7 +369,7 @@
 }
 
 void DownloadTargetDeterminer::ReserveVirtualPathDone(
-    PathValidationResult result,
+    download::PathValidationResult result,
     const base::FilePath& path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DVLOG(20) << "Reserved path: " << path.AsUTF8Unsafe()
@@ -379,45 +380,45 @@
   if (download_->IsTransient()) {
     DCHECK_EQ(DownloadConfirmationReason::NONE, confirmation_reason_)
         << "Transient download should not ask the user for confirmation.";
-    DCHECK(result != PathValidationResult::CONFLICT)
+    DCHECK(result != download::PathValidationResult::CONFLICT)
         << "Transient download"
            "should always overwrite the file.";
     switch (result) {
-      case PathValidationResult::PATH_NOT_WRITABLE:
-      case PathValidationResult::NAME_TOO_LONG:
-      case PathValidationResult::CONFLICT:
+      case download::PathValidationResult::PATH_NOT_WRITABLE:
+      case download::PathValidationResult::NAME_TOO_LONG:
+      case download::PathValidationResult::CONFLICT:
         ScheduleCallbackAndDeleteSelf(
             download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
         return;
-      case PathValidationResult::SUCCESS:
-      case PathValidationResult::SAME_AS_SOURCE:
+      case download::PathValidationResult::SUCCESS:
+      case download::PathValidationResult::SAME_AS_SOURCE:
         DCHECK_EQ(virtual_path_, path) << "Transient download path should not"
                                           "be changed.";
         break;
-      case PathValidationResult::COUNT:
+      case download::PathValidationResult::COUNT:
         NOTREACHED();
     }
   } else {
     virtual_path_ = path;
 
     switch (result) {
-      case PathValidationResult::SUCCESS:
-      case PathValidationResult::SAME_AS_SOURCE:
+      case download::PathValidationResult::SUCCESS:
+      case download::PathValidationResult::SAME_AS_SOURCE:
         break;
 
-      case PathValidationResult::PATH_NOT_WRITABLE:
+      case download::PathValidationResult::PATH_NOT_WRITABLE:
         confirmation_reason_ =
             DownloadConfirmationReason::TARGET_PATH_NOT_WRITEABLE;
         break;
 
-      case PathValidationResult::NAME_TOO_LONG:
+      case download::PathValidationResult::NAME_TOO_LONG:
         confirmation_reason_ = DownloadConfirmationReason::NAME_TOO_LONG;
         break;
 
-      case PathValidationResult::CONFLICT:
+      case download::PathValidationResult::CONFLICT:
         confirmation_reason_ = DownloadConfirmationReason::TARGET_CONFLICT;
         break;
-      case PathValidationResult::COUNT:
+      case download::PathValidationResult::COUNT:
         NOTREACHED();
     }
   }
diff --git a/chrome/browser/download/download_target_determiner.h b/chrome/browser/download/download_target_determiner.h
index d3f49be1..7ede9b1d 100644
--- a/chrome/browser/download/download_target_determiner.h
+++ b/chrome/browser/download/download_target_determiner.h
@@ -14,12 +14,12 @@
 #include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "build/build_config.h"
-#include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "chrome/browser/download/download_target_determiner_delegate.h"
 #include "chrome/browser/download/download_target_info.h"
 #include "chrome/common/safe_browsing/download_file_types.pb.h"
 #include "components/download/public/common/download_danger_type.h"
 #include "components/download/public/common/download_item.h"
+#include "components/download/public/common/download_path_reservation_tracker.h"
 #include "content/public/browser/download_manager_delegate.h"
 #include "ppapi/buildflags/buildflags.h"
 
@@ -73,7 +73,8 @@
   static void Start(
       download::DownloadItem* download,
       const base::FilePath& initial_virtual_path,
-      DownloadPathReservationTracker::FilenameConflictAction conflict_action,
+      download::DownloadPathReservationTracker::FilenameConflictAction
+          conflict_action,
       DownloadPrefs* download_prefs,
       DownloadTargetDeterminerDelegate* delegate,
       const CompletionCallback& callback);
@@ -138,7 +139,8 @@
   DownloadTargetDeterminer(
       download::DownloadItem* download,
       const base::FilePath& initial_virtual_path,
-      DownloadPathReservationTracker::FilenameConflictAction conflict_action,
+      download::DownloadPathReservationTracker::FilenameConflictAction
+          conflict_action,
       DownloadPrefs* download_prefs,
       DownloadTargetDeterminerDelegate* delegate,
       const CompletionCallback& callback);
@@ -170,7 +172,8 @@
   // |conflict_action_|.
   void NotifyExtensionsDone(
       const base::FilePath& new_path,
-      DownloadPathReservationTracker::FilenameConflictAction conflict_action);
+      download::DownloadPathReservationTracker::FilenameConflictAction
+          conflict_action);
 
   // Invokes ReserveVirtualPath() on the delegate to acquire a reservation for
   // the path. See DownloadPathReservationTracker.
@@ -179,7 +182,7 @@
   Result DoReserveVirtualPath();
 
   // Callback invoked after the delegate aquires a path reservation.
-  void ReserveVirtualPathDone(PathValidationResult result,
+  void ReserveVirtualPathDone(download::PathValidationResult result,
                               const base::FilePath& path);
 
   // Presents a file picker to the user if necessary.
@@ -315,7 +318,8 @@
   DownloadConfirmationReason confirmation_reason_;
   bool should_notify_extensions_;
   bool create_target_directory_;
-  DownloadPathReservationTracker::FilenameConflictAction conflict_action_;
+  download::DownloadPathReservationTracker::FilenameConflictAction
+      conflict_action_;
   download::DownloadDangerType danger_type_;
   safe_browsing::DownloadFileType::DangerLevel danger_level_;
   base::FilePath virtual_path_;
diff --git a/chrome/browser/download/download_target_determiner_delegate.h b/chrome/browser/download/download_target_determiner_delegate.h
index 33634167..77ddced 100644
--- a/chrome/browser/download/download_target_determiner_delegate.h
+++ b/chrome/browser/download/download_target_determiner_delegate.h
@@ -10,8 +10,8 @@
 #include "base/callback_forward.h"
 #include "chrome/browser/download/download_confirmation_reason.h"
 #include "chrome/browser/download/download_confirmation_result.h"
-#include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "components/download/public/common/download_danger_type.h"
+#include "components/download/public/common/download_path_reservation_tracker.h"
 
 namespace base {
 class FilePath;
@@ -33,12 +33,13 @@
   // ignored.
   typedef base::Callback<void(
       const base::FilePath& new_virtual_path,
-      DownloadPathReservationTracker::FilenameConflictAction conflict_action)>
-  NotifyExtensionsCallback;
+      download::DownloadPathReservationTracker::FilenameConflictAction
+          conflict_action)>
+      NotifyExtensionsCallback;
 
   // Callback to be invoked when ReserveVirtualPath() completes.
   using ReservedPathCallback =
-      DownloadPathReservationTracker::ReservedPathCallback;
+      download::DownloadPathReservationTracker::ReservedPathCallback;
 
   // Callback to be invoked when RequestConfirmation() completes.
   // |virtual_path|: The path chosen by the user. If the user cancels the file
@@ -90,7 +91,8 @@
       download::DownloadItem* download,
       const base::FilePath& virtual_path,
       bool create_directory,
-      DownloadPathReservationTracker::FilenameConflictAction conflict_action,
+      download::DownloadPathReservationTracker::FilenameConflictAction
+          conflict_action,
       const ReservedPathCallback& callback) = 0;
 
   // Display a prompt to the user requesting that a download target be chosen.
diff --git a/chrome/browser/download/download_target_determiner_unittest.cc b/chrome/browser/download/download_target_determiner_unittest.cc
index bfb1da4..1a616604 100644
--- a/chrome/browser/download/download_target_determiner_unittest.cc
+++ b/chrome/browser/download/download_target_determiner_unittest.cc
@@ -67,6 +67,9 @@
 #include "extensions/common/extension.h"
 #endif
 
+using download::DownloadItem;
+using download::DownloadPathReservationTracker;
+using ::testing::_;
 using ::testing::AnyNumber;
 using ::testing::Invoke;
 using ::testing::Ref;
@@ -75,8 +78,6 @@
 using ::testing::ReturnRefOfCopy;
 using ::testing::Truly;
 using ::testing::WithArg;
-using ::testing::_;
-using download::DownloadItem;
 using ConflictAction = DownloadPathReservationTracker::FilenameConflictAction;
 using safe_browsing::DownloadFileType;
 using safe_browsing::FileTypePolicies;
@@ -559,7 +560,7 @@
     bool create_directory,
     DownloadPathReservationTracker::FilenameConflictAction conflict_action,
     const DownloadTargetDeterminerDelegate::ReservedPathCallback& callback) {
-  callback.Run(PathValidationResult::SUCCESS, virtual_path);
+  callback.Run(download::PathValidationResult::SUCCESS, virtual_path);
 }
 
 // static
@@ -1034,19 +1035,19 @@
       EXPECT_CRDOWNLOAD};
 
   struct TestCase {
-    PathValidationResult result;
+    download::PathValidationResult result;
     DownloadConfirmationReason expected_confirmation_reason;
-  } kTestCases[] = {
-      {PathValidationResult::SUCCESS, DownloadConfirmationReason::NONE},
-      {PathValidationResult::CONFLICT,
-       DownloadConfirmationReason::TARGET_CONFLICT},
-      {PathValidationResult::PATH_NOT_WRITABLE,
-       DownloadConfirmationReason::TARGET_PATH_NOT_WRITEABLE},
-      {PathValidationResult::NAME_TOO_LONG,
-       DownloadConfirmationReason::NAME_TOO_LONG}};
+  } kTestCases[] = {{download::PathValidationResult::SUCCESS,
+                     DownloadConfirmationReason::NONE},
+                    {download::PathValidationResult::CONFLICT,
+                     DownloadConfirmationReason::TARGET_CONFLICT},
+                    {download::PathValidationResult::PATH_NOT_WRITABLE,
+                     DownloadConfirmationReason::TARGET_PATH_NOT_WRITEABLE},
+                    {download::PathValidationResult::NAME_TOO_LONG,
+                     DownloadConfirmationReason::NAME_TOO_LONG}};
 
   for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(::testing::Message() << "PathValidationResult "
+    SCOPED_TRACE(::testing::Message() << "download::PathValidationResult "
                                       << static_cast<int>(test_case.result));
     ON_CALL(*delegate(), ReserveVirtualPath(_, _, _, _, _))
         .WillByDefault(WithArg<4>(ScheduleCallback2(
@@ -1612,8 +1613,8 @@
   EXPECT_CALL(*delegate(),
               ReserveVirtualPath(_, full_overridden_path, true,
                                  DownloadPathReservationTracker::OVERWRITE, _))
-      .WillOnce(WithArg<4>(ScheduleCallback2(PathValidationResult::SUCCESS,
-                                             full_overridden_path)));
+      .WillOnce(WithArg<4>(ScheduleCallback2(
+          download::PathValidationResult::SUCCESS, full_overridden_path)));
 
   RunTestCase(test_case, base::FilePath(), item.get());
 
@@ -1625,8 +1626,8 @@
   EXPECT_CALL(*delegate(),
               ReserveVirtualPath(_, full_overridden_path, true,
                                  DownloadPathReservationTracker::PROMPT, _))
-      .WillOnce(WithArg<4>(ScheduleCallback2(PathValidationResult::SUCCESS,
-                                             full_overridden_path)));
+      .WillOnce(WithArg<4>(ScheduleCallback2(
+          download::PathValidationResult::SUCCESS, full_overridden_path)));
   RunTestCase(test_case, base::FilePath(), item.get());
 }
 
@@ -2235,7 +2236,8 @@
       1);
   histogram_tester.ExpectBucketCount(
       kTransientPathValidationHistogram,
-      ToHistogramSample<PathValidationResult>(PathValidationResult::SUCCESS),
+      ToHistogramSample<download::PathValidationResult>(
+          download::PathValidationResult::SUCCESS),
       1);
   histogram_tester.ExpectTotalCount(kTransientPathGenerationHistogram, 1);
   histogram_tester.ExpectTotalCount(kTransientPathValidationHistogram, 1);
@@ -2287,7 +2289,8 @@
       1);
   histogram_tester.ExpectBucketCount(
       kTransientPathValidationHistogram,
-      ToHistogramSample<PathValidationResult>(PathValidationResult::SUCCESS),
+      ToHistogramSample<download::PathValidationResult>(
+          download::PathValidationResult::SUCCESS),
       1);
   histogram_tester.ExpectTotalCount(kTransientPathGenerationHistogram, 1);
   histogram_tester.ExpectTotalCount(kTransientPathValidationHistogram, 1);
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index f573d150..40e574d 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -86,8 +86,9 @@
 
 using content::BrowserContext;
 using content::BrowserThread;
-using download::DownloadItem;
 using content::DownloadManager;
+using download::DownloadItem;
+using download::DownloadPathReservationTracker;
 
 namespace download_extension_errors {
 
@@ -598,8 +599,8 @@
   query_out.Search(all_items.begin(), all_items.end(), results);
 }
 
-DownloadPathReservationTracker::FilenameConflictAction ConvertConflictAction(
-    downloads::FilenameConflictAction action) {
+download::DownloadPathReservationTracker::FilenameConflictAction
+ConvertConflictAction(downloads::FilenameConflictAction action) {
   switch (action) {
     case downloads::FILENAME_CONFLICT_ACTION_NONE:
     case downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY:
@@ -610,7 +611,7 @@
       return DownloadPathReservationTracker::PROMPT;
   }
   NOTREACHED();
-  return DownloadPathReservationTracker::UNIQUIFY;
+  return download::DownloadPathReservationTracker::UNIQUIFY;
 }
 
 class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.h b/chrome/browser/extensions/api/downloads/downloads_api.h
index 6605c2a..7a44733 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.h
+++ b/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -14,10 +14,10 @@
 #include "base/scoped_observer.h"
 #include "base/time/time.h"
 #include "chrome/browser/download/download_danger_prompt.h"
-#include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/downloads.h"
 #include "components/download/content/public/all_download_item_notifier.h"
+#include "components/download/public/common/download_path_reservation_tracker.h"
 #include "content/public/browser/download_manager.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_registry_observer.h"
@@ -314,8 +314,8 @@
  public:
   typedef base::Callback<void(
       const base::FilePath& changed_filename,
-      DownloadPathReservationTracker::FilenameConflictAction)>
-    FilenameChangedCallback;
+      download::DownloadPathReservationTracker::FilenameConflictAction)>
+      FilenameChangedCallback;
 
   static void SetDetermineFilenameTimeoutSecondsForTesting(int s);
 
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
index db6d694f..aa1e7cd6 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
@@ -283,7 +283,7 @@
       << message_;
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     CheckSystemTokenAvailability,
     EnterprisePlatformKeysTest,
     ::testing::Values(
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
index 7b672dc..cd85e422 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
@@ -374,7 +374,7 @@
   EXPECT_EQ("cmVzcG9uc2U=" /* Base64 encoding of 'response' */, response);
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     AllProfiles,
     EPKPChallengeMachineKeyAllProfilesTest,
     ::testing::Values(EPKPChallengeKeyTestBase::ProfileType::USER_PROFILE,
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
index cfb96d6..fd89c1f 100644
--- a/chrome/browser/extensions/bookmark_app_helper.cc
+++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -531,7 +531,6 @@
     }
 #endif  // !defined(OS_CHROMEOS)
   }
-#endif  // !defined(OS_MACOSX)
 
   // Reparent the tab into an app window immediately when opening as a window.
   if (!silent_install &&
@@ -539,6 +538,7 @@
       launch_type == LAUNCH_TYPE_WINDOW && !profile_->IsOffTheRecord()) {
     ReparentWebContentsIntoAppBrowser(contents_, extension);
   }
+#endif  // !defined(OS_MACOSX)
 
   callback_.Run(extension, web_app_info_);
 }
diff --git a/chrome/browser/extensions/bookmark_app_helper_browsertest.cc b/chrome/browser/extensions/bookmark_app_helper_browsertest.cc
index 7ffb51c..5f5b924 100644
--- a/chrome/browser/extensions/bookmark_app_helper_browsertest.cc
+++ b/chrome/browser/extensions/bookmark_app_helper_browsertest.cc
@@ -184,10 +184,12 @@
                                           bookmark_app_helper_->web_app_info_);
   Wait();  // Quits when the extension install completes.
 
+#if !defined(OS_MACOSX)
   // We do not reparent the tab on OS X.
   Browser* app_browser = chrome::FindBrowserWithWebContents(web_contents());
   EXPECT_TRUE(app_browser->is_app());
   EXPECT_NE(app_browser, browser());
+#endif  // defined(OS_MACOSX)
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/policy_handlers.cc b/chrome/browser/extensions/policy_handlers.cc
index 0e2eda1..0974548 100644
--- a/chrome/browser/extensions/policy_handlers.cc
+++ b/chrome/browser/extensions/policy_handlers.cc
@@ -24,7 +24,7 @@
 #include "url/gurl.h"
 
 #if defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 #endif
 
 namespace extensions {
@@ -277,7 +277,7 @@
 #if defined(OS_WIN)
           // We can't use IsWebstoreUpdateUrl() here since the ExtensionClient
           // isn't set this early during startup.
-          if (!base::win::IsEnterpriseManaged() &&
+          if (!base::IsMachineExternallyManaged() &&
               !base::LowerCaseEqualsASCII(
                   update_url, extension_urls::kChromeWebstoreUpdateURL)) {
             errors->AddError(policy_name(), it.key(),
diff --git a/chrome/browser/feature_engagement/incognito_window/incognito_window_tracker.cc b/chrome/browser/feature_engagement/incognito_window/incognito_window_tracker.cc
index 5d07a43..01a71bf 100644
--- a/chrome/browser/feature_engagement/incognito_window/incognito_window_tracker.cc
+++ b/chrome/browser/feature_engagement/incognito_window/incognito_window_tracker.cc
@@ -10,6 +10,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/in_product_help/in_product_help.h"
 #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
 #include "chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -100,7 +101,7 @@
       FeaturePromoBubbleView::ActivationAction::ACTIVATE);
   views::Widget* widget = incognito_promo_->GetWidget();
   incognito_promo_observer_.Add(widget);
-  app_menu_button->SetPromoIsShowing(true);
+  app_menu_button->SetPromoFeature(InProductHelpFeature::kIncognitoWindow);
 }
 
 void IncognitoWindowTracker::OnWidgetDestroying(views::Widget* widget) {
@@ -110,7 +111,7 @@
     incognito_promo_observer_.Remove(widget);
     BrowserAppMenuButton* app_menu_button = GetAppMenuButton();
     if (app_menu_button)
-      app_menu_button->SetPromoIsShowing(false);
+      app_menu_button->SetPromoFeature(base::nullopt);
   }
 }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index fcf85e21..6dd51bf 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -888,6 +888,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "enable-autofill-import-non-focusable-credit-card-forms",
+    "owners": [ "hozhng@google.com", "jiahuiguo@google.com" ],
+    "expiry_milestone": 76
+  },
+  {
     "name": "enable-autofill-local-card-migration-show-feedback",
     "owners": [ "jiahuiguo@google.com", "siyua@google.com" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c98b39a4..69d8618 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -427,6 +427,13 @@
     "offering card upload to Google Payments, the offer-to-save dialog "
     "displays an expiration date selector.";
 
+const char kEnableAutofillImportNonFocusableCreditCardFormsName[] =
+    "Allow credit card import from forms that disappear after entry";
+const char kEnableAutofillImportNonFocusableCreditCardFormsDescription[] =
+    "If enabled, offers credit card save for forms that are hidden from the "
+    "page after information has been entered into them, including "
+    "accordion-style checkout flows.";
+
 const char kEnableAutofillLocalCardMigrationShowFeedbackName[] =
     "Show the upload results dialog after local card migration";
 const char kEnableAutofillLocalCardMigrationShowFeedbackDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index dbfbb030..5302c37 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -294,6 +294,9 @@
 extern const char
     kEnableAutofillCreditCardUploadEditableExpirationDateDescription[];
 
+extern const char kEnableAutofillImportNonFocusableCreditCardFormsName[];
+extern const char kEnableAutofillImportNonFocusableCreditCardFormsDescription[];
+
 extern const char kEnableAutofillLocalCardMigrationShowFeedbackName[];
 extern const char kEnableAutofillLocalCardMigrationShowFeedbackDescription[];
 
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac.mm b/chrome/browser/local_discovery/service_discovery_client_mac.mm
index 82726f7..bf78555 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac.mm
+++ b/chrome/browser/local_discovery/service_discovery_client_mac.mm
@@ -233,10 +233,7 @@
   DVLOG(1) << "Listening for service type '" << [type UTF8String]
            << "' on domain '" << [domain UTF8String] << "'";
 
-  base::Time start_time = base::Time::Now();
   [browser_ searchForServicesOfType:type inDomain:domain];
-  UMA_HISTOGRAM_TIMES("LocalDiscovery.MacBrowseCallTimes",
-                      base::Time::Now() - start_time);
 }
 
 void ServiceWatcherImplMac::NetServiceBrowserContainer::OnServicesUpdate(
diff --git a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
index 4982f61..406a704 100644
--- a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
@@ -247,17 +247,9 @@
   RunsAudioVideoCall60SecsAndLogsInternalMetrics("VP9");
 }
 
-// See https://crbug.com/922198.
-#if defined(OS_MACOSX)
-#define MAYBE_MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp9Profile2 \
-  DISABLED_MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp9Profile2
-#else
-#define MAYBE_MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp9Profile2 \
-  MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp9Profile2
-#endif  // defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(
     WebRtcInternalsPerfBrowserTest,
-    MAYBE_MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp9Profile2) {
+    MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp9Profile2) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   RunsAudioVideoCall60SecsAndLogsInternalMetrics(
       "VP9", true /* prefer_hw_video_codec */,
diff --git a/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc
index 0118e621..76fc623e 100644
--- a/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc
@@ -309,17 +309,9 @@
   RunsAudioAndVideoCallCollectingMetricsWithVideoCodec("VP9");
 }
 
-// See https://crbug.com/922198.
-#if defined(OS_MACOSX)
-#define MAYBE_MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP9Profile2 \
-  DISABLED_MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP9Profile2
-#else
-#define MAYBE_MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP9Profile2 \
-  MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP9Profile2
-#endif  // defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(
     WebRtcStatsPerfBrowserTest,
-    MAYBE_MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP9Profile2) {
+    MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP9Profile2) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   RunsAudioAndVideoCallCollectingMetricsWithVideoCodec(
       "VP9", true /* prefer_hw_video_codec */,
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
index 2bd01006..d10d2dd 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -563,9 +563,8 @@
   if (web_contents_will_soon_be_destroyed_)
     return;
 
-  // TODO(bmcquade): Consider handling an OCCLUDED tab as not in foreground.
   bool was_in_foreground = in_foreground_;
-  in_foreground_ = visibility != content::Visibility::HIDDEN;
+  in_foreground_ = visibility == content::Visibility::VISIBLE;
   if (in_foreground_ == was_in_foreground)
     return;
 
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store_proxy_unittest.cc b/chrome/browser/prefs/chrome_command_line_pref_store_proxy_unittest.cc
index be9df49..62e885a1 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store_proxy_unittest.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store_proxy_unittest.cc
@@ -193,6 +193,6 @@
       GetParam().proxy_rules.Matches(proxy_config()->value().proxy_rules()));
 }
 
-INSTANTIATE_TEST_CASE_P(ChromeCommandLinePrefStoreProxyTestInstance,
-                        ChromeCommandLinePrefStoreProxyTest,
-                        testing::ValuesIn(kCommandLineTestParams));
+INSTANTIATE_TEST_SUITE_P(ChromeCommandLinePrefStoreProxyTestInstance,
+                         ChromeCommandLinePrefStoreProxyTest,
+                         testing::ValuesIn(kCommandLineTestParams));
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index 724c86e..c848923 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -74,7 +74,7 @@
 #endif
 
 #if defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 #if BUILDFLAG(ENABLE_RLZ)
 #include "rlz/lib/machine_id.h"
 #endif  // BUILDFLAG(ENABLE_RLZ)
@@ -214,7 +214,7 @@
 # if defined(OS_WIN)
   if (!g_disable_domain_check_for_testing) {
     static bool first_call = true;
-    static const bool is_managed = base::win::IsEnterpriseManaged();
+    static const bool is_managed = base::IsMachineExternallyManaged();
     if (first_call) {
       UMA_HISTOGRAM_BOOLEAN("Settings.TrackedPreferencesNoEnforcementOnDomain",
                             is_managed);
diff --git a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
index b506a053..8e45024 100644
--- a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
+++ b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
@@ -157,22 +157,17 @@
 #endif
 }
 
-#define PREF_HASH_BROWSER_TEST(fixture, test_name)                          \
-  IN_PROC_BROWSER_TEST_P(fixture, PRE_##test_name) {                        \
-    SetupPreferences();                                                     \
-  }                                                                         \
-  IN_PROC_BROWSER_TEST_P(fixture, test_name) {                              \
-    VerifyReactionToPrefAttack();                                           \
-  }                                                                         \
-  INSTANTIATE_TEST_CASE_P(                                                  \
-      fixture##Instance,                                                    \
-      fixture,                                                              \
-      testing::Values(                                                      \
-          chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement,  \
-          chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways,  \
-          chrome_prefs::internals::                                         \
-              kSettingsEnforcementGroupEnforceAlwaysWithDSE,                \
-          chrome_prefs::internals::                                         \
+#define PREF_HASH_BROWSER_TEST(fixture, test_name)                             \
+  IN_PROC_BROWSER_TEST_P(fixture, PRE_##test_name) { SetupPreferences(); }     \
+  IN_PROC_BROWSER_TEST_P(fixture, test_name) { VerifyReactionToPrefAttack(); } \
+  INSTANTIATE_TEST_SUITE_P(                                                    \
+      fixture##Instance, fixture,                                              \
+      testing::Values(                                                         \
+          chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement,     \
+          chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways,     \
+          chrome_prefs::internals::                                            \
+              kSettingsEnforcementGroupEnforceAlwaysWithDSE,                   \
+          chrome_prefs::internals::                                            \
               kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE));
 
 // A base fixture designed such that implementations do two things:
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 9c88ffd..be3d8ff 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -143,7 +143,7 @@
 #endif
 
 #if defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 #include "chrome/browser/signin/signin_util_win.h"
@@ -1081,7 +1081,7 @@
     profile->GetPrefs()->SetBoolean(prefs::kHasSeenWelcomePage, false);
 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
     // Enterprise users should not be included in any NUX/Navi flow.
-    if (!base::win::IsEnterpriseManaged()) {
+    if (!base::IsMachineExternallyManaged()) {
       profile->GetPrefs()->SetString(prefs::kNaviOnboardGroup,
                                      nux::GetOnboardingGroup());
     }
diff --git a/chrome/browser/resources/cryptotoken/enroller.js b/chrome/browser/resources/cryptotoken/enroller.js
index f23e6286..f3ea5cc5 100644
--- a/chrome/browser/resources/cryptotoken/enroller.js
+++ b/chrome/browser/resources/cryptotoken/enroller.js
@@ -888,12 +888,29 @@
   const randomId = new Uint8Array(new ArrayBuffer(16));
   crypto.getRandomValues(randomId);
 
+  const decodedChallenge = B64_decode(challenge);
+  if (decodedChallenge.length == 0) {
+    this.notifyError_({
+      errorCode: ErrorCodes.BAD_REQUEST,
+      errorMessage: 'challenge must be base64url encoded',
+    });
+    return;
+  }
+
   const excludeList = [];
   for (let index = 0; index < request['signData'].length; index++) {
     const element = request['signData'][index];
+    const decodedKeyHandle = B64_decode(element['keyHandle']);
+    if (decodedKeyHandle.length == 0) {
+      this.notifyError_({
+        errorCode: ErrorCodes.BAD_REQUEST,
+        errorMessage: 'keyHandle must be base64url encoded',
+      });
+      return;
+    }
     excludeList.push({
       type: 'public-key',
-      id: new Uint8Array(B64_decode(element['keyHandle'])).buffer,
+      id: new Uint8Array(decodedKeyHandle).buffer,
       transports: ['usb'],
     });
   }
@@ -913,7 +930,7 @@
         displayName: this.sender_.origin,
         name: this.sender_.origin,
       },
-      challenge: new Uint8Array(B64_decode(challenge)).buffer,
+      challenge: new Uint8Array(decodedChallenge).buffer,
       pubKeyCredParams: [{
         type: 'public-key',
         alg: -7,  // ES-256
diff --git a/chrome/browser/resources/cryptotoken/signer.js b/chrome/browser/resources/cryptotoken/signer.js
index 2c9467a..4f89796 100644
--- a/chrome/browser/resources/cryptotoken/signer.js
+++ b/chrome/browser/resources/cryptotoken/signer.js
@@ -495,11 +495,28 @@
     return false;
   }
 
+  const decodedChallenge = B64_decode(challengeVal);
+  if (decodedChallenge.length == 0) {
+    this.notifyError_({
+      errorCode: ErrorCodes.BAD_REQUEST,
+      errorMessage: 'challenge must be base64url encoded',
+    });
+    return false;
+  }
+
   const credentialList = [];
   for (let i = 0; i < encodedChallenges.length; i++) {
+    const decodedKeyHandle = B64_decode(encodedChallenges[i]['keyHandle']);
+    if (decodedKeyHandle.length == 0) {
+      this.notifyError_({
+        errorCode: ErrorCodes.BAD_REQUEST,
+        errorMessage: 'keyHandle must be base64url encoded',
+      });
+      return false;
+    }
     credentialList.push({
       type: 'public-key',
-      id: new Uint8Array(B64_decode(encodedChallenges[i].keyHandle)).buffer,
+      id: new Uint8Array(decodedKeyHandle).buffer,
     });
   }
   // App ID could be defined for each challenge or globally.
@@ -509,7 +526,7 @@
 
   const request = {
     publicKey: {
-      challenge: new Uint8Array(B64_decode(challengeVal)).buffer,
+      challenge: new Uint8Array(decodedChallenge).buffer,
       timeout: this.timer_.millisecondsUntilExpired(),
       rpId: this.sender_.origin,
       allowCredentials: credentialList,
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index ea1e0b8..942e449 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -1168,7 +1168,7 @@
   args.push('removeTooltip=' +
       encodeURIComponent(configData.translatedStrings.removeThumbnailTooltip));
 
-  if (configData.isDarkModeEnabled) {
+  if (isDarkModeEnabled) {
     args.push('enableDarkMode=1');
   }
 
@@ -1206,7 +1206,7 @@
       clArgs.push('rtl=1');
     }
 
-    if (configData.isDarkModeEnabled) {
+    if (isDarkModeEnabled) {
       clArgs.push('enableDarkMode=1');
     }
 
diff --git a/chrome/browser/resources/settings/controls/settings_slider.html b/chrome/browser/resources/settings/controls/settings_slider.html
index 15257fa0..872792b 100644
--- a/chrome/browser/resources/settings/controls/settings_slider.html
+++ b/chrome/browser/resources/settings/controls/settings_slider.html
@@ -26,7 +26,7 @@
         display: flex;
         flex-direction: column;
         margin: 8px 0;
-        min-width: var(--cr-text-element-min-width);
+        min-width: 200px;
       }
 
       #labels {
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
index bdeecaf6..a25cf48 100644
--- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
+++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
@@ -14,11 +14,7 @@
 
 <dom-module id="settings-google-assistant-page">
   <template>
-    <style include="settings-shared md-select">
-      .text-area {
-        margin-inline-end: 24px;
-      }
-    </style>
+    <style include="settings-shared md-select"></style>
     <settings-toggle-button id="googleAssistantEnable"
         class="first primary-toggle"
         pref="{{prefs.settings.voice_interaction.enabled}}"
diff --git a/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.cc b/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.cc
index 7120b9f..d9d7ee1 100644
--- a/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win.cc
@@ -10,6 +10,7 @@
 #include <set>
 #include <string>
 
+#include "base/enterprise_util.h"
 #include "base/i18n/case_conversion.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
@@ -18,7 +19,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/registry.h"
-#include "base/win/win_util.h"
 #include "chrome/browser/install_verification/win/module_info.h"
 #include "chrome/browser/install_verification/win/module_verification_common.h"
 #include "chrome/browser/net/service_providers_win.h"
@@ -292,7 +292,7 @@
 
 void CollectDomainEnrollmentData(
     ClientIncidentReport_EnvironmentData_OS* os_data) {
-  os_data->set_is_enrolled_to_domain(base::win::IsEnterpriseManaged());
+  os_data->set_is_enrolled_to_domain(base::IsMachineExternallyManaged());
 }
 
 void CollectPlatformProcessData(
diff --git a/chrome/browser/search/background/ntp_background_service.cc b/chrome/browser/search/background/ntp_background_service.cc
index 8008970..9c2049d1 100644
--- a/chrome/browser/search/background/ntp_background_service.cc
+++ b/chrome/browser/search/background/ntp_background_service.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/search/background/ntp_background.pb.h"
+#include "chrome/browser/search/background/onboarding_ntp_backgrounds.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
@@ -514,6 +515,12 @@
 }
 
 bool NtpBackgroundService::IsValidBackdropUrl(const GURL& url) const {
+  for (auto& onboarding_background : GetOnboardingNtpBackgrounds()) {
+    if (onboarding_background == url) {
+      return true;
+    }
+  }
+
   for (auto& image : collection_images_) {
     if (image.image_url == url)
       return true;
diff --git a/chrome/browser/search/background/onboarding_ntp_backgrounds.cc b/chrome/browser/search/background/onboarding_ntp_backgrounds.cc
new file mode 100644
index 0000000..5931d343
--- /dev/null
+++ b/chrome/browser/search/background/onboarding_ntp_backgrounds.cc
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/search/background/onboarding_ntp_backgrounds.h"
+
+#include "url/gurl.h"
+
+std::array<GURL, kOnboardingNtpBackgroundsCount> GetOnboardingNtpBackgrounds() {
+  // A set of whitelisted NTP background image URLs that are always considered
+  // to be valid URLs that are shown to the user as part of the Onboarding flow.
+  // These backgrounds were handpicked from the Backdrop API.
+  const std::array<GURL, kOnboardingNtpBackgroundsCount>
+      kOnboardingNtpBackgrounds = {
+          {// Art
+           GURL(
+               "https://lh4.googleusercontent.com/proxy/"
+               "rh9ut9biDoATqaadvgilbUAkIDo50op0G9056C1TnbfK5063_"
+               "M1OzTyOSfgbHbwcXzWz-UoM19yeObH2gXCX8wB8hVPbc_MXHBMfJWUmpg1Tg0s="
+               "w3840-h2160-p-k-no-nd-mv"),
+
+           // Landscape
+           GURL("https://lh6.googleusercontent.com/proxy/"
+                "5YUVHiA1x4KXBMvcnQ_"
+                "fNcsGFQig9vpKgEbH98vc3mIx6963Jawv4WtVMemvIEdCHGpo60iD8t0OfwnHu"
+                "5w"
+                "Y5InXTyqTPZx4a77T7iIFnHti=w3840-h2160-p-k-no-nd-mv"),
+
+           // Cityscape
+           GURL(
+               "https://lh6.googleusercontent.com/proxy/"
+               "Ym39mP3aRahUqQD_W1bks3MdDZx-Mea7_ajAs293LciDm70mFzpsswh_"
+               "QBJVFeUMWYF2jIQFvcBPeEdNAAwBlFNc2PsINAWHXe68Kg=w3840-h2160-p-k-"
+               "no-nd-mv"),
+
+           // Seascape
+           GURL("https://lh4.googleusercontent.com/proxy/"
+                "hl6qyPDq9FBOuU8G1A3X2khJJdAzfccHtIoX7hHtlkR4tgj_"
+                "WJvpj4s8FX8cb8u9R6xhrp96xXJIIFrTK8Rdpqh0tTiSfL5k_OXcWw=w3840-"
+                "h2160-p-k-no-nd-mv"),
+
+           // Geometric forms
+           GURL("https://lh5.googleusercontent.com/proxy/"
+                "Dm41Zdz8s5TnQcIRSCnAXUvHItsB67S7U3DytjCwsIpG9SmJKsVkkBRCK0ODme"
+                "vy"
+                "_M47-2CSAxGzFaiJM3bHaPfVT90Fm6lBbNd2yueqMg=w3840-h2160-p-k-no-"
+                "nd-mv")}};
+  return kOnboardingNtpBackgrounds;
+}
diff --git a/chrome/browser/search/background/onboarding_ntp_backgrounds.h b/chrome/browser/search/background/onboarding_ntp_backgrounds.h
new file mode 100644
index 0000000..b5570db
--- /dev/null
+++ b/chrome/browser/search/background/onboarding_ntp_backgrounds.h
@@ -0,0 +1,15 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SEARCH_BACKGROUND_ONBOARDING_NTP_BACKGROUNDS_H_
+#define CHROME_BROWSER_SEARCH_BACKGROUND_ONBOARDING_NTP_BACKGROUNDS_H_
+
+#include <array>
+
+#include "url/gurl.h"
+
+const size_t kOnboardingNtpBackgroundsCount = 5;
+std::array<GURL, kOnboardingNtpBackgroundsCount> GetOnboardingNtpBackgrounds();
+
+#endif  // CHROME_BROWSER_SEARCH_BACKGROUND_ONBOARDING_NTP_BACKGROUNDS_H_
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index e36a368..6525f94 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -473,8 +473,8 @@
 }
 
 void InstantService::OnDarkModeChanged(bool dark_mode) {
-  if (theme_info_)
-    theme_info_->using_dark_mode = dark_mode;
+  // Force theme information rebuild in order to update dark mode colors.
+  BuildThemeInfo();
   UpdateThemeInfo();
 }
 
diff --git a/chrome/browser/ssl/cert_report_helper.cc b/chrome/browser/ssl/cert_report_helper.cc
index aee221b..b3b52302 100644
--- a/chrome/browser/ssl/cert_report_helper.cc
+++ b/chrome/browser/ssl/cert_report_helper.cc
@@ -29,7 +29,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 #elif defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #endif
@@ -162,7 +162,7 @@
   report.AddChromeChannel(chrome::GetChannel());
 
 #if defined(OS_WIN)
-  report.SetIsEnterpriseManaged(base::win::IsEnterpriseManaged());
+  report.SetIsEnterpriseManaged(base::IsMachineExternallyManaged());
 #elif defined(OS_CHROMEOS)
   report.SetIsEnterpriseManaged(g_browser_process->platform_part()
                                     ->browser_policy_connector_chromeos()
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
index 72e6408..183ce86a 100644
--- a/chrome/browser/ssl/ssl_error_handler.cc
+++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -56,7 +56,7 @@
 #endif
 
 #if defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 #elif defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #endif  // #if defined(OS_WIN)
@@ -346,7 +346,7 @@
   }
 
 #if defined(OS_WIN)
-  if (base::win::IsEnterpriseManaged()) {
+  if (base::IsMachineExternallyManaged()) {
     return true;
   }
 #elif defined(OS_CHROMEOS)
diff --git a/chrome/browser/task_manager/sampling/task_manager_impl.cc b/chrome/browser/task_manager/sampling/task_manager_impl.cc
index 5faa05d..1c50a9b9 100644
--- a/chrome/browser/task_manager/sampling/task_manager_impl.cc
+++ b/chrome/browser/task_manager/sampling/task_manager_impl.cc
@@ -635,6 +635,9 @@
     io_thread_helper_manager_.reset(new IoThreadHelperManager(
         base::BindRepeating(&TaskManagerImpl::OnMultipleBytesTransferredUI)));
   }
+  // Kick off fetch of asynchronous data, e.g., memory footprint, so that it
+  // will be displayed sooner after opening the task manager.
+  Refresh();
 }
 
 void TaskManagerImpl::StopUpdating() {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index c5660b0..65ffae47 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1795,6 +1795,7 @@
       "//services/ws/public/cpp",
       "//services/ws/public/mojom",
       "//ui/base/ime",
+      "//ui/base/user_activity",
       "//ui/chromeos",
       "//ui/chromeos/events",
       "//ui/compositor_extra",
diff --git a/chrome/browser/ui/in_product_help/in_product_help.h b/chrome/browser/ui/in_product_help/in_product_help.h
index 0a4381f..9cb833c 100644
--- a/chrome/browser/ui/in_product_help/in_product_help.h
+++ b/chrome/browser/ui/in_product_help/in_product_help.h
@@ -5,10 +5,9 @@
 #ifndef CHROME_BROWSER_UI_IN_PRODUCT_HELP_IN_PRODUCT_HELP_H_
 #define CHROME_BROWSER_UI_IN_PRODUCT_HELP_IN_PRODUCT_HELP_H_
 
-// Identifies a feature that has in-product help. This is used for dispatching
-// in-product help promos from a |BrowserWindow| object.
+// Identifies a feature that has in-product help.
 enum class InProductHelpFeature {
-  // For |ReopenTabInProductHelp|
+  kIncognitoWindow,
   kReopenTab,
 };
 
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_browsertest.cc b/chrome/browser/ui/views/autofill/local_card_migration_browsertest.cc
index 4f60dea4..a7d5acf 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_browsertest.cc
@@ -15,11 +15,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/autofill/autofill_uitest_util.h"
 #include "chrome/browser/signin/account_fetcher_service_factory.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
-#include "chrome/browser/signin/fake_account_fetcher_service_builder.h"
-#include "chrome/browser/signin/fake_signin_manager_builder.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
index c737177..d11ac97 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
@@ -94,9 +95,11 @@
     "link: "
     "{0}.\",\"template_parameter\":[{\"display_text\":\"Link\",\"url\":\"https:"
     "//www.example.com/\"}]}]},\"context_token\":\"dummy_context_token\"}";
-const char kResponseGetUploadDetailsFailure[] =
+const char kResponsePaymentsFailure[] =
     "{\"error\":{\"code\":\"FAILED_PRECONDITION\",\"user_error_message\":\"An "
     "unexpected error has occurred. Please try again later.\"}}";
+const char kURLUploadCardRequest[] =
+    "https://payments.google.com/payments/apis/chromepaymentsservice/savecard";
 
 const double kFakeGeolocationLatitude = 1.23;
 const double kFakeGeolocationLongitude = 4.56;
@@ -509,7 +512,7 @@
 
   void SetUploadDetailsRpcPaymentsDeclines() {
     test_url_loader_factory()->AddResponse(kURLGetUploadDetailsRequest,
-                                           kResponseGetUploadDetailsFailure);
+                                           kResponsePaymentsFailure);
   }
 
   void SetUploadDetailsRpcServerError() {
@@ -518,6 +521,11 @@
                                            net::HTTP_INTERNAL_SERVER_ERROR);
   }
 
+  void SetUploadCardRpcPaymentsFails() {
+    test_url_loader_factory()->AddResponse(kURLUploadCardRequest,
+                                           kResponsePaymentsFailure);
+  }
+
   void ClickOnView(views::View* view) {
     DCHECK(view);
     ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
@@ -590,19 +598,19 @@
     return specified_view;
   }
 
-  void ClickOnCancelButton() {
+  void ClickOnCancelButton(bool strike_expected = false) {
     SaveCardBubbleViews* save_card_bubble_views = GetSaveCardBubbleViews();
     DCHECK(save_card_bubble_views);
-    if (base::FeatureList::IsEnabled(
-            features::kAutofillSaveCreditCardUsesStrikeSystem) ||
-        base::FeatureList::IsEnabled(
-            features::kAutofillSaveCreditCardUsesStrikeSystemV2)) {
+    if (strike_expected &&
+        (base::FeatureList::IsEnabled(
+             features::kAutofillSaveCreditCardUsesStrikeSystem) ||
+         base::FeatureList::IsEnabled(
+             features::kAutofillSaveCreditCardUsesStrikeSystemV2))) {
       ResetEventWaiterForSequence(
           {DialogEvent::STRIKE_CHANGE_COMPLETE, DialogEvent::BUBBLE_CLOSED});
     } else {
       ResetEventWaiterForSequence({DialogEvent::BUBBLE_CLOSED});
     }
-
     ClickOnDialogViewWithIdAndWait(DialogViewId::CANCEL_BUTTON);
     DCHECK(!GetSaveCardBubbleViews());
   }
@@ -720,8 +728,12 @@
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
                        Local_ClickingNoThanksClosesBubble) {
   // Enable the updated UI.
-  scoped_feature_list_.InitAndEnableFeature(
-      features::kAutofillSaveCardImprovedUserConsent);
+  scoped_feature_list_.InitWithFeatures(
+      // Enabled
+      {features::kAutofillSaveCardImprovedUserConsent},
+      // Disabled
+      {features::kAutofillSaveCreditCardUsesStrikeSystem,
+       features::kAutofillSaveCreditCardUsesStrikeSystemV2});
 
   // Submitting the form and having Payments decline offering to save should
   // show the local save bubble.
@@ -1254,7 +1266,8 @@
       {features::kAutofillSaveCardImprovedUserConsent,
        features::kAutofillUpstream},
       // Disabled
-      {});
+      {features::kAutofillSaveCreditCardUsesStrikeSystem,
+       features::kAutofillSaveCreditCardUsesStrikeSystemV2});
 
   // Start sync.
   harness_->SetupSync();
@@ -2275,4 +2288,414 @@
             year_input()->GetTextForRow(year_input()->selected_index()));
 }
 
+// TODO(crbug.com/884817): Investigate combining local vs. upload tests using a
+//                         boolean to branch local vs. upload logic.
+
+// Tests StrikeDatabase interaction with the local save bubble. Ensures that no
+// strikes are added if the feature flag is disabled.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       StrikeDatabase_Local_StrikeNotAddedIfExperimentFlagOff) {
+  // Disable the the SaveCreditCardUsesStrikeSystem experiments.
+  scoped_feature_list_.InitWithFeatures(
+      // Enabled
+      {features::kAutofillSaveCardImprovedUserConsent},
+      // Disabled
+      {features::kAutofillSaveCreditCardUsesStrikeSystem,
+       features::kAutofillSaveCreditCardUsesStrikeSystemV2});
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_LOCAL)->visible());
+
+  base::HistogramTester histogram_tester;
+  ClickOnCancelButton();
+
+  // Ensure that no strike was added because the feature is disabled.
+  histogram_tester.ExpectTotalCount(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave", 0);
+}
+
+// Tests StrikeDatabase interaction with the upload save bubble. Ensures that no
+// strikes are added if the feature flag is disabled.
+IN_PROC_BROWSER_TEST_F(
+    SaveCardBubbleViewsFullFormBrowserTest,
+    StrikeDatabase_Upload_StrikeNotAddedIfExperimentFlagOff) {
+  // Disable the the SaveCreditCardUsesStrikeSystem experiments.
+  scoped_feature_list_.InitWithFeatures(
+      // Enabled
+      {features::kAutofillUpstream,
+       features::kAutofillSaveCardImprovedUserConsent},
+      // Disabled
+      {features::kAutofillSaveCreditCardUsesStrikeSystem,
+       features::kAutofillSaveCreditCardUsesStrikeSystemV2});
+
+  // Start sync.
+  harness_->SetupSync();
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsAccepts();
+
+  // Submitting the form should show the upload save bubble and legal footer.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_UPLOAD)->visible());
+  EXPECT_TRUE(FindViewInBubbleById(DialogViewId::FOOTNOTE_VIEW)->visible());
+
+  base::HistogramTester histogram_tester;
+
+  ClickOnCancelButton();
+
+  // Ensure that no strike was added because the feature is disabled.
+  histogram_tester.ExpectTotalCount(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave", 0);
+}
+
+// Tests StrikeDatabase interaction with the local save bubble. Ensures that a
+// strike is added if the bubble is ignored.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       StrikeDatabase_Local_AddStrikeIfBubbleIgnored) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+
+  TestAutofillClock test_clock;
+  test_clock.SetNow(base::Time::Now());
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsDeclines();
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_LOCAL)->visible());
+
+  // Clicking the [X] close button should dismiss the bubble.
+  ClickOnCloseButton();
+
+  // Add an event observer to the controller to detect strike changes.
+  AddEventObserverToController();
+
+  base::HistogramTester histogram_tester;
+
+  // Wait long enough to avoid bubble stickiness, then navigate away from the
+  // page.
+  test_clock.Advance(kCardBubbleSurviveNavigationTime);
+  ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE});
+  NavigateTo(kCreditCardUploadForm);
+  WaitForObservedEvent();
+
+  // Ensure that a strike was added due to the bubble being ignored.
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave",
+      /*sample=*/1, /*count=*/1);
+}
+
+// Tests StrikeDatabase interaction with the upload save bubble. Ensures that a
+// strike is added if the bubble is ignored.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       StrikeDatabase_Upload_AddStrikeIfBubbleIgnored) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCreditCardUsesStrikeSystemV2);
+
+  TestAutofillClock test_clock;
+  test_clock.SetNow(base::Time::Now());
+
+  // Start sync.
+  harness_->SetupSync();
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsAccepts();
+
+  // Submitting the form should show the upload save bubble and legal footer.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_UPLOAD)->visible());
+  EXPECT_TRUE(FindViewInBubbleById(DialogViewId::FOOTNOTE_VIEW)->visible());
+
+  // Clicking the [X] close button should dismiss the bubble.
+  ClickOnCloseButton();
+
+  // Add an event observer to the controller to detect strike changes.
+  AddEventObserverToController();
+
+  base::HistogramTester histogram_tester;
+
+  // Wait long enough to avoid bubble stickiness, then navigate away from the
+  // page.
+  test_clock.Advance(kCardBubbleSurviveNavigationTime);
+  ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE});
+  NavigateTo(kCreditCardUploadForm);
+  WaitForObservedEvent();
+
+  // Ensure that a strike was added due to the bubble being ignored.
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave",
+      /*sample=*/1, /*count=*/1);
+}
+
+// Tests the local save bubble. Ensures that clicking the [No thanks] button
+// successfully causes the bubble to go away.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       StrikeDatabase_Local_AddStrikeIfBubbleDeclined) {
+  // Enable the updated UI.
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillSaveCardImprovedUserConsent);
+
+  // Submitting the form and having Payments decline offering to save should
+  // show the local save bubble.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_LOCAL)->visible());
+
+  // Clicking [No thanks] should cancel and close it.
+  base::HistogramTester histogram_tester;
+  ClickOnCancelButton(/*strike_expected=*/true);
+
+  // Ensure that a strike was added.
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave",
+      /*sample=*/(1), /*count=*/1);
+}
+
+// Tests the upload save bubble. Ensures that clicking the [No thanks] button
+// successfully causes a strike to be added.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       StrikeDatabase_Upload_AddStrikeIfBubbleDeclined) {
+  // Enable the updated UI.
+  scoped_feature_list_.InitWithFeatures(
+      // Enabled
+      {features::kAutofillSaveCardImprovedUserConsent,
+       features::kAutofillUpstream},
+      // Disabled
+      {});
+
+  // Start sync.
+  harness_->SetupSync();
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsAccepts();
+
+  // Submitting the form should show the upload save bubble and legal footer.
+  // (Must wait for response from Payments before accessing the controller.)
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_UPLOAD)->visible());
+  EXPECT_TRUE(FindViewInBubbleById(DialogViewId::FOOTNOTE_VIEW)->visible());
+
+  // Clicking [No thanks] should cancel and close it.
+  base::HistogramTester histogram_tester;
+  ClickOnCancelButton(/*strike_expected=*/true);
+
+  // Ensure that a strike was added.
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave",
+      /*sample=*/(1), /*count=*/1);
+}
+
+// Tests overall StrikeDatabase interaction with the local save bubble. Runs an
+// example of declining the prompt three times and ensuring that the
+// offer-to-save bubble does not appear on the fourth try. Then, ensures that no
+// strikes are added if the card already has max strikes.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       StrikeDatabase_Local_FullFlowTest) {
+  scoped_feature_list_.InitWithFeatures(
+      // Enabled
+      {features::kAutofillSaveCardImprovedUserConsent,
+       features::kAutofillSaveCreditCardUsesStrikeSystemV2},
+      // Disabled
+      {});
+
+  bool controller_observer_set = false;
+
+  // Show and ignore the bubble kMaxStrikesToPreventPoppingUpOfferToSavePrompt
+  // times in order to accrue maximum strikes.
+  for (int i = 0; i < kMaxStrikesToPreventPoppingUpOfferToSavePrompt; i++) {
+    // Submitting the form and having Payments decline offering to save should
+    // show the local save bubble.
+    // (Must wait for response from Payments before accessing the controller.)
+    ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE});
+    NavigateTo(kCreditCardUploadForm);
+    FillAndSubmitForm();
+    WaitForObservedEvent();
+    EXPECT_TRUE(
+        FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_LOCAL)->visible());
+
+    if (!controller_observer_set) {
+      // Add an event observer to the controller.
+      AddEventObserverToController();
+      ReduceAnimationTime();
+      controller_observer_set = true;
+    }
+
+    base::HistogramTester histogram_tester;
+    ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE});
+    ClickOnCancelButton(/*strike_expected=*/true);
+    WaitForObservedEvent();
+
+    // Ensure that a strike was added due to the bubble being declined.
+    // The sample logged is the Nth strike added, or (i+1).
+    histogram_tester.ExpectUniqueSample(
+        "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave",
+        /*sample=*/(i + 1), /*count=*/1);
+  }
+
+  base::HistogramTester histogram_tester;
+
+  // Submit the form a fourth time. Since the card now has maximum strikes (3),
+  // the icon should be shown but the bubble should not.
+  ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(GetSaveCardIconView()->visible());
+  EXPECT_FALSE(GetSaveCardBubbleViews());
+
+  // Click the icon to show the bubble.
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+  ClickOnView(GetSaveCardIconView());
+  WaitForObservedEvent();
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_LOCAL)->visible());
+
+  ClickOnCancelButton();
+
+  // Ensure that no strike was added because the card already had max strikes.
+  histogram_tester.ExpectTotalCount(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave", 0);
+
+  // Verify that the correct histogram entry was logged.
+  histogram_tester.ExpectBucketCount(
+      "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes",
+      AutofillMetrics::SaveTypeMetric::LOCAL, 1);
+
+  // UMA should have recorded bubble rejection.
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveCreditCardPrompt.Local.FirstShow",
+      AutofillMetrics::SAVE_CARD_ICON_SHOWN_WITHOUT_PROMPT, 1);
+}
+
+// Tests overall StrikeDatabase interaction with the upload save bubble. Runs an
+// example of declining the prompt three times and ensuring that the
+// offer-to-save bubble does not appear on the fourth try. Then, ensures that no
+// strikes are added if the card already has max strikes.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
+                       StrikeDatabase_Upload_FullFlowTest) {
+  scoped_feature_list_.InitWithFeatures(
+      // Enabled
+      {features::kAutofillSaveCardImprovedUserConsent,
+       features::kAutofillSaveCreditCardUsesStrikeSystemV2},
+      // Disabled
+      {});
+
+  bool controller_observer_set = false;
+
+  // Start sync.
+  harness_->SetupSync();
+
+  // Set up the Payments RPC.
+  SetUploadDetailsRpcPaymentsAccepts();
+
+  // Show and ignore the bubble kMaxStrikesToPreventPoppingUpOfferToSavePrompt
+  // times in order to accrue maximum strikes.
+  for (int i = 0; i < kMaxStrikesToPreventPoppingUpOfferToSavePrompt; i++) {
+    // Submitting the form should show the upload save bubble and legal footer.
+    // (Must wait for response from Payments before accessing the controller.)
+    ResetEventWaiterForSequence(
+        {DialogEvent::REQUESTED_UPLOAD_SAVE,
+         DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE});
+    NavigateTo(kCreditCardUploadForm);
+    FillAndSubmitForm();
+    WaitForObservedEvent();
+    EXPECT_TRUE(FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_UPLOAD)
+                    ->visible());
+    EXPECT_TRUE(FindViewInBubbleById(DialogViewId::FOOTNOTE_VIEW)->visible());
+
+    if (!controller_observer_set) {
+      // Add an event observer to the controller.
+      AddEventObserverToController();
+      ReduceAnimationTime();
+      controller_observer_set = true;
+    }
+
+    base::HistogramTester histogram_tester;
+
+    ClickOnCancelButton(/*strike_expected=*/true);
+    WaitForObservedEvent();
+
+    // Ensure that a strike was added due to the bubble being declined.
+    // The sample logged is the Nth strike added, or (i+1).
+    histogram_tester.ExpectUniqueSample(
+        "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave",
+        /*sample=*/(i + 1), /*count=*/1);
+  }
+
+  base::HistogramTester histogram_tester;
+
+  // Submit the form a fourth time. Since the card now has maximum strikes (3),
+  // the icon should be shown but the bubble should not.
+  ResetEventWaiterForSequence(
+      {DialogEvent::REQUESTED_UPLOAD_SAVE,
+       DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(GetSaveCardIconView()->visible());
+  EXPECT_FALSE(GetSaveCardBubbleViews());
+
+  // Click the icon to show the bubble.
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+  ClickOnView(GetSaveCardIconView());
+  WaitForObservedEvent();
+  EXPECT_TRUE(
+      FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_UPLOAD)->visible());
+  EXPECT_TRUE(FindViewInBubbleById(DialogViewId::FOOTNOTE_VIEW)->visible());
+
+  ClickOnCancelButton();
+
+  // Ensure that no strike was added because the card already had max strikes.
+  histogram_tester.ExpectTotalCount(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave", 0);
+
+  // Verify that the correct histogram entry was logged.
+  histogram_tester.ExpectBucketCount(
+      "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes",
+      AutofillMetrics::SaveTypeMetric::SERVER, 1);
+
+  // UMA should have recorded bubble rejection.
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveCreditCardPrompt.Upload.FirstShow",
+      AutofillMetrics::SAVE_CARD_ICON_SHOWN_WITHOUT_PROMPT, 1);
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
index 9ec4daf..13b25a15 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
@@ -8,8 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/fake_signin_manager_builder.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
@@ -17,6 +16,7 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
 #include "ui/views/window/dialog_client_view.h"
 
 class BookmarkBubbleViewBrowserTest : public DialogBrowserTest {
@@ -26,15 +26,14 @@
   // DialogBrowserTest:
   void ShowUi(const std::string& name) override {
 #if !defined(OS_CHROMEOS)
+    identity::IdentityManager* identity_manager =
+        IdentityManagerFactory::GetForProfile(browser()->profile());
     if (name == "bookmark_details") {
-      SigninManagerFactory::GetForProfile(browser()->profile())
-          ->SignOut(signin_metrics::SIGNOUT_TEST,
-                    signin_metrics::SignoutDelete::IGNORE_METRIC);
+      identity::ClearPrimaryAccount(
+          identity_manager, identity::ClearPrimaryAccountPolicy::DEFAULT);
     } else {
-      constexpr char kTestGaiaID[] = "test";
       constexpr char kTestUserEmail[] = "testuser@gtest.com";
-      SigninManagerFactory::GetForProfile(browser()->profile())
-          ->SetAuthenticatedAccountInfo(kTestGaiaID, kTestUserEmail);
+      identity::MakePrimaryAccountAvailable(identity_manager, kTestUserEmail);
     }
 #endif
 
diff --git a/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller.cc b/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller.cc
index 1b944c80..770f325 100644
--- a/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller.cc
+++ b/chrome/browser/ui/views/feature_promos/reopen_tab_promo_controller.cc
@@ -6,6 +6,7 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/in_product_help/in_product_help.h"
 #include "chrome/browser/ui/in_product_help/reopen_tab_in_product_help.h"
 #include "chrome/browser/ui/in_product_help/reopen_tab_in_product_help_factory.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
@@ -15,6 +16,7 @@
 #include "chrome/browser/ui/views/toolbar/browser_app_menu_button.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/feature_engagement/public/feature_constants.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 
 namespace {
@@ -63,7 +65,7 @@
   BrowserAppMenuButton* app_menu_button =
       browser_view_->toolbar()->app_menu_button();
   app_menu_button->AddMenuListener(this);
-  app_menu_button->SetPromoIsShowing(true);
+  app_menu_button->SetPromoFeature(InProductHelpFeature::kReopenTab);
 
   promo_bubble_ = FeaturePromoBubbleView::CreateOwned(
       app_menu_button, views::BubbleBorder::Arrow::TOP_RIGHT,
@@ -84,7 +86,6 @@
 
   AppMenu* app_menu = app_menu_button->app_menu();
   app_menu->AddObserver(this);
-  app_menu->ShowReopenTabPromo();
 }
 
 void ReopenTabPromoController::OnWidgetDestroying(views::Widget* widget) {
@@ -100,7 +101,7 @@
     BrowserAppMenuButton* app_menu_button =
         browser_view_->toolbar()->app_menu_button();
     app_menu_button->RemoveMenuListener(this);
-    app_menu_button->SetPromoIsShowing(false);
+    app_menu_button->SetPromoFeature(base::nullopt);
     iph_service_->HelpDismissed();
   }
 }
@@ -116,7 +117,7 @@
 
   iph_service_->HelpDismissed();
 
-  browser_view_->toolbar()->app_menu_button()->SetPromoIsShowing(false);
+  browser_view_->toolbar()->app_menu_button()->SetPromoFeature(base::nullopt);
 
   AppMenu* app_menu = browser_view_->toolbar()->app_menu_button()->app_menu();
   app_menu->RemoveObserver(this);
diff --git a/chrome/browser/ui/views/frame/app_menu_button.cc b/chrome/browser/ui/views/frame/app_menu_button.cc
index d8cbe52..a302144 100644
--- a/chrome/browser/ui/views/frame/app_menu_button.cc
+++ b/chrome/browser/ui/views/frame/app_menu_button.cc
@@ -40,13 +40,14 @@
 
 void AppMenuButton::InitMenu(std::unique_ptr<AppMenuModel> menu_model,
                              Browser* browser,
-                             int run_flags) {
+                             int run_flags,
+                             bool alert_reopen_tab_items) {
   // |menu_| must be reset before |menu_model_| is destroyed, as per the comment
   // in the class declaration.
   menu_.reset();
   menu_model_ = std::move(menu_model);
   menu_model_->Init();
-  menu_ = std::make_unique<AppMenu>(browser, run_flags);
+  menu_ = std::make_unique<AppMenu>(browser, run_flags, alert_reopen_tab_items);
   menu_->Init(menu_model_.get());
 
   for (views::MenuListener& observer : menu_listeners_)
diff --git a/chrome/browser/ui/views/frame/app_menu_button.h b/chrome/browser/ui/views/frame/app_menu_button.h
index 409ce46d..ba51fac 100644
--- a/chrome/browser/ui/views/frame/app_menu_button.h
+++ b/chrome/browser/ui/views/frame/app_menu_button.h
@@ -47,10 +47,11 @@
 
  protected:
   // Create (but don't show) the menu. |menu_model| should be a newly created
-  // AppMenuModel.
+  // AppMenuModel.  The other params are forwarded to the created AppMenu.
   void InitMenu(std::unique_ptr<AppMenuModel> menu_model,
                 Browser* browser,
-                int run_flags);
+                int run_flags,
+                bool alert_reopen_tab_items);
 
   AppMenu* menu() { return menu_.get(); }
   const AppMenu* menu() const { return menu_.get(); }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 7311cb0..7e3c9fa 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -3030,14 +3030,12 @@
 
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
 void BrowserView::ShowInProductHelpPromo(InProductHelpFeature iph_feature) {
-  switch (iph_feature) {
-    case InProductHelpFeature::kReopenTab:
-      if (!reopen_tab_promo_controller_) {
-        reopen_tab_promo_controller_ =
-            std::make_unique<ReopenTabPromoController>(this);
-      }
-      reopen_tab_promo_controller_->ShowPromo();
-      break;
+  if (iph_feature == InProductHelpFeature::kReopenTab) {
+    if (!reopen_tab_promo_controller_) {
+      reopen_tab_promo_controller_ =
+          std::make_unique<ReopenTabPromoController>(this);
+    }
+    reopen_tab_promo_controller_->ShowPromo();
   }
 }
 #endif
diff --git a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
index df1cced..9f45c9eb 100644
--- a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
+++ b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
@@ -71,7 +71,7 @@
                                               const ui::Event* event) {
   Browser* browser = browser_view_->browser();
   InitMenu(std::make_unique<HostedAppMenuModel>(browser_view_, browser),
-           browser, AppMenu::NO_FLAGS);
+           browser, AppMenu::NO_FLAGS, false);
 
   menu()->RunMenu(this);
 
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index aa28a73..efa1185 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -785,8 +785,10 @@
 
 // AppMenu ------------------------------------------------------------------
 
-AppMenu::AppMenu(Browser* browser, int run_flags)
-    : browser_(browser), run_flags_(run_flags) {
+AppMenu::AppMenu(Browser* browser, int run_flags, bool alert_reopen_tab_items)
+    : browser_(browser),
+      run_flags_(run_flags),
+      alert_reopen_tab_items_(alert_reopen_tab_items) {
   registrar_.Add(this, chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED,
                  content::Source<Profile>(browser_->profile()));
 }
@@ -822,17 +824,9 @@
 void AppMenu::RunMenu(views::MenuButton* host) {
   base::RecordAction(UserMetricsAction("ShowAppMenu"));
 
-  // If we are displaying reopen tab in-product help, tell the menu runner to
-  // show alerts for the recent tabs submenu and the last closed tab menu item.
-  base::flat_set<int> alerted_commands;
-  if (showing_reopen_tab_promo_) {
-    alerted_commands.insert(IDC_RECENT_TABS_MENU);
-    alerted_commands.insert(AppMenuModel::kMinRecentTabsCommandId);
-  }
-
-  menu_runner_->RunMenuAt(
-      host->GetWidget(), host, host->GetAnchorBoundsInScreen(),
-      views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_NONE, alerted_commands);
+  menu_runner_->RunMenuAt(host->GetWidget(), host,
+                          host->GetAnchorBoundsInScreen(),
+                          views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_NONE);
 
   for (AppMenuObserver& observer : observer_list_)
     observer.AppMenuShown();
@@ -847,10 +841,6 @@
   return menu_runner_.get() && menu_runner_->IsRunning();
 }
 
-void AppMenu::ShowReopenTabPromo() {
-  showing_reopen_tab_promo_ = true;
-}
-
 void AppMenu::AddObserver(AppMenuObserver* observer) {
   observer_list_.AddObserver(observer);
 }
@@ -1233,6 +1223,14 @@
       if (model->GetIconAt(model_index, &icon))
         menu_item->SetIcon(*icon.ToImageSkia());
     }
+
+    // If we want to show items relating to reopening the last-closed tab as
+    // alerted, we specifically need to show alerts on the recent tabs submenu
+    // and the last closed tab menu item.
+    if (alert_reopen_tab_items_ &&
+        ((command_id == IDC_RECENT_TABS_MENU) ||
+         (command_id == AppMenuModel::kMinRecentTabsCommandId)))
+      menu_item->SetAlerted(true);
   }
 
   return menu_item;
diff --git a/chrome/browser/ui/views/toolbar/app_menu.h b/chrome/browser/ui/views/toolbar/app_menu.h
index 919625b..ecf5701 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.h
+++ b/chrome/browser/ui/views/toolbar/app_menu.h
@@ -41,7 +41,7 @@
     FOR_DROP = 1 << 0,
   };
 
-  AppMenu(Browser* browser, int run_flags);
+  AppMenu(Browser* browser, int run_flags, bool alert_reopen_tab_items);
   ~AppMenu() override;
 
   void Init(ui::MenuModel* model);
@@ -59,9 +59,6 @@
 
   views::MenuItemView* root_menu_item() { return root_; }
 
-  // Highlight menu items for reopen tab in-product help.
-  void ShowReopenTabPromo();
-
   void AddObserver(AppMenuObserver* observer);
   void RemoveObserver(AppMenuObserver* observer);
 
@@ -197,15 +194,14 @@
   // The bit mask of RunFlags.
   const int run_flags_;
 
+  // Whether to show items relating to reopening the last-closed tab as alerted.
+  const bool alert_reopen_tab_items_;
+
   base::ObserverList<AppMenuObserver>::Unchecked observer_list_;
 
   // Records the time from when menu opens to when the user selects a menu item.
   base::ElapsedTimer menu_opened_timer_;
 
-  // Whether we are showing reopen tab in-product help. If true, the MenuRunner
-  // is told to highlight the appropriate menu items.
-  bool showing_reopen_tab_promo_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(AppMenu);
 };
 
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
index 54c2565..b68f632b 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/grit/chromium_strings.h"
+#include "components/feature_engagement/public/feature_constants.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -47,6 +48,9 @@
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #endif  // defined(OS_CHROMEOS)
 
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+#include "chrome/browser/ui/in_product_help/in_product_help.h"
+
 namespace {
 
 // Button background and icon color for in-product help promos.
@@ -55,6 +59,7 @@
 constexpr SkColor kFeaturePromoHighlightColor = gfx::kGoogleBlue600;
 
 }  // namespace
+#endif
 
 // static
 bool BrowserAppMenuButton::g_open_app_immediately_for_testing = false;
@@ -94,21 +99,23 @@
   UpdateIcon();
 }
 
-void BrowserAppMenuButton::SetPromoIsShowing(bool promo_is_showing) {
-  if (promo_is_showing_ == promo_is_showing)
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+void BrowserAppMenuButton::SetPromoFeature(
+    base::Optional<InProductHelpFeature> promo_feature) {
+  if (promo_feature_ == promo_feature)
     return;
 
-  promo_is_showing_ = promo_is_showing;
-  // We override GetInkDropBaseColor below in the |promo_is_showing_| case. This
-  // sets the ink drop into the activated state, which will highlight it in the
-  // desired color.
-  GetInkDrop()->AnimateToState(promo_is_showing_
-                                   ? views::InkDropState::ACTIVATED
-                                   : views::InkDropState::HIDDEN);
+  promo_feature_ = promo_feature;
+  // We override GetInkDropBaseColor below when |promo_feature_| is non-null.
+  // This sets the ink drop into the activated state, which will highlight it in
+  // the desired color.
+  GetInkDrop()->AnimateToState(promo_feature_ ? views::InkDropState::ACTIVATED
+                                              : views::InkDropState::HIDDEN);
 
   UpdateIcon();
   SchedulePaint();
 }
+#endif
 
 void BrowserAppMenuButton::ShowMenu(bool for_drop) {
   if (IsMenuShowing())
@@ -121,11 +128,15 @@
 #endif
 
   Browser* browser = toolbar_view_->browser();
-
+  bool alert_reopen_tab_items = false;
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+  alert_reopen_tab_items = promo_feature_ == InProductHelpFeature::kReopenTab;
+#endif
   InitMenu(
       std::make_unique<AppMenuModel>(toolbar_view_, browser,
                                      toolbar_view_->app_menu_icon_controller()),
-      browser, for_drop ? AppMenu::FOR_DROP : AppMenu::NO_FLAGS);
+      browser, for_drop ? AppMenu::FOR_DROP : AppMenu::NO_FLAGS,
+      alert_reopen_tab_items);
 
   base::TimeTicks menu_open_time = base::TimeTicks::Now();
   menu()->RunMenu(this);
@@ -149,10 +160,12 @@
   const ui::NativeTheme* native_theme = GetNativeTheme();
   switch (type_and_severity_.severity) {
     case AppMenuIconController::Severity::NONE:
-      severity_color = promo_is_showing_
-                           ? kFeaturePromoHighlightColor
-                           : GetThemeProvider()->GetColor(
-                                 ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
+      severity_color = GetThemeProvider()->GetColor(
+          ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+      if (promo_feature_)
+        severity_color = kFeaturePromoHighlightColor;
+#endif
       break;
     case AppMenuIconController::Severity::LOW:
       severity_color = native_theme->GetSystemColor(
@@ -283,6 +296,9 @@
 }
 
 SkColor BrowserAppMenuButton::GetInkDropBaseColor() const {
-  return promo_is_showing_ ? kFeaturePromoHighlightColor
-                           : AppMenuButton::GetInkDropBaseColor();
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+  if (promo_feature_)
+    return kFeaturePromoHighlightColor;
+#endif
+  return AppMenuButton::GetInkDropBaseColor();
 }
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
index dbfba54..3d5b959a 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
@@ -13,10 +13,14 @@
 #include "base/scoped_observer.h"
 #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
 #include "chrome/browser/ui/views/frame/app_menu_button.h"
+#include "components/feature_engagement/buildflags.h"
 #include "ui/base/material_design/material_design_controller_observer.h"
 #include "ui/views/view.h"
 
 class ToolbarView;
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+enum class InProductHelpFeature;
+#endif
 
 // The app menu button in the main browser window (as opposed to hosted app
 // windows, which is implemented in HostedAppMenuButton).
@@ -37,9 +41,12 @@
   // drag-and-drop operation.
   void ShowMenu(bool for_drop);
 
-  // Sets whether an in-product help feature promo is showing for the app menu.
-  // When true, the button is highlighted in a noticeable color.
-  void SetPromoIsShowing(bool promo_is_showing);
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+  // Called to inform the button that it's being used as an anchor for a promo
+  // for |promo_feature|.  When this is non-null, the button is highlighted in a
+  // noticeable color, and the menu item appearance may be affected.
+  void SetPromoFeature(base::Optional<InProductHelpFeature> promo_feature);
+#endif
 
   // views::MenuButton:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
@@ -85,8 +92,10 @@
   // Our owning toolbar view.
   ToolbarView* const toolbar_view_;
 
-  // Whether an in-product help promo is currently showing for the app menu.
-  bool promo_is_showing_ = false;
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+  // The feature, if any, for which this button is anchoring a promo.
+  base::Optional<InProductHelpFeature> promo_feature_;
+#endif
 
   ScopedObserver<ui::MaterialDesignController,
                  ui::MaterialDesignControllerObserver>
diff --git a/chrome/browser/ui/webui/conflicts/conflicts_handler.cc b/chrome/browser/ui/webui/conflicts/conflicts_handler.cc
index 5d2afa8..c2e6807 100644
--- a/chrome/browser/ui/webui/conflicts/conflicts_handler.cc
+++ b/chrome/browser/ui/webui/conflicts/conflicts_handler.cc
@@ -22,6 +22,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(GOOGLE_CHROME_BUILD)
+#include "base/enterprise_util.h"
 #include "base/win/win_util.h"
 #include "chrome/browser/conflicts/incompatible_applications_updater_win.h"
 #include "chrome/browser/conflicts/module_blacklist_cache_updater_win.h"
@@ -303,7 +304,7 @@
     third_party_features_status_ = kFeatureDisabled;
   }
 
-  if (base::win::IsEnterpriseManaged())
+  if (base::IsMachineExternallyManaged())
     third_party_features_status_ = kEnterpriseManaged;
 
   // The above 3 cases are the only possible reasons why the manager wouldn't
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index cc2994c..85aa19d 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -64,7 +64,7 @@
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #elif defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 #endif
 
 using content::WebContents;
@@ -308,9 +308,9 @@
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   enterprise_managed = connector->IsEnterpriseManaged();
 #elif defined(OS_WIN)
-  enterprise_managed = base::win::IsEnterpriseManaged();
+  enterprise_managed = base::IsMachineExternallyManaged();
 #endif
-  source->AddBoolean("isEnterpriseManaged", enterprise_managed);
+  source->AddBoolean("IsEnterpriseManaged", enterprise_managed);
 
   bool nup_printing_enabled =
       base::FeatureList::IsEnabled(features::kNupPrinting);
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index 4a76310..8d0a6d5 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -1337,15 +1337,14 @@
   if (!profile_->HasOffTheRecordProfile())
     return;
 
+  // At the moment, off the record chooser permissions are not included in the
+  // chooser permissions.
+  // TODO(https://crbug.com/927372): When chooser permissions are included,
+  // attach SiteSettingsHandler as an observer to the chooser contexts.
   auto* map = HostContentSettingsMapFactory::GetForProfile(
       profile_->GetOffTheRecordProfile());
   if (!observer_.IsObserving(map))
     observer_.Add(map);
-
-  auto* usb_context = UsbChooserContextFactory::GetForProfile(
-      profile_->GetOffTheRecordProfile());
-  if (!chooser_observer_.IsObserving(usb_context))
-    chooser_observer_.Add(usb_context);
 }
 
 void SiteSettingsHandler::TreeNodesAdded(ui::TreeModel* model,
diff --git a/chrome/browser/ui/webui/site_settings_helper.cc b/chrome/browser/ui/webui/site_settings_helper.cc
index 89778049..d7aa8eb 100644
--- a/chrome/browser/ui/webui/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/site_settings_helper.cc
@@ -644,6 +644,8 @@
     const ChooserTypeNameEntry& chooser_type) {
   auto exceptions = std::make_unique<base::ListValue>();
 
+  // TODO(https://crbug.com/927372): Combine the off the record permissions with
+  // the main profile permissions so that the UI is able to display them.
   if (incognito) {
     if (!profile->HasOffTheRecordProfile())
       return exceptions;
diff --git a/chrome/browser/ui/webui/welcome/nux_helper.cc b/chrome/browser/ui/webui/welcome/nux_helper.cc
index a780e4c..2f9d839 100644
--- a/chrome/browser/ui/webui/welcome/nux_helper.cc
+++ b/chrome/browser/ui/webui/welcome/nux_helper.cc
@@ -17,6 +17,10 @@
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 
+#if defined(OS_MACOSX)
+#include "base/enterprise_util.h"
+#endif  // defined(OS_MACOSX)
+
 namespace nux {
 // This feature flag is used to force the feature to be turned on for non-win
 // and non-branded builds, like with tests or development on other platforms.
@@ -56,9 +60,8 @@
 #if defined(GOOGLE_CHROME_BUILD)
 
 #if defined(OS_MACOSX)
-  // TODO(hcarmona): don't enable if enterprise
-  return true;
-#endif  // defined(OS_WIN)
+  return !base::IsMachineExternallyManaged();
+#endif  // defined(OS_MACOSX)
 
 #if defined(OS_WIN)
   // To avoid diluting data collection, existing users should not be assigned
diff --git a/chrome/browser/upgrade_detector/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
index 04ea6f5..2d9ea18 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
+++ b/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
@@ -40,7 +40,7 @@
 #include "components/version_info/version_info.h"
 
 #if defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 #include "chrome/installer/util/google_update_settings.h"
 #include "chrome/installer/util/install_util.h"
 #elif defined(OS_MACOSX)
@@ -400,7 +400,7 @@
 
 #if defined(OS_WIN)
     // Don't show the update bubbles to enterprise users.
-    if (base::win::IsEnterpriseManaged())
+    if (base::IsMachineExternallyManaged())
       return false;
 #endif
   }
diff --git a/chrome/common/service_process_util_posix.cc b/chrome/common/service_process_util_posix.cc
index d20efee..c23fbb2 100644
--- a/chrome/common/service_process_util_posix.cc
+++ b/chrome/common/service_process_util_posix.cc
@@ -139,6 +139,9 @@
   // with base::FilePathWatcher::Watch().
   DCHECK(!task_runner || task_runner->BelongsToCurrentThread());
 
+  // Cancel any pending file-descriptor watch before closing the descriptor.
+  watcher.StopWatchingFileDescriptor();
+
   if (sockets[0] != -1) {
     if (IGNORE_EINTR(close(sockets[0]))) {
       DPLOG(ERROR) << "close";
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index d7369ec..5cc0b98c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -522,7 +522,6 @@
     }
 
     deps += [
-      "//ash:interactive_ui_test_support",
       "//ash:test_support",
       "//ash/public/interfaces:test_interfaces",
       "//chrome/browser/chromeos:arc_test_support",
@@ -1962,10 +1961,6 @@
         "../browser/ui/webui/chromeos/system_web_dialog_browsertest.cc",
         "../browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc",
         "../browser/ui/window_sizer/window_sizer_ash_uitest.cc",
-        "//ash/accelerators/accelerator_interactive_uitest_chromeos.cc",
-        "//ash/app_list/app_list_interactive_uitest.cc",
-        "//ash/drag_drop/drag_drop_interactive_uitest.cc",
-        "//ash/wm/native_cursor_manager_ash_interactive_uitest.cc",
         "base/interactive_test_utils.cc",
         "base/interactive_test_utils.h",
         "base/interactive_test_utils_aura.cc",
@@ -2570,7 +2565,6 @@
     "../browser/download/chrome_download_manager_delegate_unittest.cc",
     "../browser/download/download_history_unittest.cc",
     "../browser/download/download_item_model_unittest.cc",
-    "../browser/download/download_path_reservation_tracker_unittest.cc",
     "../browser/download/download_prefs_unittest.cc",
     "../browser/download/download_query_unittest.cc",
     "../browser/download/download_request_limiter_unittest.cc",
diff --git a/chrome/test/base/in_process_browser_test_browsertest.cc b/chrome/test/base/in_process_browser_test_browsertest.cc
index 83dc373..79e3260 100644
--- a/chrome/test/base/in_process_browser_test_browsertest.cc
+++ b/chrome/test/base/in_process_browser_test_browsertest.cc
@@ -97,9 +97,7 @@
 
 // On Mac this crashes inside cc::SingleThreadProxy::SetNeedsCommit. See
 // https://ci.chromium.org/b/8923336499994443392
-// On ChromeOS this crashes because ProfileIOData and NetworkContext both try
-// to set up NSS on different threads, which it doesn't like.
-#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
+#if !defined(OS_MACOSX)
 class SingleProcessBrowserTest : public InProcessBrowserTest {
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
index 40b5c1e..e3ac345 100644
--- a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
@@ -235,17 +235,14 @@
   RunTestViaHTTP("FileChooser_SaveAsCancel");
 }
 
-#if defined(OS_WIN) || defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#if defined(OS_WIN)
 // On Windows, tests that a file downloaded via PPAPI FileChooser API has the
 // mark-of-the-web. The PPAPI FileChooser implementation invokes QuarantineFile
 // in order to mark the file as being downloaded from the web as soon as the
-// file is created. This MOTW prevents the file being opened without due
+// file is created. This MotW prevents the file being opened without due
 // security warnings if the file is executable.
 //
-// On Linux Desktop, the setxattr call is made to set 'user.xdg.origin.url' and
-// the non-standard 'user.xdg.referrer.url' extended attributes to accomplish
-// the same thing. See
-// https://www.freedesktop.org/wiki/CommonExtendedAttributes/.
+// TODO(crbug.com/927074): Enable this test on macOS.
 IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTest, FileChooser_Quarantine) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   base::ScopedTempDir temp_dir;
@@ -265,7 +262,7 @@
   ASSERT_TRUE(base::PathExists(actual_filename));
   EXPECT_TRUE(download::IsFileQuarantined(actual_filename, GURL(), GURL()));
 }
-#endif  // defined(OS_WIN) || defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#endif  // defined(OS_WIN)
 
 #if defined(FULL_SAFE_BROWSING)
 // These tests only make sense when SafeBrowsing is enabled. They verify
diff --git a/chromeos/components/tether/connect_tethering_operation.cc b/chromeos/components/tether/connect_tethering_operation.cc
index 4e65c90..cad30863 100644
--- a/chromeos/components/tether/connect_tethering_operation.cc
+++ b/chromeos/components/tether/connect_tethering_operation.cc
@@ -148,7 +148,7 @@
     }
   } else {
     PA_LOG(WARNING)
-        << "Received ConnectTetheringResponse from unexpected device with ID "
+        << "Received failing ConnectTetheringResponse from device with ID "
         << remote_device.GetTruncatedDeviceIdForLogs() << " and "
         << "response_code == " << response->response_code() << ".";
     error_code_to_return_ = ConnectTetheringResponseCodeToHostResponseErrorCode(
diff --git a/chromeos/services/assistant/public/features.cc b/chromeos/services/assistant/public/features.cc
index 39ad4d2..5009cc7 100644
--- a/chromeos/services/assistant/public/features.cc
+++ b/chromeos/services/assistant/public/features.cc
@@ -19,6 +19,9 @@
 const base::Feature kAssistantAppSupport{"AssistantAppSupport",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kInAssistantNotifications{
+    "InAssistantNotifications", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kEnableDspHotword{"EnableDspHotword",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -27,6 +30,7 @@
 
 const base::Feature kTimerNotification{"ChromeOSAssistantTimerNotification",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
+
 const base::Feature kEnableTextQueriesWithClientDiscourseContext{
     "AssistantEnableTextQueriesWithClientDiscourseContext",
     base::FEATURE_DISABLED_BY_DEFAULT};
@@ -34,6 +38,10 @@
 const base::Feature kTimerTicks{"ChromeOSAssistantTimerTicks",
                                 base::FEATURE_DISABLED_BY_DEFAULT};
 
+bool IsInAssistantNotificationsEnabled() {
+  return base::FeatureList::IsEnabled(kInAssistantNotifications);
+}
+
 bool IsDspHotwordEnabled() {
   return base::FeatureList::IsEnabled(kEnableDspHotword);
 }
diff --git a/chromeos/services/assistant/public/features.h b/chromeos/services/assistant/public/features.h
index 97fe30f..379645b3 100644
--- a/chromeos/services/assistant/public/features.h
+++ b/chromeos/services/assistant/public/features.h
@@ -24,6 +24,10 @@
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kAssistantAppSupport;
 
+// Enables in-Assistant notifications.
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
+extern const base::Feature kInAssistantNotifications;
+
 // Enables DSP for hotword detection.
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kEnableDspHotword;
@@ -44,6 +48,9 @@
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kTimerTicks;
 
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
+bool IsInAssistantNotificationsEnabled();
+
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsDspHotwordEnabled();
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsStereoAudioInputEnabled();
diff --git a/chromeos/services/device_sync/BUILD.gn b/chromeos/services/device_sync/BUILD.gn
index b252301f..69c9ea5 100644
--- a/chromeos/services/device_sync/BUILD.gn
+++ b/chromeos/services/device_sync/BUILD.gn
@@ -116,6 +116,8 @@
     "fake_cryptauth_device_manager.h",
     "fake_cryptauth_enrollment_manager.cc",
     "fake_cryptauth_enrollment_manager.h",
+    "fake_cryptauth_enrollment_scheduler.cc",
+    "fake_cryptauth_enrollment_scheduler.h",
     "fake_cryptauth_gcm_manager.cc",
     "fake_cryptauth_gcm_manager.h",
     "fake_device_sync.cc",
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_result.cc b/chromeos/services/device_sync/cryptauth_enrollment_result.cc
index 40405b7..060e709d 100644
--- a/chromeos/services/device_sync/cryptauth_enrollment_result.cc
+++ b/chromeos/services/device_sync/cryptauth_enrollment_result.cc
@@ -40,6 +40,9 @@
     const base::Optional<cryptauthv2::ClientDirective>& client_directive)
     : result_code_(result_code), client_directive_(client_directive) {}
 
+CryptAuthEnrollmentResult::CryptAuthEnrollmentResult(
+    const CryptAuthEnrollmentResult& other) = default;
+
 CryptAuthEnrollmentResult::~CryptAuthEnrollmentResult() = default;
 
 bool CryptAuthEnrollmentResult::IsSuccess() const {
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_result.h b/chromeos/services/device_sync/cryptauth_enrollment_result.h
index 2f23e87..c8a0c9d 100644
--- a/chromeos/services/device_sync/cryptauth_enrollment_result.h
+++ b/chromeos/services/device_sync/cryptauth_enrollment_result.h
@@ -59,6 +59,7 @@
   CryptAuthEnrollmentResult(
       ResultCode result_code,
       const base::Optional<cryptauthv2::ClientDirective>& client_directive);
+  CryptAuthEnrollmentResult(const CryptAuthEnrollmentResult& other);
 
   ~CryptAuthEnrollmentResult();
 
diff --git a/chromeos/services/device_sync/fake_cryptauth_enrollment_scheduler.cc b/chromeos/services/device_sync/fake_cryptauth_enrollment_scheduler.cc
new file mode 100644
index 0000000..42d266c
--- /dev/null
+++ b/chromeos/services/device_sync/fake_cryptauth_enrollment_scheduler.cc
@@ -0,0 +1,73 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/services/device_sync/fake_cryptauth_enrollment_scheduler.h"
+
+#include "base/logging.h"
+
+namespace chromeos {
+
+namespace device_sync {
+
+constexpr base::TimeDelta
+    FakeCryptAuthEnrollmentScheduler::kDefaultRefreshPeriod;
+constexpr base::TimeDelta
+    FakeCryptAuthEnrollmentScheduler::kDefaultTimeToNextEnrollmentRequest;
+
+FakeCryptAuthEnrollmentScheduler::FakeCryptAuthEnrollmentScheduler(
+    Delegate* delegate)
+    : CryptAuthEnrollmentScheduler(delegate) {}
+
+FakeCryptAuthEnrollmentScheduler::~FakeCryptAuthEnrollmentScheduler() = default;
+
+void FakeCryptAuthEnrollmentScheduler::RequestEnrollmentNow() {
+  is_waiting_for_enrollment_result_ = true;
+  NotifyEnrollmentRequested(client_directive_policy_reference_);
+}
+
+void FakeCryptAuthEnrollmentScheduler::HandleEnrollmentResult(
+    const CryptAuthEnrollmentResult& enrollment_result) {
+  DCHECK(is_waiting_for_enrollment_result_);
+  handled_enrollment_results_.push_back(enrollment_result);
+  is_waiting_for_enrollment_result_ = false;
+}
+
+base::Optional<base::Time>
+FakeCryptAuthEnrollmentScheduler::GetLastSuccessfulEnrollmentTime() const {
+  return last_successful_enrollment_time_;
+}
+
+base::TimeDelta FakeCryptAuthEnrollmentScheduler::GetRefreshPeriod() const {
+  return refresh_period_;
+}
+
+base::TimeDelta
+FakeCryptAuthEnrollmentScheduler::GetTimeToNextEnrollmentRequest() const {
+  return time_to_next_enrollment_request_;
+}
+
+bool FakeCryptAuthEnrollmentScheduler::IsWaitingForEnrollmentResult() const {
+  return is_waiting_for_enrollment_result_;
+}
+
+size_t FakeCryptAuthEnrollmentScheduler::GetNumConsecutiveFailures() const {
+  return num_consecutive_failures_;
+}
+
+FakeCryptAuthEnrollmentSchedulerDelegate::
+    FakeCryptAuthEnrollmentSchedulerDelegate() = default;
+
+FakeCryptAuthEnrollmentSchedulerDelegate::
+    ~FakeCryptAuthEnrollmentSchedulerDelegate() = default;
+
+void FakeCryptAuthEnrollmentSchedulerDelegate::OnEnrollmentRequested(
+    const base::Optional<cryptauthv2::PolicyReference>&
+        client_directive_policy_reference) {
+  policy_references_from_enrollment_requests_.push_back(
+      client_directive_policy_reference);
+}
+
+}  // namespace device_sync
+
+}  // namespace chromeos
diff --git a/chromeos/services/device_sync/fake_cryptauth_enrollment_scheduler.h b/chromeos/services/device_sync/fake_cryptauth_enrollment_scheduler.h
new file mode 100644
index 0000000..4aaf746
--- /dev/null
+++ b/chromeos/services/device_sync/fake_cryptauth_enrollment_scheduler.h
@@ -0,0 +1,112 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_FAKE_CRYPTAUTH_ENROLLMENT_SCHEDULER_H_
+#define CHROMEOS_SERVICES_DEVICE_SYNC_FAKE_CRYPTAUTH_ENROLLMENT_SCHEDULER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "chromeos/services/device_sync/cryptauth_enrollment_result.h"
+#include "chromeos/services/device_sync/cryptauth_enrollment_scheduler.h"
+#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
+
+namespace chromeos {
+
+namespace device_sync {
+
+// Fake CryptAuthEnrollmentScheduler implementation.
+class FakeCryptAuthEnrollmentScheduler : public CryptAuthEnrollmentScheduler {
+ public:
+  static constexpr base::TimeDelta kDefaultRefreshPeriod =
+      base::TimeDelta::FromDays(30);
+  static constexpr base::TimeDelta kDefaultTimeToNextEnrollmentRequest =
+      base::TimeDelta::FromHours(12);
+
+  FakeCryptAuthEnrollmentScheduler(Delegate* delegate);
+  ~FakeCryptAuthEnrollmentScheduler() override;
+
+  const std::vector<CryptAuthEnrollmentResult>& handled_enrollment_results()
+      const {
+    return handled_enrollment_results_;
+  }
+
+  void set_client_directive_policy_reference(
+      const base::Optional<cryptauthv2::PolicyReference>&
+          client_directive_policy_reference) {
+    client_directive_policy_reference_ = client_directive_policy_reference;
+  }
+
+  void set_last_successful_enrollment_time(
+      base::Time last_successful_enrollment_time) {
+    last_successful_enrollment_time_ = last_successful_enrollment_time;
+  }
+
+  void set_refresh_period(base::TimeDelta refresh_period) {
+    refresh_period_ = refresh_period;
+  }
+
+  void set_time_to_next_enrollment_request(
+      base::TimeDelta time_to_next_enrollment_request) {
+    time_to_next_enrollment_request_ = time_to_next_enrollment_request;
+  }
+
+  void set_num_consecutive_failures(size_t num_consecutive_failures) {
+    num_consecutive_failures_ = num_consecutive_failures;
+  }
+
+  // CryptAuthEnrollmentScheduler:
+  void RequestEnrollmentNow() override;
+  void HandleEnrollmentResult(
+      const CryptAuthEnrollmentResult& enrollment_result) override;
+  base::Optional<base::Time> GetLastSuccessfulEnrollmentTime() const override;
+  base::TimeDelta GetRefreshPeriod() const override;
+  base::TimeDelta GetTimeToNextEnrollmentRequest() const override;
+  bool IsWaitingForEnrollmentResult() const override;
+  size_t GetNumConsecutiveFailures() const override;
+
+ private:
+  std::vector<CryptAuthEnrollmentResult> handled_enrollment_results_;
+  base::Optional<cryptauthv2::PolicyReference>
+      client_directive_policy_reference_;
+  base::Optional<base::Time> last_successful_enrollment_time_;
+  base::TimeDelta refresh_period_ = kDefaultRefreshPeriod;
+  base::TimeDelta time_to_next_enrollment_request_ =
+      kDefaultTimeToNextEnrollmentRequest;
+  size_t num_consecutive_failures_ = 0u;
+  bool is_waiting_for_enrollment_result_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeCryptAuthEnrollmentScheduler);
+};
+
+// Fake CryptAuthEnrollmentScheduler::Delegate implementation.
+class FakeCryptAuthEnrollmentSchedulerDelegate
+    : public CryptAuthEnrollmentScheduler::Delegate {
+ public:
+  FakeCryptAuthEnrollmentSchedulerDelegate();
+  ~FakeCryptAuthEnrollmentSchedulerDelegate() override;
+
+  const std::vector<base::Optional<cryptauthv2::PolicyReference>>&
+  policy_references_from_enrollment_requests() const {
+    return policy_references_from_enrollment_requests_;
+  }
+
+ private:
+  // CryptAuthEnrollmentScheduler::Delegate:
+  void OnEnrollmentRequested(const base::Optional<cryptauthv2::PolicyReference>&
+                                 client_directive_policy_reference) override;
+
+  std::vector<base::Optional<cryptauthv2::PolicyReference>>
+      policy_references_from_enrollment_requests_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeCryptAuthEnrollmentSchedulerDelegate);
+};
+
+}  // namespace device_sync
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_SERVICES_DEVICE_SYNC_FAKE_CRYPTAUTH_ENROLLMENT_SCHEDULER_H_
diff --git a/chromeos/services/device_sync/persistent_enrollment_scheduler.cc b/chromeos/services/device_sync/persistent_enrollment_scheduler.cc
index dae6082..a05cda19 100644
--- a/chromeos/services/device_sync/persistent_enrollment_scheduler.cc
+++ b/chromeos/services/device_sync/persistent_enrollment_scheduler.cc
@@ -124,6 +124,8 @@
   test_factory_ = test_factory;
 }
 
+PersistentEnrollmentScheduler::Factory::~Factory() = default;
+
 std::unique_ptr<CryptAuthEnrollmentScheduler>
 PersistentEnrollmentScheduler::Factory::BuildInstance(
     Delegate* delegate,
diff --git a/chromeos/services/device_sync/persistent_enrollment_scheduler.h b/chromeos/services/device_sync/persistent_enrollment_scheduler.h
index 3ea6b36..61e15f0 100644
--- a/chromeos/services/device_sync/persistent_enrollment_scheduler.h
+++ b/chromeos/services/device_sync/persistent_enrollment_scheduler.h
@@ -35,6 +35,7 @@
    public:
     static Factory* Get();
     static void SetFactoryForTesting(Factory* test_factory);
+    virtual ~Factory();
     virtual std::unique_ptr<CryptAuthEnrollmentScheduler> BuildInstance(
         Delegate* delegate,
         PrefService* pref_service,
diff --git a/chromeos/services/device_sync/persistent_enrollment_scheduler_unittest.cc b/chromeos/services/device_sync/persistent_enrollment_scheduler_unittest.cc
index 7df7acb..55a3287 100644
--- a/chromeos/services/device_sync/persistent_enrollment_scheduler_unittest.cc
+++ b/chromeos/services/device_sync/persistent_enrollment_scheduler_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/test/simple_test_clock.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/timer/mock_timer.h"
+#include "chromeos/services/device_sync/fake_cryptauth_enrollment_scheduler.h"
 #include "chromeos/services/device_sync/pref_names.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -51,47 +52,6 @@
   return encoded_serialized_client_directive;
 }
 
-class FakeDelegate : public CryptAuthEnrollmentScheduler::Delegate {
- public:
-  FakeDelegate() = default;
-
-  ~FakeDelegate() override = default;
-
-  void OnEnrollmentRequested(const base::Optional<cryptauthv2::PolicyReference>&
-                                 client_directive_policy_reference) override {
-    policy_reference_history_.push_back(client_directive_policy_reference);
-  }
-
-  const std::vector<base::Optional<cryptauthv2::PolicyReference>>&
-  policy_reference_history() {
-    return policy_reference_history_;
-  }
-
-  void VerifyReceivedPolicyReference(
-      size_t num_expected_received_policy_references,
-      const base::Optional<cryptauthv2::PolicyReference>&
-          last_expected_received_policy_reference) {
-    EXPECT_EQ(num_expected_received_policy_references,
-              policy_reference_history_.size());
-
-    if (policy_reference_history_.empty())
-      return;
-
-    EXPECT_EQ(last_expected_received_policy_reference.has_value(),
-              policy_reference_history_.back().has_value());
-
-    if (policy_reference_history_.back().has_value() &&
-        last_expected_received_policy_reference.has_value()) {
-      EXPECT_EQ(last_expected_received_policy_reference->SerializeAsString(),
-                policy_reference_history_.back()->SerializeAsString());
-    }
-  }
-
- private:
-  std::vector<base::Optional<cryptauthv2::PolicyReference>>
-      policy_reference_history_;
-};
-
 }  // namespace
 
 class DeviceSyncPersistentEnrollmentSchedulerTest : public testing::Test {
@@ -130,7 +90,43 @@
     test_task_runner->RunUntilIdle();
   }
 
-  FakeDelegate* delegate() { return &fake_delegate_; }
+  void VerifyReceivedPolicyReference(
+      size_t num_expected_received_policy_references,
+      const base::Optional<cryptauthv2::PolicyReference>&
+          last_expected_received_policy_reference) {
+    EXPECT_EQ(
+        num_expected_received_policy_references,
+        fake_delegate_.policy_references_from_enrollment_requests().size());
+
+    if (fake_delegate_.policy_references_from_enrollment_requests().empty())
+      return;
+
+    EXPECT_EQ(last_expected_received_policy_reference.has_value(),
+              fake_delegate_.policy_references_from_enrollment_requests()
+                  .back()
+                  .has_value());
+
+    if (fake_delegate_.policy_references_from_enrollment_requests()
+            .back()
+            .has_value() &&
+        last_expected_received_policy_reference.has_value()) {
+      EXPECT_EQ(last_expected_received_policy_reference->SerializeAsString(),
+                fake_delegate_.policy_references_from_enrollment_requests()
+                    .back()
+                    ->SerializeAsString());
+    }
+  }
+
+  void VerifyLastEnrollmentAttemptTimePref(const base::Time& expected_time) {
+    EXPECT_EQ(
+        pref_service_.GetTime(
+            prefs::kCryptAuthEnrollmentSchedulerLastEnrollmentAttemptTime),
+        expected_time);
+  }
+
+  FakeCryptAuthEnrollmentSchedulerDelegate* delegate() {
+    return &fake_delegate_;
+  }
 
   PrefService* pref_service() { return &pref_service_; }
 
@@ -144,15 +140,8 @@
     return fake_client_directive_;
   }
 
-  void VerifyLastEnrollmentAttemptTimePref(const base::Time& expected_time) {
-    EXPECT_EQ(
-        pref_service_.GetTime(
-            prefs::kCryptAuthEnrollmentSchedulerLastEnrollmentAttemptTime),
-        expected_time);
-  }
-
  private:
-  FakeDelegate fake_delegate_;
+  FakeCryptAuthEnrollmentSchedulerDelegate fake_delegate_;
   TestingPrefServiceSimple pref_service_;
   base::SimpleTestClock test_clock_;
   base::MockOneShotTimer* mock_timer_;
@@ -181,7 +170,7 @@
   timer()->Fire();
 
   EXPECT_TRUE(scheduler()->IsWaitingForEnrollmentResult());
-  delegate()->VerifyReceivedPolicyReference(1, base::nullopt);
+  VerifyReceivedPolicyReference(1, base::nullopt);
 
   CryptAuthEnrollmentResult result(
       CryptAuthEnrollmentResult::ResultCode::kSuccessNewKeysEnrolled,
@@ -202,8 +191,7 @@
 
   timer()->Fire();
 
-  delegate()->VerifyReceivedPolicyReference(
-      2, fake_client_directive().policy_reference());
+  VerifyReceivedPolicyReference(2, fake_client_directive().policy_reference());
 }
 
 TEST_F(DeviceSyncPersistentEnrollmentSchedulerTest,
@@ -237,7 +225,8 @@
 
   scheduler()->RequestEnrollmentNow();
   EXPECT_TRUE(scheduler()->IsWaitingForEnrollmentResult());
-  EXPECT_EQ(1u, delegate()->policy_reference_history().size());
+  EXPECT_EQ(1u,
+            delegate()->policy_references_from_enrollment_requests().size());
 }
 
 TEST_F(DeviceSyncPersistentEnrollmentSchedulerTest,
diff --git a/chromeos/services/multidevice_setup/public/cpp/android_sms_pairing_state_tracker.h b/chromeos/services/multidevice_setup/public/cpp/android_sms_pairing_state_tracker.h
index 6b96062b..b3abbaf 100644
--- a/chromeos/services/multidevice_setup/public/cpp/android_sms_pairing_state_tracker.h
+++ b/chromeos/services/multidevice_setup/public/cpp/android_sms_pairing_state_tracker.h
@@ -14,12 +14,12 @@
 // Inspects and track pairing state of the Messages for Web PWA.
 class AndroidSmsPairingStateTracker {
  public:
-  class Observer {
+  class Observer : public base::CheckedObserver {
    public:
     virtual void OnPairingStateChanged() = 0;
 
    protected:
-    virtual ~Observer() = default;
+    ~Observer() override = default;
   };
 
   AndroidSmsPairingStateTracker();
@@ -35,7 +35,7 @@
   void NotifyPairingStateChanged();
 
  private:
-  base::ObserverList<Observer>::Unchecked observer_list_;
+  base::ObserverList<Observer> observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(AndroidSmsPairingStateTracker);
 };
diff --git a/components/arc/arc_bridge_host_impl.cc b/components/arc/arc_bridge_host_impl.cc
index 9c21978b..46562959 100644
--- a/components/arc/arc_bridge_host_impl.cc
+++ b/components/arc/arc_bridge_host_impl.cc
@@ -12,6 +12,52 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "components/arc/arc_bridge_service.h"
+#include "components/arc/common/accessibility_helper.mojom.h"
+#include "components/arc/common/app.mojom.h"
+#include "components/arc/common/app_permissions.mojom.h"
+#include "components/arc/common/appfuse.mojom.h"
+#include "components/arc/common/audio.mojom.h"
+#include "components/arc/common/auth.mojom.h"
+#include "components/arc/common/backup_settings.mojom.h"
+#include "components/arc/common/bluetooth.mojom.h"
+#include "components/arc/common/boot_phase_monitor.mojom.h"
+#include "components/arc/common/cast_receiver.mojom.h"
+#include "components/arc/common/cert_store.mojom.h"
+#include "components/arc/common/clipboard.mojom.h"
+#include "components/arc/common/crash_collector.mojom.h"
+#include "components/arc/common/disk_quota.mojom.h"
+#include "components/arc/common/enterprise_reporting.mojom.h"
+#include "components/arc/common/file_system.mojom.h"
+#include "components/arc/common/ime.mojom.h"
+#include "components/arc/common/input_method_manager.mojom.h"
+#include "components/arc/common/intent_helper.mojom.h"
+#include "components/arc/common/kiosk.mojom.h"
+#include "components/arc/common/lock_screen.mojom.h"
+#include "components/arc/common/media_session.mojom.h"
+#include "components/arc/common/metrics.mojom.h"
+#include "components/arc/common/midis.mojom.h"
+#include "components/arc/common/net.mojom.h"
+#include "components/arc/common/obb_mounter.mojom.h"
+#include "components/arc/common/oemcrypto.mojom.h"
+#include "components/arc/common/pip.mojom.h"
+#include "components/arc/common/policy.mojom.h"
+#include "components/arc/common/power.mojom.h"
+#include "components/arc/common/print.mojom.h"
+#include "components/arc/common/process.mojom.h"
+#include "components/arc/common/property.mojom.h"
+#include "components/arc/common/rotation_lock.mojom.h"
+#include "components/arc/common/screen_capture.mojom.h"
+#include "components/arc/common/storage_manager.mojom.h"
+#include "components/arc/common/timer.mojom.h"
+#include "components/arc/common/tracing.mojom.h"
+#include "components/arc/common/tts.mojom.h"
+#include "components/arc/common/usb_host.mojom.h"
+#include "components/arc/common/video.mojom.h"
+#include "components/arc/common/voice_interaction_arc_home.mojom.h"
+#include "components/arc/common/voice_interaction_framework.mojom.h"
+#include "components/arc/common/volume_mounter.mojom.h"
+#include "components/arc/common/wake_lock.mojom.h"
+#include "components/arc/common/wallpaper.mojom.h"
 #include "components/arc/mojo_channel.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/service_manager/public/cpp/connector.h"
diff --git a/components/arc/arc_bridge_service.cc b/components/arc/arc_bridge_service.cc
index 3c1b504..99eccc7 100644
--- a/components/arc/arc_bridge_service.cc
+++ b/components/arc/arc_bridge_service.cc
@@ -4,7 +4,54 @@
 
 #include "components/arc/arc_bridge_service.h"
 
+// These header is necessary for instantiation of ConnectionHolder.
+#include "components/arc/common/accessibility_helper.mojom.h"
+#include "components/arc/common/app.mojom.h"
+#include "components/arc/common/app_permissions.mojom.h"
+#include "components/arc/common/appfuse.mojom.h"
 #include "components/arc/common/arc_bridge.mojom.h"
+#include "components/arc/common/audio.mojom.h"
+#include "components/arc/common/auth.mojom.h"
+#include "components/arc/common/backup_settings.mojom.h"
+#include "components/arc/common/bluetooth.mojom.h"
+#include "components/arc/common/boot_phase_monitor.mojom.h"
+#include "components/arc/common/cast_receiver.mojom.h"
+#include "components/arc/common/cert_store.mojom.h"
+#include "components/arc/common/clipboard.mojom.h"
+#include "components/arc/common/crash_collector.mojom.h"
+#include "components/arc/common/disk_quota.mojom.h"
+#include "components/arc/common/enterprise_reporting.mojom.h"
+#include "components/arc/common/file_system.mojom.h"
+#include "components/arc/common/ime.mojom.h"
+#include "components/arc/common/input_method_manager.mojom.h"
+#include "components/arc/common/intent_helper.mojom.h"
+#include "components/arc/common/kiosk.mojom.h"
+#include "components/arc/common/lock_screen.mojom.h"
+#include "components/arc/common/media_session.mojom.h"
+#include "components/arc/common/metrics.mojom.h"
+#include "components/arc/common/midis.mojom.h"
+#include "components/arc/common/net.mojom.h"
+#include "components/arc/common/obb_mounter.mojom.h"
+#include "components/arc/common/oemcrypto.mojom.h"
+#include "components/arc/common/pip.mojom.h"
+#include "components/arc/common/policy.mojom.h"
+#include "components/arc/common/power.mojom.h"
+#include "components/arc/common/print.mojom.h"
+#include "components/arc/common/process.mojom.h"
+#include "components/arc/common/property.mojom.h"
+#include "components/arc/common/rotation_lock.mojom.h"
+#include "components/arc/common/screen_capture.mojom.h"
+#include "components/arc/common/storage_manager.mojom.h"
+#include "components/arc/common/timer.mojom.h"
+#include "components/arc/common/tracing.mojom.h"
+#include "components/arc/common/tts.mojom.h"
+#include "components/arc/common/usb_host.mojom.h"
+#include "components/arc/common/video.mojom.h"
+#include "components/arc/common/voice_interaction_arc_home.mojom.h"
+#include "components/arc/common/voice_interaction_framework.mojom.h"
+#include "components/arc/common/volume_mounter.mojom.h"
+#include "components/arc/common/wake_lock.mojom.h"
+#include "components/arc/common/wallpaper.mojom.h"
 
 namespace arc {
 
diff --git a/components/arc/test/fake_arc_bridge_host.cc b/components/arc/test/fake_arc_bridge_host.cc
index 751d5cd8..5b52f52 100644
--- a/components/arc/test/fake_arc_bridge_host.cc
+++ b/components/arc/test/fake_arc_bridge_host.cc
@@ -4,6 +4,55 @@
 
 #include "components/arc/test/fake_arc_bridge_host.h"
 
+#include "components/arc/common/accessibility_helper.mojom.h"
+#include "components/arc/common/app.mojom.h"
+#include "components/arc/common/app_permissions.mojom.h"
+#include "components/arc/common/appfuse.mojom.h"
+#include "components/arc/common/arc_bridge.mojom.h"
+#include "components/arc/common/audio.mojom.h"
+#include "components/arc/common/auth.mojom.h"
+#include "components/arc/common/backup_settings.mojom.h"
+#include "components/arc/common/bluetooth.mojom.h"
+#include "components/arc/common/boot_phase_monitor.mojom.h"
+#include "components/arc/common/cast_receiver.mojom.h"
+#include "components/arc/common/cert_store.mojom.h"
+#include "components/arc/common/clipboard.mojom.h"
+#include "components/arc/common/crash_collector.mojom.h"
+#include "components/arc/common/disk_quota.mojom.h"
+#include "components/arc/common/enterprise_reporting.mojom.h"
+#include "components/arc/common/file_system.mojom.h"
+#include "components/arc/common/ime.mojom.h"
+#include "components/arc/common/input_method_manager.mojom.h"
+#include "components/arc/common/intent_helper.mojom.h"
+#include "components/arc/common/kiosk.mojom.h"
+#include "components/arc/common/lock_screen.mojom.h"
+#include "components/arc/common/media_session.mojom.h"
+#include "components/arc/common/metrics.mojom.h"
+#include "components/arc/common/midis.mojom.h"
+#include "components/arc/common/net.mojom.h"
+#include "components/arc/common/notifications.mojom.h"
+#include "components/arc/common/obb_mounter.mojom.h"
+#include "components/arc/common/oemcrypto.mojom.h"
+#include "components/arc/common/pip.mojom.h"
+#include "components/arc/common/policy.mojom.h"
+#include "components/arc/common/power.mojom.h"
+#include "components/arc/common/print.mojom.h"
+#include "components/arc/common/process.mojom.h"
+#include "components/arc/common/property.mojom.h"
+#include "components/arc/common/rotation_lock.mojom.h"
+#include "components/arc/common/screen_capture.mojom.h"
+#include "components/arc/common/storage_manager.mojom.h"
+#include "components/arc/common/timer.mojom.h"
+#include "components/arc/common/tracing.mojom.h"
+#include "components/arc/common/tts.mojom.h"
+#include "components/arc/common/usb_host.mojom.h"
+#include "components/arc/common/video.mojom.h"
+#include "components/arc/common/voice_interaction_arc_home.mojom.h"
+#include "components/arc/common/voice_interaction_framework.mojom.h"
+#include "components/arc/common/volume_mounter.mojom.h"
+#include "components/arc/common/wake_lock.mojom.h"
+#include "components/arc/common/wallpaper.mojom.h"
+
 namespace arc {
 
 FakeArcBridgeHost::FakeArcBridgeHost() = default;
diff --git a/components/autofill/core/browser/autofill_data_model.cc b/components/autofill/core/browser/autofill_data_model.cc
index 913bfe2..dd580ec 100644
--- a/components/autofill/core/browser/autofill_data_model.cc
+++ b/components/autofill/core/browser/autofill_data_model.cc
@@ -37,8 +37,9 @@
   return !((other->use_date() - use_date()).InSeconds());
 }
 
-bool AutofillDataModel::CompareFrecency(const AutofillDataModel* other,
-                                        base::Time comparison_time) const {
+bool AutofillDataModel::HasGreaterFrecencyThan(
+    const AutofillDataModel* other,
+    base::Time comparison_time) const {
   double score = GetFrecencyScore(comparison_time);
   double other_score = other->GetFrecencyScore(comparison_time);
 
diff --git a/components/autofill/core/browser/autofill_data_model.h b/components/autofill/core/browser/autofill_data_model.h
index 719df50..a6d005a 100644
--- a/components/autofill/core/browser/autofill_data_model.h
+++ b/components/autofill/core/browser/autofill_data_model.h
@@ -56,8 +56,8 @@
   // a combination of frequency and recency to determine the relevance of the
   // profile. |comparison_time_| allows consistent sorting throughout the
   // comparisons.
-  bool CompareFrecency(const AutofillDataModel* other,
-                       base::Time comparison_time) const;
+  bool HasGreaterFrecencyThan(const AutofillDataModel* other,
+                              base::Time comparison_time) const;
 
   // Gets the metadata associated with this autofill data model.
   virtual AutofillMetadata GetMetadata() const;
diff --git a/components/autofill/core/browser/autofill_data_model_unittest.cc b/components/autofill/core/browser/autofill_data_model_unittest.cc
index 670e50c..2f0c40f 100644
--- a/components/autofill/core/browser/autofill_data_model_unittest.cc
+++ b/components/autofill/core/browser/autofill_data_model_unittest.cc
@@ -110,7 +110,7 @@
 }
 
 enum Expectation { GREATER, LESS };
-struct CompareFrecencyTestCase {
+struct HasGreaterFrecencyThanTestCase {
   const std::string guid_a;
   const int use_count_a;
   const base::Time use_date_a;
@@ -122,10 +122,10 @@
 
 base::Time now = base::Time::Now();
 
-class CompareFrecencyTest
-    : public testing::TestWithParam<CompareFrecencyTestCase> {};
+class HasGreaterFrecencyThanTest
+    : public testing::TestWithParam<HasGreaterFrecencyThanTestCase> {};
 
-TEST_P(CompareFrecencyTest, CompareFrecency) {
+TEST_P(HasGreaterFrecencyThanTest, HasGreaterFrecencyThan) {
   auto test_case = GetParam();
   TestAutofillDataModel model_a(test_case.guid_a, test_case.use_count_a,
                                 test_case.use_date_a);
@@ -133,39 +133,44 @@
                                 test_case.use_date_b);
 
   EXPECT_EQ(test_case.expectation == GREATER,
-            model_a.CompareFrecency(&model_b, now));
+            model_a.HasGreaterFrecencyThan(&model_b, now));
   EXPECT_NE(test_case.expectation == GREATER,
-            model_b.CompareFrecency(&model_a, now));
+            model_b.HasGreaterFrecencyThan(&model_a, now));
 }
 
 INSTANTIATE_TEST_CASE_P(
     AutofillDataModelTest,
-    CompareFrecencyTest,
+    HasGreaterFrecencyThanTest,
     testing::Values(
         // Same frecency, model_a has a smaller GUID (tie breaker).
-        CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 8, now, LESS},
+        HasGreaterFrecencyThanTestCase{"guid_a", 8, now, "guid_b", 8, now,
+                                       LESS},
         // Same recency, model_a has a bigger frequency.
-        CompareFrecencyTestCase{"guid_a", 10, now, "guid_b", 8, now, GREATER},
+        HasGreaterFrecencyThanTestCase{"guid_a", 10, now, "guid_b", 8, now,
+                                       GREATER},
         // Same recency, model_a has a smaller frequency.
-        CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 10, now, LESS},
+        HasGreaterFrecencyThanTestCase{"guid_a", 8, now, "guid_b", 10, now,
+                                       LESS},
         // Same frequency, model_a is more recent.
-        CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 8,
-                                now - base::TimeDelta::FromDays(1), GREATER},
+        HasGreaterFrecencyThanTestCase{"guid_a", 8, now, "guid_b", 8,
+                                       now - base::TimeDelta::FromDays(1),
+                                       GREATER},
         // Same frequency, model_a is less recent.
-        CompareFrecencyTestCase{"guid_a", 8, now - base::TimeDelta::FromDays(1),
-                                "guid_b", 8, now, LESS},
+        HasGreaterFrecencyThanTestCase{"guid_a", 8,
+                                       now - base::TimeDelta::FromDays(1),
+                                       "guid_b", 8, now, LESS},
         // Special case: occasional profiles. A profile with relatively low
         // usage and used recently (model_b) should not rank higher than a more
         // used profile that has been unused for a short amount of time
         // (model_a).
-        CompareFrecencyTestCase{
+        HasGreaterFrecencyThanTestCase{
             "guid_a", 300, now - base::TimeDelta::FromDays(5), "guid_b", 10,
             now - base::TimeDelta::FromDays(1), GREATER},
         // Special case: moving. A new profile used frequently (model_b) should
         // rank higher than a profile with more usage that has not been used for
         // a while (model_a).
-        CompareFrecencyTestCase{"guid_a", 300,
-                                now - base::TimeDelta::FromDays(15), "guid_b",
-                                10, now - base::TimeDelta::FromDays(1), LESS}));
+        HasGreaterFrecencyThanTestCase{
+            "guid_a", 300, now - base::TimeDelta::FromDays(15), "guid_b", 10,
+            now - base::TimeDelta::FromDays(1), LESS}));
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index ac94dac..cffe334 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -838,7 +838,7 @@
   bool other_is_valid = (!use_client_validation || other->IsValidByClient()) &&
                         (!use_server_validation || other->IsValidByServer());
   if (is_valid == other_is_valid)
-    return CompareFrecency(other, comparison_time);
+    return HasGreaterFrecencyThan(other, comparison_time);
   if (is_valid && !other_is_valid)
     return true;
   return false;
@@ -922,7 +922,6 @@
     return;
   }
   DCHECK_EQ(SERVER, validation_source);
-  LOG(ERROR) << __FUNCTION__;
   server_validity_states_[type] = validity;
 }
 
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h
index 1eb99230..ff02d24 100644
--- a/components/autofill/core/browser/autofill_profile.h
+++ b/components/autofill/core/browser/autofill_profile.h
@@ -224,14 +224,17 @@
   // use and updates |previous_use_date_| to the last value of |use_date_|.
   void RecordAndLogUse();
 
-  // Returns true if the current profile has greated frescocency than the
+  // Returns true if the current profile has greater frescocency than the
   // |other|. Frescocency is a combination of validation score and frecency to
-  // determine the relevance of the profile. Please see
-  // AutofillDataModel::CompareFrecency.
+  // determine the relevance of the profile. Frescocency is a total order: it
+  // puts all the valid profiles before the invalid ones, and uses frecency
+  // (another total order) in case of tie. Please see
+  // AutofillDataModel::HasGreaterFrecencyThan.
   bool HasGreaterFrescocencyThan(const AutofillProfile* other,
                                  base::Time comparison_time,
                                  bool use_client_validation,
                                  bool use_server_validation) const;
+
   // Returns false if the profile has any invalid field, according to the client
   // source of validation.
   bool IsValidByClient() const;
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index 9e5e493..f1b3303 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -1873,7 +1873,7 @@
 
 enum Expectation { GREATER, LESS, EQUAL };
 
-struct CompareFrescocencyTestCase {
+struct HasGreaterFrescocencyTestCase {
   const AutofillProfile::ValidityState client_validity_state_a;
   const AutofillProfile::ValidityState server_validity_state_a;
   const AutofillProfile::ValidityState client_validity_state_b;
@@ -1884,10 +1884,10 @@
   Expectation expectation;
 };
 
-class CompareFrescocencyTest
-    : public testing::TestWithParam<CompareFrescocencyTestCase> {};
+class HasGreaterFrescocencyTest
+    : public testing::TestWithParam<HasGreaterFrescocencyTestCase> {};
 
-TEST_P(CompareFrescocencyTest, CompareFrescocency) {
+TEST_P(HasGreaterFrescocencyTest, HasGreaterFrescocency) {
   auto test_case = GetParam();
   AutofillProfile profile_a("00000000-0000-0000-0000-000000000001", "");
   AutofillProfile profile_b("00000000-0000-0000-0000-000000000002", "");
@@ -1908,7 +1908,7 @@
   base::Time now = base::Time::Now();
 
   if (test_case.expectation == EQUAL) {
-    EXPECT_EQ(profile_a.CompareFrecency(&profile_b, now),
+    EXPECT_EQ(profile_a.HasGreaterFrecencyThan(&profile_b, now),
               profile_a.HasGreaterFrescocencyThan(
                   &profile_b, now, test_case.use_client_validation,
                   test_case.use_server_validation));
@@ -1927,58 +1927,58 @@
 
 INSTANTIATE_TEST_CASE_P(
     AutofillProfileTest,
-    CompareFrescocencyTest,
+    HasGreaterFrescocencyTest,
     testing::Values(
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::VALID, AutofillProfile::INVALID,
             AutofillProfile::VALID, AutofillProfile::UNVALIDATED, false, false,
             EQUAL},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::INVALID, AutofillProfile::VALID,
             AutofillProfile::VALID, AutofillProfile::INVALID, false, false,
             EQUAL},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::INVALID, AutofillProfile::VALID,
             AutofillProfile::VALID, AutofillProfile::INVALID, false, true,
             GREATER},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::INVALID, AutofillProfile::INVALID,
             AutofillProfile::VALID, AutofillProfile::INVALID, false, true,
             EQUAL},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::INVALID, AutofillProfile::VALID,
             AutofillProfile::VALID, AutofillProfile::VALID, false, true, EQUAL},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::INVALID, AutofillProfile::INVALID,
             AutofillProfile::VALID, AutofillProfile::UNVALIDATED, false, true,
             LESS},
-        CompareFrescocencyTestCase{AutofillProfile::INVALID,
-                                   AutofillProfile::VALID,
-                                   AutofillProfile::VALID,
-                                   AutofillProfile::INVALID, true, true, EQUAL},
-        CompareFrescocencyTestCase{AutofillProfile::INVALID,
-                                   AutofillProfile::INVALID,
-                                   AutofillProfile::UNVALIDATED,
-                                   AutofillProfile::VALID, true, true, LESS},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
+            AutofillProfile::INVALID, AutofillProfile::VALID,
+            AutofillProfile::VALID, AutofillProfile::INVALID, true, true,
+            EQUAL},
+        HasGreaterFrescocencyTestCase{AutofillProfile::INVALID,
+                                      AutofillProfile::INVALID,
+                                      AutofillProfile::UNVALIDATED,
+                                      AutofillProfile::VALID, true, true, LESS},
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::VALID, AutofillProfile::VALID,
             AutofillProfile::VALID, AutofillProfile::VALID, true, true, EQUAL},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::VALID, AutofillProfile::UNVALIDATED,
             AutofillProfile::VALID, AutofillProfile::INVALID, true, true,
             GREATER},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::VALID, AutofillProfile::INVALID,
             AutofillProfile::INVALID, AutofillProfile::VALID, true, false,
             GREATER},
-        CompareFrescocencyTestCase{AutofillProfile::INVALID,
-                                   AutofillProfile::INVALID,
-                                   AutofillProfile::UNVALIDATED,
-                                   AutofillProfile::VALID, true, false, LESS},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
+            AutofillProfile::INVALID, AutofillProfile::INVALID,
+            AutofillProfile::UNVALIDATED, AutofillProfile::VALID, true, false,
+            LESS},
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::VALID, AutofillProfile::INVALID,
             AutofillProfile::VALID, AutofillProfile::VALID, true, false, EQUAL},
-        CompareFrescocencyTestCase{
+        HasGreaterFrescocencyTestCase{
             AutofillProfile::VALID, AutofillProfile::UNVALIDATED,
             AutofillProfile::INVALID, AutofillProfile::INVALID, true, false,
             GREATER}));
diff --git a/components/autofill/core/browser/form_data_importer.cc b/components/autofill/core/browser/form_data_importer.cc
index 6304adea..20be69d 100644
--- a/components/autofill/core/browser/form_data_importer.cc
+++ b/components/autofill/core/browser/form_data_importer.cc
@@ -488,10 +488,17 @@
     base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
 
     // If we don't know the type of the field, or the user hasn't entered any
-    // information into the field, or the field is non-focusable (hidden), then
-    // skip it.
-    if (!field->IsFieldFillable() || !field->is_focusable || value.empty())
+    // information into the field, then skip it.
+    if (!field->IsFieldFillable() || value.empty())
       continue;
+    // If the field is non-focusable (hidden) after the user entered information
+    // into it, then skip it, unless the experiment to import non-focusable
+    // forms is enabled.
+    if (!field->is_focusable &&
+        !base::FeatureList::IsEnabled(
+            features::kAutofillImportNonFocusableCreditCardForms)) {
+      continue;
+    }
 
     AutofillType field_type = field->Type();
     // Field was not identified as a credit card field.
diff --git a/components/autofill/core/browser/form_data_importer.h b/components/autofill/core/browser/form_data_importer.h
index 56e32ab1..3d263a7d 100644
--- a/components/autofill/core/browser/form_data_importer.h
+++ b/components/autofill/core/browser/form_data_importer.h
@@ -153,6 +153,15 @@
                            AllowDuplicateMaskedServerCardIfFlagEnabled);
   FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, DontDuplicateFullServerCard);
   FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, DontDuplicateMaskedServerCard);
+  FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
+                           ImportFormData_AddressesDisabledOneCreditCard);
+  FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
+                           ImportFormData_AddressCreditCardDisabled);
+  FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
+                           ImportFormData_HiddenCreditCardFormAfterEntered);
+  FRIEND_TEST_ALL_PREFIXES(
+      FormDataImporterTest,
+      ImportFormData_HiddenCreditCardFormAfterEnteredWithExpOff);
   FRIEND_TEST_ALL_PREFIXES(
       FormDataImporterTest,
       ImportFormData_ImportCreditCardRecordType_FullServerCard);
@@ -180,10 +189,6 @@
       FormDataImporterTest,
       ImportFormData_SecondImportResetsCreditCardRecordType);
   FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
-                           ImportFormData_AddressesDisabledOneCreditCard);
-  FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
-                           ImportFormData_AddressCreditCardDisabled);
-  FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
                            ImportFormData_TwoAddressesOneCreditCard);
   FRIEND_TEST_ALL_PREFIXES(
       FormDataImporterTest,
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc
index 8e297de..a205459 100644
--- a/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -2794,6 +2794,101 @@
   ASSERT_FALSE(imported_credit_card);
 }
 
+// Tests that a credit card form that is hidden after receiving input still
+// imports the card.
+TEST_F(FormDataImporterTest, ImportFormData_HiddenCreditCardFormAfterEntered) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillImportNonFocusableCreditCardForms);
+
+  FormData form;
+  form.origin = GURL("https://wwww.foo.com");
+
+  FormFieldData field;
+
+  test::CreateTestFormField("Name on card:", "name_on_card", "Biggie Smalls",
+                            "text", &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+  test::CreateTestFormField("Card Number:", "card_number", "4111111111111111",
+                            "text", &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+  test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text",
+                            &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+  test::CreateTestFormField("Exp Month:", "exp_month", "01", "text", &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+  test::CreateTestFormField("Exp Year:", "exp_year", "2999", "text", &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+
+  FormStructure form_structure(form);
+  form_structure.DetermineHeuristicTypes();
+  std::unique_ptr<CreditCard> imported_credit_card;
+  // Still returns true because the credit card import was successful.
+  EXPECT_TRUE(form_data_importer_->ImportFormData(
+      form_structure, /*profile_autofill_enabled=*/true,
+      /*credit_card_autofill_enabled=*/true,
+      /*should_return_local_card=*/false, &imported_credit_card));
+  ASSERT_TRUE(imported_credit_card);
+  personal_data_manager_->OnAcceptedLocalCreditCardSave(*imported_credit_card);
+
+  WaitForOnPersonalDataChanged();
+
+  // Test that the credit card has been saved.
+  CreditCard expected_card(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&expected_card, "Biggie Smalls", "4111111111111111",
+                          "01", "2999", "");
+  const std::vector<CreditCard*>& results =
+      personal_data_manager_->GetCreditCards();
+  ASSERT_EQ(1U, results.size());
+  EXPECT_EQ(0, expected_card.Compare(*results[0]));
+}
+
+// Tests that a credit card form that is hidden after receiving input does not
+// import the card when the experiment is off.
+TEST_F(FormDataImporterTest,
+       ImportFormData_HiddenCreditCardFormAfterEnteredWithExpOff) {
+  scoped_feature_list_.InitAndDisableFeature(
+      features::kAutofillImportNonFocusableCreditCardForms);
+
+  FormData form;
+  form.origin = GURL("https://wwww.foo.com");
+
+  FormFieldData field;
+
+  test::CreateTestFormField("Name on card:", "name_on_card", "Biggie Smalls",
+                            "text", &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+  test::CreateTestFormField("Card Number:", "card_number", "4111111111111111",
+                            "text", &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+  test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text",
+                            &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+  test::CreateTestFormField("Exp Month:", "exp_month", "01", "text", &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+  test::CreateTestFormField("Exp Year:", "exp_year", "2999", "text", &field);
+  field.is_focusable = false;
+  form.fields.push_back(field);
+
+  FormStructure form_structure(form);
+  form_structure.DetermineHeuristicTypes();
+  std::unique_ptr<CreditCard> imported_credit_card;
+  // Returns false because the credit card import was failed.
+  EXPECT_FALSE(form_data_importer_->ImportFormData(
+      form_structure, /*profile_autofill_enabled=*/true,
+      /*credit_card_autofill_enabled=*/true,
+      /*should_return_local_card=*/false, &imported_credit_card));
+  ASSERT_FALSE(imported_credit_card);
+}
+
 TEST_F(FormDataImporterTest, DontDuplicateFullServerCard) {
   EnableWalletCardImport();
 
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 2ceed114..140650b 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1134,8 +1134,9 @@
       comparator.NormalizeForComparison(field_contents);
 
   if (base::FeatureList::IsEnabled(
-          autofill::features::kAutofillProfileServerValidation))
+          autofill::features::kAutofillProfileServerValidation)) {
     UpdateProfilesServerValidityMapsIfNeeded(GetProfiles());
+  }
 
   // Get the profiles to suggest, which are already sorted.
   std::vector<AutofillProfile*> sorted_profiles = GetProfilesToSuggest();
@@ -1212,7 +1213,7 @@
                      if (a_is_expired != b->IsExpired(comparison_time))
                        return !a_is_expired;
 
-                     return a->CompareFrecency(b, comparison_time);
+                     return a->HasGreaterFrecencyThan(b, comparison_time);
                    });
 
   return cards_to_suggest;
@@ -1467,7 +1468,7 @@
                               const std::unique_ptr<AutofillProfile>& b) {
               if (a->IsVerified() != b->IsVerified())
                 return !a->IsVerified();
-              return a->CompareFrecency(b.get(), comparison_time);
+              return a->HasGreaterFrecencyThan(b.get(), comparison_time);
             });
 
   // Set to true if |existing_profiles| already contains an equivalent profile.
@@ -2193,7 +2194,7 @@
                               const std::unique_ptr<AutofillProfile>& b) {
               if (a->IsVerified() != b->IsVerified())
                 return !a->IsVerified();
-              return a->CompareFrecency(b.get(), comparison_time);
+              return a->HasGreaterFrecencyThan(b.get(), comparison_time);
             });
 
   AutofillProfileComparator comparator(app_locale_);
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index a062e8b..2f253e4 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -129,6 +129,12 @@
 const base::Feature kAutofillGetPaymentsIdentityFromSync{
     "AutofillGetPaymentsIdentityFromSync", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// When enabled, a credit card form that is hidden after receiving input can
+// import the card.
+const base::Feature kAutofillImportNonFocusableCreditCardForms{
+    "AutofillImportNonFocusableCreditCardForms",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // When enabled, autofill suggestions are displayed in the keyboard accessory
 // instead of the regular popup.
 const base::Feature kAutofillKeyboardAccessory{
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index e767b0fd..c93d85f 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -43,6 +43,7 @@
 extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery;
 extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload;
 extern const base::Feature kAutofillGetPaymentsIdentityFromSync;
+extern const base::Feature kAutofillImportNonFocusableCreditCardForms;
 extern const base::Feature kAutofillKeyboardAccessory;
 extern const base::Feature kAutofillLocalCardMigrationShowFeedback;
 extern const base::Feature kAutofillManualFallback;
diff --git a/components/download/internal/common/BUILD.gn b/components/download/internal/common/BUILD.gn
index 0f957ee..a52b848 100644
--- a/components/download/internal/common/BUILD.gn
+++ b/components/download/internal/common/BUILD.gn
@@ -28,6 +28,7 @@
     "download_job_factory.cc",
     "download_job_impl.cc",
     "download_job_impl.h",
+    "download_path_reservation_tracker.cc",
     "download_response_handler.cc",
     "download_stats.cc",
     "download_task_runner.cc",
@@ -61,6 +62,7 @@
     "//components/download/database",
     "//components/download/public/common:interfaces",
     "//components/download/quarantine",
+    "//components/filename_generation",
     "//components/leveldb_proto",
     "//mojo/public/c/system",
     "//net",
@@ -98,6 +100,7 @@
     "download_db_cache_unittest.cc",
     "download_file_unittest.cc",
     "download_item_impl_unittest.cc",
+    "download_path_reservation_tracker_unittest.cc",
     "download_stats_unittest.cc",
     "download_ukm_helper_unittest.cc",
     "parallel_download_job_unittest.cc",
diff --git a/components/download/internal/common/DEPS b/components/download/internal/common/DEPS
index 328cd26..1267c2d 100644
--- a/components/download/internal/common/DEPS
+++ b/components/download/internal/common/DEPS
@@ -3,6 +3,7 @@
   "+components/download/downloader/in_progress",
   "+components/download/public/common",
   "+components/download/quarantine",
+  "+components/filename_generation/filename_generation.h",
   "+components/leveldb_proto",
   "+components/ukm/test_ukm_recorder.h",
   "+crypto",
diff --git a/chrome/browser/download/download_path_reservation_tracker.cc b/components/download/internal/common/download_path_reservation_tracker.cc
similarity index 96%
rename from chrome/browser/download/download_path_reservation_tracker.cc
rename to components/download/internal/common/download_path_reservation_tracker.cc
index d7a6f7b..93bf59b 100644
--- a/chrome/browser/download/download_path_reservation_tracker.cc
+++ b/components/download/internal/common/download_path_reservation_tracker.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/download/download_path_reservation_tracker.h"
+#include "components/download/public/common/download_path_reservation_tracker.h"
 
 #include <stddef.h>
 
@@ -16,7 +16,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -27,16 +26,12 @@
 #include "base/third_party/icu/icu_utf.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "chrome/common/buildflags.h"
-#include "chrome/common/chrome_paths.h"
 #include "components/download/public/common/download_item.h"
 #include "components/filename_generation/filename_generation.h"
-#include "content/public/browser/browser_thread.h"
 #include "net/base/filename_util.h"
 #include "url/gurl.h"
 
-using content::BrowserThread;
-using download::DownloadItem;
+namespace download {
 
 namespace {
 
@@ -183,6 +178,8 @@
   base::FilePath suggested_path;
   base::FilePath default_download_path;
   base::FilePath temporary_path;
+  base::FilePath fallback_directory;  // directory to use when target path
+                                      // cannot be used.
   bool create_target_directory;
   base::Time start_time;
   DownloadPathReservationTracker::FilenameConflictAction conflict_action;
@@ -212,9 +209,7 @@
   // prompted.
   if (!IsPathWritable(info, *target_path)) {
     DVLOG(1) << "Unable to write to path \"" << target_path->value() << "\"";
-    base::FilePath target_dir;
-    base::PathService::Get(chrome::DIR_USER_DOCUMENTS, &target_dir);
-    *target_path = target_dir.Append(target_path->BaseName());
+    *target_path = info.fallback_directory.Append(target_path->BaseName());
     return PathValidationResult::PATH_NOT_WRITABLE;
   }
 
@@ -344,14 +339,12 @@
     const DownloadPathReservationTracker::ReservedPathCallback& callback,
     const base::FilePath* reserved_path,
     PathValidationResult result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   callback.Run(result, *reserved_path);
 }
 
 DownloadItemObserver::DownloadItemObserver(DownloadItem* download_item)
     : download_item_(download_item),
       last_target_path_(download_item->GetTargetFilePath()) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   download_item_->AddObserver(this);
   download_item_->SetUserData(&kUserDataKey, base::WrapUnique(this));
 }
@@ -417,10 +410,10 @@
     DownloadItem* download_item,
     const base::FilePath& target_path,
     const base::FilePath& default_path,
+    const base::FilePath& fallback_directory,
     bool create_directory,
     FilenameConflictAction conflict_action,
     const ReservedPathCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Attach an observer to the download item so that we know when the target
   // path changes and/or the download is no longer active.
   new DownloadItemObserver(download_item);
@@ -435,6 +428,7 @@
                                 target_path,
                                 default_path,
                                 download_item->GetTemporaryFilePath(),
+                                fallback_directory,
                                 create_directory,
                                 download_item->GetStartTime(),
                                 conflict_action,
@@ -458,3 +452,5 @@
 DownloadPathReservationTracker::GetTaskRunner() {
   return g_sequenced_task_runner.Get();
 }
+
+}  // namespace download
diff --git a/chrome/browser/download/download_path_reservation_tracker_unittest.cc b/components/download/internal/common/download_path_reservation_tracker_unittest.cc
similarity index 93%
rename from chrome/browser/download/download_path_reservation_tracker_unittest.cc
rename to components/download/internal/common/download_path_reservation_tracker_unittest.cc
index 1d3cd925..d9d8745 100644
--- a/chrome/browser/download/download_path_reservation_tracker_unittest.cc
+++ b/components/download/internal/common/download_path_reservation_tracker_unittest.cc
@@ -15,25 +15,23 @@
 #include "base/observer_list.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/test/test_file_util.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "chrome/browser/download/download_path_reservation_tracker.h"
-#include "chrome/browser/download/download_target_determiner.h"
+#include "components/download/public/common/download_path_reservation_tracker.h"
 #include "components/download/public/common/mock_download_item.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "content/public/test/test_utils.h"
 #include "net/base/filename_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using download::DownloadItem;
-using download::MockDownloadItem;
 using testing::AnyNumber;
 using testing::Return;
 using testing::ReturnRef;
 using testing::ReturnRefOfCopy;
 
+namespace download {
+
 namespace {
 
 class DownloadPathReservationTrackerTest : public testing::Test {
@@ -48,6 +46,7 @@
   base::FilePath GetPathInDownloadsDirectory(
       const base::FilePath::CharType* suffix);
   bool IsPathInUse(const base::FilePath& path);
+  void RunUntilIdle();
   void CallGetReservedPath(
       DownloadItem* download_item,
       const base::FilePath& target_path,
@@ -62,6 +61,9 @@
   void set_default_download_path(const base::FilePath& path) {
     default_download_path_ = path;
   }
+  void set_fallback_directory(const base::FilePath& path) {
+    fallback_directory_ = path;
+  }
   // Creates a name of form 'a'*repeat + suffix
   base::FilePath GetLongNamePathInDownloadsDirectory(
       size_t repeat,
@@ -70,7 +72,8 @@
  protected:
   base::ScopedTempDir test_download_dir_;
   base::FilePath default_download_path_;
-  content::TestBrowserThreadBundle test_browser_thread_bundle_;
+  base::FilePath fallback_directory_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 
  private:
   void TestReservedPathCallback(base::FilePath* return_path,
@@ -88,14 +91,13 @@
 }
 
 void DownloadPathReservationTrackerTest::TearDown() {
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
 }
 
 std::unique_ptr<MockDownloadItem>
 DownloadPathReservationTrackerTest::CreateDownloadItem(int32_t id) {
   auto item = std::make_unique<::testing::StrictMock<MockDownloadItem>>();
-  EXPECT_CALL(*item, GetId())
-      .WillRepeatedly(Return(id));
+  EXPECT_CALL(*item, GetId()).WillRepeatedly(Return(id));
   EXPECT_CALL(*item, GetTargetFilePath())
       .WillRepeatedly(ReturnRefOfCopy(base::FilePath()));
   EXPECT_CALL(*item, GetTemporaryFilePath())
@@ -129,10 +131,14 @@
 
 bool DownloadPathReservationTrackerTest::IsPathInUse(
     const base::FilePath& path) {
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   return DownloadPathReservationTracker::IsPathInUseForTesting(path);
 }
 
+void DownloadPathReservationTrackerTest::RunUntilIdle() {
+  scoped_task_environment_.RunUntilIdle();
+}
+
 void DownloadPathReservationTrackerTest::CallGetReservedPath(
     DownloadItem* download_item,
     const base::FilePath& target_path,
@@ -145,11 +151,11 @@
   base::WeakPtrFactory<DownloadPathReservationTrackerTest> weak_ptr_factory(
       this);
   DownloadPathReservationTracker::GetReservedPath(
-      download_item, target_path, default_download_path(), create_directory,
-      conflict_action,
+      download_item, target_path, default_download_path(), fallback_directory_,
+      create_directory, conflict_action,
       base::Bind(&DownloadPathReservationTrackerTest::TestReservedPathCallback,
                  weak_ptr_factory.GetWeakPtr(), return_path, return_result));
-  content::RunAllTasksUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
 }
 
 void DownloadPathReservationTrackerTest::TestReservedPathCallback(
@@ -163,16 +169,16 @@
 
 base::FilePath
 DownloadPathReservationTrackerTest::GetLongNamePathInDownloadsDirectory(
-    size_t repeat, const base::FilePath::CharType* suffix) {
+    size_t repeat,
+    const base::FilePath::CharType* suffix) {
   return GetPathInDownloadsDirectory(
-      (base::FilePath::StringType(repeat, FILE_PATH_LITERAL('a'))
-          + suffix).c_str());
+      (base::FilePath::StringType(repeat, FILE_PATH_LITERAL('a')) + suffix)
+          .c_str());
 }
 
-void SetDownloadItemState(download::MockDownloadItem* download_item,
-                          download::DownloadItem::DownloadState state) {
-  EXPECT_CALL(*download_item, GetState())
-      .WillRepeatedly(Return(state));
+void SetDownloadItemState(MockDownloadItem* download_item,
+                          DownloadItem::DownloadState state) {
+  EXPECT_CALL(*download_item, GetState()).WillRepeatedly(Return(state));
   download_item->NotifyObserversDownloadUpdated();
 }
 
@@ -199,7 +205,7 @@
   // Destroying the item should release the reservation.
   SetDownloadItemState(item.get(), DownloadItem::COMPLETE);
   item.reset();
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   EXPECT_FALSE(IsPathInUse(path));
 }
 
@@ -223,7 +229,7 @@
 
   // Once the download is interrupted, the path should become available again.
   SetDownloadItemState(item.get(), DownloadItem::INTERRUPTED);
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   EXPECT_FALSE(IsPathInUse(path));
 }
 
@@ -250,7 +256,7 @@
   // The path wouldn't be available since it is occupied on disk by the
   // completed download.
   SetDownloadItemState(item.get(), DownloadItem::COMPLETE);
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   EXPECT_FALSE(IsPathInUse(path));
 }
 
@@ -264,9 +270,9 @@
       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")));
   // Create a file at |path|, and a .crdownload file at |path1|.
   ASSERT_EQ(0, base::WriteFile(path, "", 0));
-  ASSERT_EQ(0,
-            base::WriteFile(
-                DownloadTargetDeterminer::GetCrDownloadPath(path1), "", 0));
+  ASSERT_EQ(0, base::WriteFile(base::FilePath(path1.value() +
+                                              FILE_PATH_LITERAL(".crdownload")),
+                               "", 0));
   ASSERT_TRUE(IsPathInUse(path));
 
   base::FilePath reserved_path;
@@ -287,7 +293,7 @@
 
   SetDownloadItemState(item.get(), DownloadItem::COMPLETE);
   item.reset();
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   EXPECT_TRUE(IsPathInUse(path));
   EXPECT_FALSE(IsPathInUse(reserved_path));
 }
@@ -316,7 +322,7 @@
 
   SetDownloadItemState(item.get(), DownloadItem::COMPLETE);
   item.reset();
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
 }
 
 // If the source is a file:// URL that is in the download directory, then Chrome
@@ -341,7 +347,7 @@
 
   SetDownloadItemState(item.get(), DownloadItem::COMPLETE);
   item.reset();
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
 }
 
 // Multiple reservations for the same path should uniquify around each other.
@@ -359,7 +365,7 @@
   bool create_directory = false;
 
   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
-    DownloadPathReservationTracker::UNIQUIFY;
+      DownloadPathReservationTracker::UNIQUIFY;
   CallGetReservedPath(item1.get(), path, create_directory, conflict_action,
                       &reserved_path1, &result);
   EXPECT_TRUE(IsPathInUse(path));
@@ -377,7 +383,7 @@
     EXPECT_EQ(uniquified_path.value(), reserved_path2.value());
     SetDownloadItemState(item2.get(), DownloadItem::COMPLETE);
   }
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   EXPECT_TRUE(IsPathInUse(path));
   EXPECT_FALSE(IsPathInUse(uniquified_path));
 
@@ -393,7 +399,7 @@
     EXPECT_EQ(uniquified_path.value(), reserved_path2.value());
     SetDownloadItemState(item2.get(), DownloadItem::COMPLETE);
   }
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
 
   // Now acquire an overwriting reservation. We should end up with the same
   // non-uniquified path for both reservations.
@@ -458,7 +464,7 @@
   std::unique_ptr<MockDownloadItem>
       items[DownloadPathReservationTracker::kMaxUniqueFiles + 2];
   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
-    DownloadPathReservationTracker::UNIQUIFY;
+      DownloadPathReservationTracker::UNIQUIFY;
   bool create_directory = false;
 
   // Create |kMaxUniqueFiles + 2| reservations for |path|. The first reservation
@@ -515,6 +521,8 @@
     // Scope for FilePermissionRestorer
     base::FilePermissionRestorer restorer(dir);
     EXPECT_TRUE(base::MakeFileUnwritable(dir));
+    base::FilePath fallback_dir(FILE_PATH_LITERAL("/tmp/download"));
+    set_fallback_directory(fallback_dir);
     base::FilePath reserved_path;
     PathValidationResult result = PathValidationResult::NAME_TOO_LONG;
     DownloadPathReservationTracker::FilenameConflictAction conflict_action =
@@ -525,6 +533,7 @@
     // Verification fails.
     EXPECT_EQ(PathValidationResult::PATH_NOT_WRITABLE, result);
     EXPECT_EQ(path.BaseName().value(), reserved_path.BaseName().value());
+    EXPECT_EQ(fallback_dir.value(), reserved_path.DirName().value());
   }
   SetDownloadItemState(item.get(), DownloadItem::COMPLETE);
 }
@@ -537,7 +546,7 @@
   base::FilePath dir(path.DirName());
   ASSERT_FALSE(base::DirectoryExists(dir));
   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
-    DownloadPathReservationTracker::OVERWRITE;
+      DownloadPathReservationTracker::OVERWRITE;
   bool create_directory = false;
 
   {
@@ -588,7 +597,7 @@
   // this state, we shouldn't lose the reservation.
   ASSERT_EQ(base::FilePath::StringType(), item->GetTargetFilePath().value());
   item->NotifyObserversDownloadUpdated();
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   EXPECT_TRUE(IsPathInUse(path));
 
   // If the target path changes, we should update the reservation to match.
@@ -598,14 +607,14 @@
   EXPECT_CALL(*item, GetTargetFilePath())
       .WillRepeatedly(ReturnRef(new_target_path));
   item->NotifyObserversDownloadUpdated();
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   EXPECT_FALSE(IsPathInUse(path));
   EXPECT_TRUE(IsPathInUse(new_target_path));
 
   // Destroying the item should release the reservation.
   SetDownloadItemState(item.get(), DownloadItem::COMPLETE);
   item.reset();
-  content::RunAllTasksUntilIdle();
+  RunUntilIdle();
   EXPECT_FALSE(IsPathInUse(new_target_path));
 }
 
@@ -676,7 +685,7 @@
   base::FilePath reserved_path;
   PathValidationResult result = PathValidationResult::NAME_TOO_LONG;
   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
-    DownloadPathReservationTracker::UNIQUIFY;
+      DownloadPathReservationTracker::UNIQUIFY;
   bool create_directory = false;
   CallGetReservedPath(item.get(), path, create_directory, conflict_action,
                       &reserved_path, &result);
@@ -698,8 +707,8 @@
 
   std::unique_ptr<MockDownloadItem> item = CreateDownloadItem(1);
   base::FilePath path(GetPathInDownloadsDirectory(
-      (FILE_PATH_LITERAL("a.") +
-          base::FilePath::StringType(max_length, 'b')).c_str()));
+      (FILE_PATH_LITERAL("a.") + base::FilePath::StringType(max_length, 'b'))
+          .c_str()));
   ASSERT_FALSE(IsPathInUse(path));
 
   base::FilePath reserved_path;
@@ -715,3 +724,5 @@
 }
 
 #endif  // Platforms that support filename truncation.
+
+}  // namespace download
diff --git a/components/download/public/common/BUILD.gn b/components/download/public/common/BUILD.gn
index a9437d4..a550efc 100644
--- a/components/download/public/common/BUILD.gn
+++ b/components/download/public/common/BUILD.gn
@@ -38,6 +38,7 @@
     "download_item_impl_delegate.h",
     "download_job.h",
     "download_job_factory.h",
+    "download_path_reservation_tracker.h",
     "download_request_handle_interface.h",
     "download_response_handler.h",
     "download_save_info.cc",
diff --git a/chrome/browser/download/download_path_reservation_tracker.h b/components/download/public/common/download_path_reservation_tracker.h
similarity index 88%
rename from chrome/browser/download/download_path_reservation_tracker.h
rename to components/download/public/common/download_path_reservation_tracker.h
index 3f83905..446a2de 100644
--- a/chrome/browser/download/download_path_reservation_tracker.h
+++ b/components/download/public/common/download_path_reservation_tracker.h
@@ -2,20 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
-#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
+#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
 
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
+#include "components/download/public/common/download_export.h"
 
 namespace base {
 class FilePath;
 class SequencedTaskRunner;
-}
+}  // namespace base
 
 namespace download {
 class DownloadItem;
-}
 
 // Used in UMA, do not remove, change or reuse existing entries.
 // Update histograms.xml and enums.xml when adding entries.
@@ -34,7 +34,7 @@
 // Therefore only considering files that exist on the filesystem is
 // insufficient. This class tracks files that are assigned to active downloads
 // so that uniquification can take those into account as well.
-class DownloadPathReservationTracker {
+class COMPONENTS_DOWNLOAD_EXPORT DownloadPathReservationTracker {
  public:
   // Callback used with |GetReservedPath|. |target_path| specifies the target
   // path for the download. If |result| is SUCCESS then:
@@ -71,8 +71,8 @@
   //   and either |create_directory| or |requested_target_path.DirName() ==
   //   default_download_path|.
   //
-  // - Verifying that |requested_target_path| is writeable. If not, the user's
-  //   documents folder is used instead.
+  // - Verifying that |requested_target_path| is writeable. If not,
+  //   |fallback_directory| is used instead.
   //
   // - Uniquifying |requested_target_path| by suffixing the filename with a
   //   uniquifier (e.g. "foo.txt" -> "foo (1).txt") in order to avoid conflicts
@@ -97,9 +97,10 @@
   // The current implementation doesn't look at symlinks/mount points. E.g.: It
   // considers 'foo/bar/x.pdf' and 'foo/baz/x.pdf' to be two different paths,
   // even though 'bar' might be a symlink to 'baz'.
-  static void GetReservedPath(download::DownloadItem* download_item,
+  static void GetReservedPath(DownloadItem* download_item,
                               const base::FilePath& requested_target_path,
                               const base::FilePath& default_download_path,
+                              const base::FilePath& fallback_directory,
                               bool create_directory,
                               FilenameConflictAction conflict_action,
                               const ReservedPathCallback& callback);
@@ -113,4 +114,6 @@
   static scoped_refptr<base::SequencedTaskRunner> GetTaskRunner();
 };
 
-#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
diff --git a/components/download/quarantine/BUILD.gn b/components/download/quarantine/BUILD.gn
index fafcb749..4ce7b5b 100644
--- a/components/download/quarantine/BUILD.gn
+++ b/components/download/quarantine/BUILD.gn
@@ -14,7 +14,6 @@
     "quarantine.h",
     "quarantine_features_win.cc",
     "quarantine_features_win.h",
-    "quarantine_linux.cc",
     "quarantine_mac.mm",
     "quarantine_win.cc",
   ]
@@ -36,8 +35,6 @@
 
 source_set("common") {
   sources = [
-    "common_linux.cc",
-    "common_linux.h",
     "common_mac.h",
     "common_mac.mm",
     "common_win.cc",
@@ -62,7 +59,6 @@
   sources = [
     "test_support.cc",
     "test_support.h",
-    "test_support_linux.cc",
     "test_support_mac.mm",
     "test_support_win.cc",
   ]
@@ -86,7 +82,6 @@
   testonly = true
 
   sources = [
-    "quarantine_linux_unittest.cc",
     "quarantine_mac_unittest.mm",
     "quarantine_win_unittest.cc",
   ]
diff --git a/components/download/quarantine/common_linux.cc b/components/download/quarantine/common_linux.cc
deleted file mode 100644
index 3674c8c..0000000
--- a/components/download/quarantine/common_linux.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/download/quarantine/common_linux.h"
-
-namespace download {
-
-const char kSourceURLExtendedAttrName[] = "user.xdg.origin.url";
-const char kReferrerURLExtendedAttrName[] = "user.xdg.referrer.url";
-
-}  // namespace download
diff --git a/components/download/quarantine/common_linux.h b/components/download/quarantine/common_linux.h
deleted file mode 100644
index 6b52b1b4..0000000
--- a/components/download/quarantine/common_linux.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DOWNLOAD_QUARANTINE_COMMON_LINUX_H_
-#define COMPONENTS_DOWNLOAD_QUARANTINE_COMMON_LINUX_H_
-
-namespace download {
-
-// Attribute names to be used with setxattr and friends.
-//
-// The source URL attribute is part of the XDG standard.
-// The referrer URL attribute is not part of the XDG standard,
-// but it is used to keep the naming consistent.
-// http://freedesktop.org/wiki/CommonExtendedAttributes
-extern const char kSourceURLExtendedAttrName[];
-extern const char kReferrerURLExtendedAttrName[];
-
-}  // namespace download
-
-#endif  // COMPONENTS_DOWNLOAD_QUARANTINE_COMMON_LINUX_H_
diff --git a/components/download/quarantine/quarantine.cc b/components/download/quarantine/quarantine.cc
index 48a2c59..ac5b109 100644
--- a/components/download/quarantine/quarantine.cc
+++ b/components/download/quarantine/quarantine.cc
@@ -6,7 +6,7 @@
 
 #include "build/build_config.h"
 
-#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_LINUX)
+#if !defined(OS_WIN) && !defined(OS_MACOSX)
 
 namespace download {
 
@@ -19,4 +19,4 @@
 
 }  // namespace download
 
-#endif  // !WIN && !MAC && !LINUX
+#endif  // !WIN && !MAC
diff --git a/components/download/quarantine/quarantine_linux.cc b/components/download/quarantine/quarantine_linux.cc
deleted file mode 100644
index 8683056..0000000
--- a/components/download/quarantine/quarantine_linux.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/download/quarantine/quarantine.h"
-
-#include <stddef.h>
-#include <sys/types.h>
-#include <sys/xattr.h>
-
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/threading/scoped_blocking_call.h"
-#include "components/download/quarantine/common_linux.h"
-#include "url/gurl.h"
-
-namespace download {
-
-namespace {
-
-bool SetExtendedFileAttribute(const char* path,
-                              const char* name,
-                              const char* value,
-                              size_t value_size,
-                              int flags) {
-// On Chrome OS, there is no component that can validate these extended
-// attributes so there is no need to set them.
-#if !defined(OS_CHROMEOS)
-  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
-  int result = setxattr(path, name, value, value_size, flags);
-  if (result) {
-    DPLOG(ERROR) << "Could not set extended attribute " << name << " on file "
-                 << path;
-    return false;
-  }
-#endif  // !defined(OS_CHROMEOS)
-  return true;
-}
-
-}  // namespace
-
-QuarantineFileResult QuarantineFile(const base::FilePath& file,
-                                    const GURL& source_url,
-                                    const GURL& referrer_url,
-                                    const std::string& client_guid) {
-  bool source_succeeded =
-      source_url.is_valid() &&
-      SetExtendedFileAttribute(file.value().c_str(), kSourceURLExtendedAttrName,
-                               source_url.spec().c_str(),
-                               source_url.spec().length(), 0);
-
-  // Referrer being empty is not considered an error. This could happen if the
-  // referrer policy resulted in an empty referrer for the download request.
-  bool referrer_succeeded =
-      !referrer_url.is_valid() ||
-      SetExtendedFileAttribute(
-          file.value().c_str(), kReferrerURLExtendedAttrName,
-          referrer_url.spec().c_str(), referrer_url.spec().length(), 0);
-  return source_succeeded && referrer_succeeded
-             ? QuarantineFileResult::OK
-             : QuarantineFileResult::ANNOTATION_FAILED;
-}
-
-}  // namespace download
diff --git a/components/download/quarantine/quarantine_linux_unittest.cc b/components/download/quarantine/quarantine_linux_unittest.cc
deleted file mode 100644
index 3216420..0000000
--- a/components/download/quarantine/quarantine_linux_unittest.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/download/quarantine/quarantine.h"
-
-#include <errno.h>
-#include <stddef.h>
-#include <sys/types.h>
-#include <sys/xattr.h>
-
-#include <algorithm>
-#include <sstream>
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/strings/string_split.h"
-#include "components/download/quarantine/common_linux.h"
-#include "components/download/quarantine/test_support.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace download {
-namespace {
-
-using std::istringstream;
-using std::string;
-using std::vector;
-
-class QuarantineLinuxTest : public testing::Test {
- public:
-  QuarantineLinuxTest()
-      : source_url_("http://www.source.com"),
-        referrer_url_("http://www.referrer.com"),
-        is_xattr_supported_(false) {}
-
-  const base::FilePath& test_file() const { return test_file_; }
-
-  const base::FilePath& test_dir() const { return temp_dir_.GetPath(); }
-
-  const GURL& source_url() const { return source_url_; }
-
-  const GURL& referrer_url() const { return referrer_url_; }
-
-  bool is_xattr_supported() const { return is_xattr_supported_; }
-
- protected:
-  void SetUp() override {
-#if !defined(OS_CHROMEOS)
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    ASSERT_TRUE(
-        base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &test_file_));
-    int result =
-        setxattr(test_file_.value().c_str(), "user.test", "test", 4, 0);
-    is_xattr_supported_ = (!result) || (errno != ENOTSUP);
-#endif  // !defined(OS_CHROMEOS)
-    if (!is_xattr_supported_) {
-      LOG(WARNING) << "Test will be skipped because extended attributes are "
-                      "not supported on this OS/file system.";
-    }
-  }
-
-  void GetExtendedAttributeNames(vector<string>* attr_names) const {
-    ssize_t len = listxattr(test_file().value().c_str(), nullptr, 0);
-    if (len <= static_cast<ssize_t>(0))
-      return;
-    char* buffer = new char[len];
-    len = listxattr(test_file().value().c_str(), buffer, len);
-    *attr_names =
-        base::SplitString(string(buffer, len), std::string(1, '\0'),
-                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-    delete[] buffer;
-  }
-
- private:
-  base::ScopedTempDir temp_dir_;
-  base::FilePath test_file_;
-  GURL source_url_;
-  GURL referrer_url_;
-  bool is_xattr_supported_;
-};
-
-}  // namespace
-
-TEST_F(QuarantineLinuxTest, CheckMetadataSetCorrectly) {
-  if (!is_xattr_supported())
-    return;
-  EXPECT_EQ(
-      QuarantineFileResult::OK,
-      QuarantineFile(test_file(), source_url(), referrer_url(), std::string()));
-  EXPECT_TRUE(IsFileQuarantined(test_file(), source_url(), referrer_url()));
-}
-
-TEST_F(QuarantineLinuxTest, SetMetadataMultipleTimes) {
-  if (!is_xattr_supported())
-    return;
-  GURL dummy_url("http://www.dummy.com");
-  EXPECT_EQ(QuarantineFileResult::OK,
-            QuarantineFile(test_file(), dummy_url, dummy_url, std::string()));
-  EXPECT_EQ(
-      QuarantineFileResult::OK,
-      QuarantineFile(test_file(), source_url(), referrer_url(), std::string()));
-  EXPECT_TRUE(IsFileQuarantined(test_file(), source_url(), referrer_url()));
-}
-
-TEST_F(QuarantineLinuxTest, InvalidSourceURLTest) {
-  if (!is_xattr_supported())
-    return;
-  GURL invalid_url;
-  vector<string> attr_names;
-  EXPECT_EQ(
-      QuarantineFileResult::ANNOTATION_FAILED,
-      QuarantineFile(test_file(), invalid_url, referrer_url(), std::string()));
-  GetExtendedAttributeNames(&attr_names);
-  EXPECT_FALSE(base::ContainsValue(attr_names, kSourceURLExtendedAttrName));
-  EXPECT_TRUE(base::ContainsValue(attr_names, kReferrerURLExtendedAttrName));
-}
-
-TEST_F(QuarantineLinuxTest, InvalidReferrerURLTest) {
-  if (!is_xattr_supported())
-    return;
-  GURL invalid_url;
-  vector<string> attr_names;
-  EXPECT_EQ(
-      QuarantineFileResult::OK,
-      QuarantineFile(test_file(), source_url(), invalid_url, std::string()));
-  GetExtendedAttributeNames(&attr_names);
-  EXPECT_FALSE(base::ContainsValue(attr_names, kReferrerURLExtendedAttrName));
-  EXPECT_TRUE(IsFileQuarantined(test_file(), source_url(), GURL()));
-}
-
-TEST_F(QuarantineLinuxTest, InvalidURLsTest) {
-  if (!is_xattr_supported())
-    return;
-  GURL invalid_url;
-  vector<string> attr_names;
-  EXPECT_EQ(
-      QuarantineFileResult::ANNOTATION_FAILED,
-      QuarantineFile(test_file(), invalid_url, invalid_url, std::string()));
-  GetExtendedAttributeNames(&attr_names);
-  EXPECT_FALSE(base::ContainsValue(attr_names, kSourceURLExtendedAttrName));
-  EXPECT_FALSE(base::ContainsValue(attr_names, kReferrerURLExtendedAttrName));
-  EXPECT_FALSE(IsFileQuarantined(test_file(), GURL(), GURL()));
-}
-
-TEST_F(QuarantineLinuxTest, IsFileQuarantined) {
-  if (!is_xattr_supported())
-    return;
-  base::FilePath does_not_exist = test_dir().AppendASCII("a.jar");
-  EXPECT_FALSE(IsFileQuarantined(does_not_exist, GURL(), GURL()));
-
-  base::FilePath no_annotations = test_dir().AppendASCII("b.jar");
-  ASSERT_EQ(5, base::WriteFile(no_annotations, "Hello", 5));
-  EXPECT_FALSE(IsFileQuarantined(no_annotations, GURL(), GURL()));
-
-  base::FilePath source_only = test_dir().AppendASCII("c.jar");
-  ASSERT_EQ(5, base::WriteFile(source_only, "Hello", 5));
-  ASSERT_EQ(QuarantineFileResult::OK,
-            QuarantineFile(source_only, source_url(), GURL(), std::string()));
-  EXPECT_TRUE(IsFileQuarantined(source_only, source_url(), GURL()));
-  EXPECT_TRUE(IsFileQuarantined(source_only, GURL(), GURL()));
-  EXPECT_TRUE(IsFileQuarantined(source_only, GURL(), referrer_url()));
-  EXPECT_FALSE(IsFileQuarantined(source_only, referrer_url(), GURL()));
-
-  base::FilePath fully_annotated = test_dir().AppendASCII("d.jar");
-  ASSERT_EQ(5, base::WriteFile(fully_annotated, "Hello", 5));
-  ASSERT_EQ(QuarantineFileResult::OK,
-            QuarantineFile(fully_annotated, source_url(), referrer_url(),
-                           std::string()));
-  EXPECT_TRUE(IsFileQuarantined(fully_annotated, GURL(), GURL()));
-  EXPECT_TRUE(IsFileQuarantined(fully_annotated, source_url(), GURL()));
-  EXPECT_TRUE(IsFileQuarantined(fully_annotated, source_url(), referrer_url()));
-  EXPECT_TRUE(IsFileQuarantined(fully_annotated, GURL(), referrer_url()));
-  EXPECT_FALSE(IsFileQuarantined(fully_annotated, source_url(), source_url()));
-  EXPECT_FALSE(
-      IsFileQuarantined(fully_annotated, referrer_url(), referrer_url()));
-}
-
-}  // namespace download
diff --git a/components/download/quarantine/quarantine_win.cc b/components/download/quarantine/quarantine_win.cc
index 763fb21..6ab164d 100644
--- a/components/download/quarantine/quarantine_win.cc
+++ b/components/download/quarantine/quarantine_win.cc
@@ -16,6 +16,7 @@
 
 #include <vector>
 
+#include "base/enterprise_util.h"
 #include "base/feature_list.h"
 #include "base/files/file_util.h"
 #include "base/guid.h"
@@ -247,7 +248,7 @@
   // TODO(pmonette): Move the InvokeAttachmentServices() call to a utility
   //                 process and remove the feature.
   bool should_invoke_attachment_services =
-      base::win::IsEnterpriseManaged() ||
+      base::IsMachineExternallyManaged() ||
       base::FeatureList::IsEnabled(kInvokeAttachmentServices);
 
   bool attachment_services_available =
diff --git a/components/download/quarantine/test_support.cc b/components/download/quarantine/test_support.cc
index e158051ae..55ef062 100644
--- a/components/download/quarantine/test_support.cc
+++ b/components/download/quarantine/test_support.cc
@@ -6,7 +6,7 @@
 
 #include "build/build_config.h"
 
-#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_LINUX)
+#if !defined(OS_WIN) && !defined(OS_MACOSX)
 
 namespace download {
 
@@ -18,4 +18,4 @@
 
 }  // namespace download
 
-#endif  // !WIN && !MAC && !LINUX
+#endif  // !WIN && !MAC
diff --git a/components/download/quarantine/test_support_linux.cc b/components/download/quarantine/test_support_linux.cc
deleted file mode 100644
index 63f8020..0000000
--- a/components/download/quarantine/test_support_linux.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/download/quarantine/test_support.h"
-
-#include <stddef.h>
-#include <sys/types.h>
-#include <sys/xattr.h>
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/threading/scoped_blocking_call.h"
-#include "components/download/quarantine/common_linux.h"
-#include "url/gurl.h"
-
-namespace download {
-
-namespace {
-
-std::string GetExtendedFileAttribute(const char* path, const char* name) {
-  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
-  ssize_t len = getxattr(path, name, nullptr, 0);
-  if (len <= 0)
-    return std::string();
-
-  std::vector<char> buffer(len);
-  len = getxattr(path, name, buffer.data(), buffer.size());
-  if (len < static_cast<ssize_t>(buffer.size()))
-    return std::string();
-  return std::string(buffer.begin(), buffer.end());
-}
-
-}  // namespace
-
-bool IsFileQuarantined(const base::FilePath& file,
-                       const GURL& source_url,
-                       const GURL& referrer_url) {
-  if (!base::PathExists(file))
-    return false;
-
-  std::string url_value = GetExtendedFileAttribute(file.value().c_str(),
-                                                   kSourceURLExtendedAttrName);
-  if (source_url.is_empty())
-    return !url_value.empty();
-
-  if (source_url != GURL(url_value))
-    return false;
-
-  return !referrer_url.is_valid() ||
-         GURL(GetExtendedFileAttribute(file.value().c_str(),
-                                       kReferrerURLExtendedAttrName)) ==
-             referrer_url;
-}
-
-}  // namespace download
diff --git a/components/feature_engagement/features.gni b/components/feature_engagement/features.gni
index bfda1bc6..72eaa1d7 100644
--- a/components/feature_engagement/features.gni
+++ b/components/feature_engagement/features.gni
@@ -4,7 +4,6 @@
 
 declare_args() {
   # In-Product Help is only available in Windows and Linux OS for
-  # desktop. Other platforms such as Mac OS currently does not support
-  # Views and there have been no strong feelings about CrOS.
+  # desktop.
   enable_desktop_in_product_help = is_win || (is_linux && !is_chromeos)
 }
diff --git a/components/history/core/browser/expire_history_backend_unittest.cc b/components/history/core/browser/expire_history_backend_unittest.cc
index d1e2a28c6..9fcb30f 100644
--- a/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/components/history/core/browser/expire_history_backend_unittest.cc
@@ -451,8 +451,9 @@
 
 // Deletes a URL with a favicon that it is the last referencer of, so that it
 // should also get deleted.
-// Fails near end of month. http://crbug.com/43586
-TEST_F(ExpireHistoryTest, DISABLED_DeleteURLAndFavicon) {
+// This test failed near end of month.
+// Please comment on http://crbug.com/15724 if it fails again.
+TEST_F(ExpireHistoryTest, DeleteURLAndFavicon) {
   URLID url_ids[3];
   base::Time visit_times[4];
   AddExampleData(url_ids, visit_times);
diff --git a/components/policy/core/browser/configuration_policy_handler.cc b/components/policy/core/browser/configuration_policy_handler.cc
index b51d221..1479a26 100644
--- a/components/policy/core/browser/configuration_policy_handler.cc
+++ b/components/policy/core/browser/configuration_policy_handler.cc
@@ -228,8 +228,8 @@
   if (!pref_path_)
     return;
   const base::Value* value = policies.GetValue(policy_name());
-  std::unique_ptr<base::ListValue> list(new base::ListValue());
-  if (value && Convert(value, list.get(), nullptr))
+  base::ListValue list;
+  if (value && Convert(value, &list, nullptr))
     prefs->SetValue(pref_path_, std::move(list));
 }
 
@@ -350,7 +350,7 @@
     return;
   const base::Value* value = policies.GetValue(policy_name());
   if (value)
-    prefs->SetValue(pref_path_, value->CreateDeepCopy());
+    prefs->SetValue(pref_path_, value->Clone());
 }
 
 
@@ -456,7 +456,7 @@
     return;
   const base::Value* value = policies.GetValue(policy_name());
   if (value)
-    prefs->SetValue(pref_path_, value->CreateDeepCopy());
+    prefs->SetValue(pref_path_, value->Clone());
 }
 
 // SimpleJsonStringSchemaValidatingPolicyHandler implementation ----------------
@@ -614,7 +614,7 @@
     return;
   const base::Value* value = policies.GetValue(policy_name_);
   if (value)
-    prefs->SetValue(pref_path_, value->CreateDeepCopy());
+    prefs->SetValue(pref_path_, value->Clone());
 }
 
 void SimpleJsonStringSchemaValidatingPolicyHandler::RecordJsonError() {
diff --git a/components/policy/core/browser/configuration_policy_handler_unittest.cc b/components/policy/core/browser/configuration_policy_handler_unittest.cc
index 02f93f0d..a8cac572 100644
--- a/components/policy/core/browser/configuration_policy_handler_unittest.cc
+++ b/components/policy/core/browser/configuration_policy_handler_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/json/json_reader.h"
+#include "base/logging.h"
 #include "base/values.h"
 #include "components/policy/core/browser/policy_error_map.h"
 #include "components/policy/core/common/policy_map.h"
@@ -116,7 +117,9 @@
  protected:
   void ApplyList(std::unique_ptr<base::ListValue> filtered_list,
                  PrefValueMap* prefs) override {
-    prefs->SetValue(kTestPref, std::move(filtered_list));
+    DCHECK(filtered_list);
+    prefs->SetValue(kTestPref,
+                    base::Value::FromUniquePtrValue(std::move(filtered_list)));
   }
 };
 
diff --git a/components/policy/core/browser/proxy_policy_handler.cc b/components/policy/core/browser/proxy_policy_handler.cc
index 686b27d..eab249ff 100644
--- a/components/policy/core/browser/proxy_policy_handler.cc
+++ b/components/policy/core/browser/proxy_policy_handler.cc
@@ -173,22 +173,19 @@
 
   switch (proxy_mode) {
     case ProxyPrefs::MODE_DIRECT:
-      prefs->SetValue(
-          proxy_config::prefs::kProxy,
-          std::make_unique<base::Value>(ProxyConfigDictionary::CreateDirect()));
+      prefs->SetValue(proxy_config::prefs::kProxy,
+                      ProxyConfigDictionary::CreateDirect());
       break;
     case ProxyPrefs::MODE_AUTO_DETECT:
       prefs->SetValue(proxy_config::prefs::kProxy,
-                      std::make_unique<base::Value>(
-                          ProxyConfigDictionary::CreateAutoDetect()));
+                      ProxyConfigDictionary::CreateAutoDetect());
       break;
     case ProxyPrefs::MODE_PAC_SCRIPT: {
       std::string pac_url_string;
       if (pac_url && pac_url->GetAsString(&pac_url_string)) {
         prefs->SetValue(
             proxy_config::prefs::kProxy,
-            std::make_unique<base::Value>(
-                ProxyConfigDictionary::CreatePacScript(pac_url_string, false)));
+            ProxyConfigDictionary::CreatePacScript(pac_url_string, false));
       } else {
         NOTREACHED();
       }
@@ -201,16 +198,14 @@
         if (bypass_list)
           bypass_list->GetAsString(&bypass_list_string);
         prefs->SetValue(proxy_config::prefs::kProxy,
-                        std::make_unique<base::Value>(
-                            ProxyConfigDictionary::CreateFixedServers(
-                                proxy_server, bypass_list_string)));
+                        ProxyConfigDictionary::CreateFixedServers(
+                            proxy_server, bypass_list_string));
       }
       break;
     }
     case ProxyPrefs::MODE_SYSTEM:
-      prefs->SetValue(
-          proxy_config::prefs::kProxy,
-          std::make_unique<base::Value>(ProxyConfigDictionary::CreateSystem()));
+      prefs->SetValue(proxy_config::prefs::kProxy,
+                      ProxyConfigDictionary::CreateSystem());
       break;
     case ProxyPrefs::kModeCount:
       NOTREACHED();
diff --git a/components/policy/core/browser/url_blacklist_policy_handler.cc b/components/policy/core/browser/url_blacklist_policy_handler.cc
index 62d615c..afe0799 100644
--- a/components/policy/core/browser/url_blacklist_policy_handler.cc
+++ b/components/policy/core/browser/url_blacklist_policy_handler.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/values.h"
 #include "components/policy/core/browser/policy_error_map.h"
@@ -53,7 +54,7 @@
   if (disabled_schemes_policy)
     disabled_schemes_policy->GetAsList(&disabled_schemes);
 
-  std::unique_ptr<base::ListValue> merged_url_blacklist(new base::ListValue());
+  std::vector<base::Value> merged_url_blacklist;
 
   // We start with the DisabledSchemes because we have size limit when
   // handling URLBlacklists.
@@ -62,7 +63,7 @@
       std::string entry_value;
       if (entry.GetAsString(&entry_value)) {
         entry_value.append("://*");
-        merged_url_blacklist->AppendString(entry_value);
+        merged_url_blacklist.emplace_back(std::move(entry_value));
       }
     }
   }
@@ -70,13 +71,13 @@
   if (url_blacklist) {
     for (const auto& entry : *url_blacklist) {
       if (entry.is_string())
-        merged_url_blacklist->Append(entry.CreateDeepCopy());
+        merged_url_blacklist.push_back(entry.Clone());
     }
   }
 
   if (disabled_schemes || url_blacklist) {
     prefs->SetValue(policy_prefs::kUrlBlacklist,
-                    std::move(merged_url_blacklist));
+                    base::Value(std::move(merged_url_blacklist)));
   }
 }
 
diff --git a/components/policy/core/common/policy_loader_win.cc b/components/policy/core/common/policy_loader_win.cc
index 7722ee1..af0b6d84 100644
--- a/components/policy/core/common/policy_loader_win.cc
+++ b/components/policy/core/common/policy_loader_win.cc
@@ -18,6 +18,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/enterprise_util.h"
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
@@ -265,7 +266,7 @@
   base::UmaHistogramBoolean("EnterpriseCheck.IsManaged",
                             base::win::IsDeviceRegisteredWithManagement());
   base::UmaHistogramBoolean("EnterpriseCheck.IsEnterpriseUser",
-                            base::win::IsEnterpriseManaged());
+                            base::IsMachineExternallyManaged());
 
   base::string16 machine_name;
   if (GetName(base::Bind(&::GetComputerNameEx, ::ComputerNameDnsHostname),
diff --git a/components/safe_browsing/common/utils.cc b/components/safe_browsing/common/utils.cc
index e1fbe2a..bc64200 100644
--- a/components/safe_browsing/common/utils.cc
+++ b/components/safe_browsing/common/utils.cc
@@ -13,7 +13,7 @@
 #include "crypto/sha2.h"
 
 #if defined(OS_WIN)
-#include "base/win/win_util.h"
+#include "base/enterprise_util.h"
 #endif
 
 namespace safe_browsing {
@@ -38,7 +38,7 @@
 ChromeUserPopulation::ProfileManagementStatus GetProfileManagementStatus(
     const policy::BrowserPolicyConnector* bpc) {
 #if defined(OS_WIN)
-  if (base::win::IsEnterpriseManaged())
+  if (base::IsMachineExternallyManaged())
     return ChromeUserPopulation::ENTERPRISE_MANAGED;
   else
     return ChromeUserPopulation::NOT_MANAGED;
diff --git a/components/safe_browsing/password_protection/password_protection_request.cc b/components/safe_browsing/password_protection/password_protection_request.cc
index b5688c4..1259f57 100644
--- a/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/components/safe_browsing/password_protection/password_protection_request.cc
@@ -13,8 +13,11 @@
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/safe_browsing/db/whitelist_checker_client.h"
 #include "components/safe_browsing/password_protection/password_protection_navigation_throttle.h"
+#include "components/safe_browsing/password_protection/visual_utils.h"
 #include "components/safe_browsing/web_ui/safe_browsing_ui.h"
+#include "components/zoom/zoom_controller.h"
 #include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
@@ -35,6 +38,20 @@
 // the size of the report. UMA suggests 99.9% will have < 200 domains.
 const int kMaxReusedDomains = 200;
 
+// Parameters chosen to ensure privacy is preserved by visual features.
+const int kMinWidthForVisualFeatures = 576;
+const int kMinHeightForVisualFeatures = 576;
+const float kMaxZoomForVisualFeatures = 2.0;
+
+std::unique_ptr<VisualFeatures> ExtractVisualFeatures(
+    const SkBitmap& screenshot) {
+  auto features = std::make_unique<VisualFeatures>();
+  visual_utils::GetHistogramForImage(screenshot,
+                                     features->mutable_color_histogram());
+  visual_utils::GetBlurredImage(screenshot, features->mutable_image());
+  return features;
+}
+
 }  // namespace
 
 PasswordProtectionRequest::PasswordProtectionRequest(
@@ -139,7 +156,7 @@
   if (verdict != LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED)
     Finish(RequestOutcome::RESPONSE_ALREADY_CACHED, std::move(cached_response));
   else
-    SendRequest();
+    FillRequestProto();
 }
 
 void PasswordProtectionRequest::FillRequestProto() {
@@ -212,11 +229,53 @@
     default:
       NOTREACHED();
   }
+
+  if (trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE &&
+      password_protection_service_->IsExtendedReporting() &&
+      zoom::ZoomController::GetZoomLevelForWebContents(web_contents_) <=
+          kMaxZoomForVisualFeatures &&
+      request_proto_->content_area_width() >= kMinWidthForVisualFeatures &&
+      request_proto_->content_area_height() >= kMinHeightForVisualFeatures) {
+    CollectVisualFeatures();
+  } else {
+    SendRequest();
+  }
+}
+
+void PasswordProtectionRequest::CollectVisualFeatures() {
+  content::RenderWidgetHostView* view =
+      web_contents_ ? web_contents_->GetRenderWidgetHostView() : nullptr;
+
+  if (!view)
+    SendRequest();
+
+  view->CopyFromSurface(
+      gfx::Rect(), gfx::Size(),
+      base::BindOnce(&PasswordProtectionRequest::OnScreenshotTaken,
+                     GetWeakPtr()));
+}
+
+void PasswordProtectionRequest::OnScreenshotTaken(const SkBitmap& screenshot) {
+  // Do the feature extraction on a worker thread, to avoid blocking the UI.
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&ExtractVisualFeatures, screenshot),
+      base::BindOnce(&PasswordProtectionRequest::OnVisualFeatureCollectionDone,
+                     GetWeakPtr()));
+}
+
+void PasswordProtectionRequest::OnVisualFeatureCollectionDone(
+    std::unique_ptr<VisualFeatures> visual_features) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  request_proto_->mutable_visual_features()->Swap(visual_features.get());
+  SendRequest();
 }
 
 void PasswordProtectionRequest::SendRequest() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  FillRequestProto();
 
   web_ui_token_ =
       WebUIInfoSingleton::GetInstance()->AddToPGPings(*request_proto_);
diff --git a/components/safe_browsing/password_protection/password_protection_request.h b/components/safe_browsing/password_protection/password_protection_request.h
index db3faa8..8c086f4 100644
--- a/components/safe_browsing/password_protection/password_protection_request.h
+++ b/components/safe_browsing/password_protection/password_protection_request.h
@@ -10,7 +10,9 @@
 #include "base/task/cancelable_task_tracker.h"
 #include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/safe_browsing/password_protection/password_protection_service.h"
+#include "components/safe_browsing/proto/csd.pb.h"
 #include "content/public/browser/browser_thread.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 
 #include <vector>
 
@@ -134,6 +136,16 @@
   // Fill |request_proto_| with appropriate values.
   void FillRequestProto();
 
+  // Collects visual features from the current login page.
+  void CollectVisualFeatures();
+
+  // Processes the screenshot of the login page into visual features.
+  void OnScreenshotTaken(const SkBitmap& bitmap);
+
+  // Called when the visual feature extraction is complete.
+  void OnVisualFeatureCollectionDone(
+      std::unique_ptr<VisualFeatures> visual_features);
+
   // Initiates network request to Safe Browsing backend.
   void SendRequest();
 
diff --git a/components/update_client/BUILD.gn b/components/update_client/BUILD.gn
index 20625d5..636f40a 100644
--- a/components/update_client/BUILD.gn
+++ b/components/update_client/BUILD.gn
@@ -92,10 +92,6 @@
     "//third_party/libxml",
     "//url",
   ]
-  libs = []
-  if (is_mac) {
-    libs += [ "OpenDirectory.framework" ]
-  }
 }
 
 static_library("test_support") {
diff --git a/components/update_client/updater_state.cc b/components/update_client/updater_state.cc
index c9bd83c..f8fd5fb 100644
--- a/components/update_client/updater_state.cc
+++ b/components/update_client/updater_state.cc
@@ -7,6 +7,7 @@
 
 #include <utility>
 
+#include "base/enterprise_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -37,7 +38,7 @@
 
 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
 void UpdaterState::ReadState() {
-  is_enterprise_managed_ = IsEnterpriseManaged();
+  is_enterprise_managed_ = base::IsMachineExternallyManaged();
 
 #if defined(GOOGLE_CHROME_BUILD)
   updater_name_ = GetUpdaterName();
diff --git a/components/update_client/updater_state.h b/components/update_client/updater_state.h
index 3bb6d38..ec11d4a 100644
--- a/components/update_client/updater_state.h
+++ b/components/update_client/updater_state.h
@@ -44,7 +44,6 @@
   static std::string GetUpdaterName();
   static base::Version GetUpdaterVersion(bool is_machine);
   static bool IsAutoupdateCheckEnabled();
-  static bool IsEnterpriseManaged();
   static base::Time GetUpdaterLastStartedAU(bool is_machine);
   static base::Time GetUpdaterLastChecked(bool is_machine);
 
diff --git a/components/update_client/updater_state_mac.mm b/components/update_client/updater_state_mac.mm
index dd9cca9..a7bceb6 100644
--- a/components/update_client/updater_state_mac.mm
+++ b/components/update_client/updater_state_mac.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #import <Foundation/Foundation.h>
-#import <OpenDirectory/OpenDirectory.h>
 
+#include "base/enterprise_util.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/mac/foundation_util.h"
@@ -116,106 +116,4 @@
   return -1;  // Keystone does not support update policies.
 }
 
-bool UpdaterState::IsEnterpriseManaged() {
-  base::mac::ScopedNSAutoreleasePool scoped_pool;
-
-  ODSession* session = [ODSession defaultSession];
-  if (session == nil) {
-    DLOG(WARNING) << "ODSession defult session is nil.";
-    return false;
-  }
-
-  NSError* error = nil;
-
-  NSArray<NSString*>* all_node_names = [session nodeNamesAndReturnError:&error];
-  if (!all_node_names) {
-    DLOG(WARNING) << "ODSession failed to give node names: "
-                  << error.localizedDescription.UTF8String;
-    return false;
-  }
-
-  NSUInteger num_nodes = all_node_names.count;
-  if (num_nodes < 3) {
-    DLOG(WARNING) << "ODSession returned too few node names: "
-                  << all_node_names.description.UTF8String;
-    return false;
-  }
-
-  if (num_nodes > 3) {
-    // Non-enterprise machines have:"/Search", "/Search/Contacts",
-    // "/Local/Default". Everything else would be enterprise management.
-    return true;
-  }
-
-  ODNode* node = [ODNode nodeWithSession:session
-                                    type:kODNodeTypeAuthentication
-                                   error:&error];
-  if (node == nil) {
-    DLOG(WARNING) << "ODSession cannot obtain the authentication node: "
-                  << error.localizedDescription.UTF8String;
-    return false;
-  }
-
-  // Now check the currently logged on user.
-  ODQuery* query = [ODQuery queryWithNode:node
-                           forRecordTypes:kODRecordTypeUsers
-                                attribute:kODAttributeTypeRecordName
-                                matchType:kODMatchEqualTo
-                              queryValues:NSUserName()
-                         returnAttributes:kODAttributeTypeAllAttributes
-                           maximumResults:0
-                                    error:&error];
-  if (query == nil) {
-    DLOG(WARNING) << "ODSession cannot create user query: "
-        << base::mac::NSToCFCast(error);
-    return false;
-  }
-
-  NSArray* results = [query resultsAllowingPartial:NO error:&error];
-  if (!results) {
-    DLOG(WARNING) << "ODSession cannot obtain current user node: "
-                  << error.localizedDescription.UTF8String;
-    return false;
-  }
-  if (results.count != 1) {
-    DLOG(WARNING) << @"ODSession unexpected number of user nodes: "
-                  << results.count;
-  }
-  for (id element in results) {
-    ODRecord* record = base::mac::ObjCCastStrict<ODRecord>(element);
-    NSArray* attributes =
-        [record valuesForAttribute:kODAttributeTypeMetaRecordName
-                             error:NULL];
-    for (id attribute in attributes) {
-      NSString* attribute_value =
-          base::mac::ObjCCastStrict<NSString>(attribute);
-      // Example: "uid=johnsmith,ou=People,dc=chromium,dc=org
-      NSRange domain_controller =
-          [attribute_value rangeOfString:@"(^|,)\\s*dc="
-                                 options:NSRegularExpressionSearch];
-      if (domain_controller.length > 0) {
-        return true;
-      }
-    }
-
-    // Scan alternative identities.
-    attributes =
-        [record valuesForAttribute:kODAttributeTypeAltSecurityIdentities
-                             error:NULL];
-    for (id attribute in attributes) {
-      NSString* attribute_value =
-          base::mac::ObjCCastStrict<NSString>(attribute);
-      NSRange iCloud =
-          [attribute_value rangeOfString:@"CN=com.apple.idms.appleid.prd"
-                                 options:NSCaseInsensitiveSearch];
-      if (!iCloud.length) {
-        // Any alternative identity that is not iCloud is likely enterprise
-        // management.
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
 }  // namespace update_client
diff --git a/components/update_client/updater_state_win.cc b/components/update_client/updater_state_win.cc
index 66a0490..89c2c18 100644
--- a/components/update_client/updater_state_win.cc
+++ b/components/update_client/updater_state_win.cc
@@ -9,10 +9,10 @@
 #include <string>
 #include <utility>
 
+#include "base/enterprise_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
 
@@ -133,8 +133,4 @@
   return -1;
 }
 
-bool UpdaterState::IsEnterpriseManaged() {
-  return base::win::IsEnterpriseManaged();
-}
-
 }  // namespace update_client
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc
index 28bc28a..32f5330 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.cc
+++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -143,6 +143,15 @@
     // Retry creating and binding |context_provider| on transient failures.
     gpu::ContextResult context_result = gpu::ContextResult::kTransientFailure;
     while (context_result != gpu::ContextResult::kSuccess) {
+      // We are about to exit the GPU process so don't try to create a context.
+      // It will be recreated after the GPU process restarts. The same check
+      // also happens on the GPU thread before the context gets initialized
+      // there. If GPU process starts to exit after this check but before
+      // context initialization we'll encounter a transient error, loop and hit
+      // this check again.
+      if (gpu_channel_manager_delegate_->IsExiting())
+        return nullptr;
+
       context_provider = base::MakeRefCounted<VizProcessContextProvider>(
           task_executor_, surface_handle, gpu_memory_buffer_manager_.get(),
           image_factory_, gpu_channel_manager_delegate_, renderer_settings);
@@ -150,16 +159,15 @@
 
       if (IsFatalOrSurfaceFailure(context_result)) {
 #if defined(OS_ANDROID)
-        // Ignore context creation failures if exiting for lost context. We are
-        // about to lose the GPU process and Viz will re-create the context at
-        // that point.
-        if (!gpu_service_impl_->gpu_channel_manager()
-                 ->is_exiting_for_lost_context()) {
-          display_client->OnFatalOrSurfaceContextCreationFailure(
-              context_result);
-        }
-#endif
+        display_client->OnFatalOrSurfaceContextCreationFailure(context_result);
+#elif defined(OS_CHROMEOS) || defined(IS_CHROMECAST)
+        // TODO(kylechar): Chrome OS can't disable GPU compositing. This needs
+        // to be handled similar to Android.
+        CHECK(false);
+#else
         gpu_service_impl_->DisableGpuCompositing();
+#endif
+
         return nullptr;
       }
     }
diff --git a/components/viz/service/display_embedder/software_output_device_win.cc b/components/viz/service/display_embedder/software_output_device_win.cc
index 963f20c..86797838 100644
--- a/components/viz/service/display_embedder/software_output_device_win.cc
+++ b/components/viz/service/display_embedder/software_output_device_win.cc
@@ -8,7 +8,6 @@
 #include "base/memory/shared_memory.h"
 #include "base/threading/thread_checker.h"
 #include "base/win/windows_version.h"
-#include "base/win/wrapped_window_proc.h"
 #include "components/viz/common/display/use_layered_window.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/service/display_embedder/output_device_backing.h"
@@ -17,7 +16,6 @@
 #include "skia/ext/platform_canvas.h"
 #include "skia/ext/skia_utils_win.h"
 #include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/base/win/hidden_window.h"
 #include "ui/gfx/gdi_util.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/win/hwnd_util.h"
@@ -336,96 +334,6 @@
   std::move(swap_ack_callback_).Run();
 }
 
-// WindowProc callback function for SoftwareOutputDeviceWinDirectChild.
-LRESULT CALLBACK IntermediateWindowProc(HWND window,
-                                        UINT message,
-                                        WPARAM w_param,
-                                        LPARAM l_param) {
-  switch (message) {
-    case WM_ERASEBKGND:
-      // Prevent Windows from erasing all window content on resize.
-      return 1;
-    default:
-      return DefWindowProc(window, message, w_param, l_param);
-  }
-}
-
-// SoftwareOutputDevice implementation that creates a child HWND and draws
-// directly to it. This is intended to be used in the GPU process. The child
-// HWND is initially parented to a hidden window and needs be reparented to the
-// appropriate browser HWND. The backing buffer for paint is shared for all
-// instances of this class.
-class SoftwareOutputDeviceWinDirectChild
-    : public SoftwareOutputDeviceWinDirect {
- public:
-  static std::unique_ptr<SoftwareOutputDeviceWinDirectChild> Create(
-      OutputDeviceBacking* backing);
-  ~SoftwareOutputDeviceWinDirectChild() override;
-
-  // SoftwareOutputDeviceWinBase implementation.
-  void ResizeDelegated() override;
-
- private:
-  static wchar_t* GetWindowClass();
-
-  SoftwareOutputDeviceWinDirectChild(HWND child_hwnd,
-                                     OutputDeviceBacking* backing);
-
-  DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinDirectChild);
-};
-
-// static
-std::unique_ptr<SoftwareOutputDeviceWinDirectChild>
-SoftwareOutputDeviceWinDirectChild::Create(OutputDeviceBacking* backing) {
-  // Create a child window that is initially parented to a hidden window.
-  // |child_hwnd| needs to be reparented to a browser created HWND to be
-  // visible.
-  HWND child_hwnd =
-      CreateWindowEx(WS_EX_NOPARENTNOTIFY, GetWindowClass(), L"",
-                     WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, 0, 0,
-                     ui::GetHiddenWindow(), nullptr, nullptr, nullptr);
-  DCHECK(child_hwnd);
-  return base::WrapUnique(
-      new SoftwareOutputDeviceWinDirectChild(child_hwnd, backing));
-}
-
-SoftwareOutputDeviceWinDirectChild::~SoftwareOutputDeviceWinDirectChild() {
-  DestroyWindow(hwnd());
-}
-
-void SoftwareOutputDeviceWinDirectChild::ResizeDelegated() {
-  SoftwareOutputDeviceWinDirect::ResizeDelegated();
-  // Resize the child HWND to match the content size.
-  SetWindowPos(hwnd(), nullptr, 0, 0, viewport_pixel_size_.width(),
-               viewport_pixel_size_.height(),
-               SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS |
-                   SWP_NOOWNERZORDER | SWP_NOZORDER);
-}
-
-// static
-wchar_t* SoftwareOutputDeviceWinDirectChild::GetWindowClass() {
-  static ATOM window_class = 0;
-
-  // Register window class on first call.
-  if (!window_class) {
-    WNDCLASSEX intermediate_class;
-    base::win::InitializeWindowClass(
-        L"Intermediate Software Window",
-        &base::win::WrappedWindowProc<IntermediateWindowProc>, CS_OWNDC, 0, 0,
-        nullptr, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr,
-        nullptr, nullptr, &intermediate_class);
-    window_class = RegisterClassEx(&intermediate_class);
-    DCHECK(window_class);
-  }
-
-  return reinterpret_cast<wchar_t*>(window_class);
-}
-
-SoftwareOutputDeviceWinDirectChild::SoftwareOutputDeviceWinDirectChild(
-    HWND child_hwnd,
-    OutputDeviceBacking* backing)
-    : SoftwareOutputDeviceWinDirect(child_hwnd, backing) {}
-
 }  // namespace
 
 std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWinBrowser(
@@ -442,6 +350,8 @@
     OutputDeviceBacking* backing,
     mojom::DisplayClient* display_client,
     HWND* out_child_hwnd) {
+  // TODO(kylechar): Remove |out_child_hwnd| parameter it's no longer used.
+
   if (NeedsToUseLayerWindow(hwnd)) {
     DCHECK(display_client);
 
@@ -456,13 +366,7 @@
     return std::make_unique<SoftwareOutputDeviceWinProxy>(
         hwnd, std::move(layered_window_updater));
   } else {
-    auto software_output_device =
-        SoftwareOutputDeviceWinDirectChild::Create(backing);
-
-    // The child HWND needs to be parented to the browser HWND to be visible.
-    *out_child_hwnd = software_output_device->hwnd();
-
-    return software_output_device;
+    return std::make_unique<SoftwareOutputDeviceWinDirect>(hwnd, backing);
   }
 }
 
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index 0f835e1..645131b 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -488,10 +488,9 @@
   gpu::RecordGpuSupportedRuntimeVersionHistograms(
       &gpu_info_.dx12_vulkan_version_info);
   std::move(callback).Run(gpu_info_.dx12_vulkan_version_info);
-  if (!in_host_process()) {
-    // The unsandboxed GPU process fulfilled its duty. Bye bye.
-    ExitProcess();
-  }
+
+  // The unsandboxed GPU process fulfilled its duty. Bye bye.
+  MaybeExit(false);
 }
 
 void GpuServiceImpl::RequestCompleteGpuInfo(
@@ -511,10 +510,8 @@
           [](GpuServiceImpl* gpu_service,
              RequestCompleteGpuInfoCallback callback) {
             std::move(callback).Run(gpu_service->gpu_info_.dx_diagnostics);
-            if (!gpu_service->in_host_process()) {
-              // The unsandboxed GPU process fulfilled its duty. Bye bye.
-              gpu_service->ExitProcess();
-            }
+            // The unsandboxed GPU process fulfilled its duty. Bye bye.
+            gpu_service->MaybeExit(false);
           },
           this, std::move(callback))));
 }
@@ -609,9 +606,12 @@
   (*gpu_host_)->StoreShaderToDisk(client_id, key, shader);
 }
 
-void GpuServiceImpl::ExitProcess() {
-  if (exit_callback_)
-    std::move(exit_callback_).Run();
+void GpuServiceImpl::MaybeExitOnContextLost() {
+  MaybeExit(true);
+}
+
+bool GpuServiceImpl::IsExiting() const {
+  return is_exiting_.IsSet();
 }
 
 #if defined(OS_WIN)
@@ -796,8 +796,25 @@
 void GpuServiceImpl::Stop(StopCallback callback) {
   DCHECK(io_runner_->BelongsToCurrentThread());
   main_runner_->PostTaskAndReply(
-      FROM_HERE, base::BindOnce(&GpuServiceImpl::ExitProcess, weak_ptr_),
+      FROM_HERE, base::BindOnce(&GpuServiceImpl::MaybeExit, weak_ptr_, false),
       std::move(callback));
 }
 
+void GpuServiceImpl::MaybeExit(bool for_context_loss) {
+  DCHECK(main_runner_->BelongsToCurrentThread());
+
+  // We can't restart the GPU process when running in the host process.
+  if (in_host_process())
+    return;
+
+  if (exit_callback_) {
+    if (for_context_loss) {
+      LOG(ERROR) << "Exiting GPU process because some drivers can't recover "
+                    "from errors. GPU process will restart shortly.";
+    }
+    is_exiting_.Set();
+    std::move(exit_callback_).Run();
+  }
+}
+
 }  // namespace viz
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h
index 08fd68d..691f2e2 100644
--- a/components/viz/service/gl/gpu_service_impl.h
+++ b/components/viz/service/gl/gpu_service_impl.h
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/single_thread_task_runner.h"
+#include "base/synchronization/atomic_flag.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/threading/thread.h"
@@ -180,7 +181,8 @@
   void StoreShaderToDisk(int client_id,
                          const std::string& key,
                          const std::string& shader) override;
-  void ExitProcess() override;
+  void MaybeExitOnContextLost() override;
+  bool IsExiting() const override;
 #if defined(OS_WIN)
   void SendCreatedChildWindow(gpu::SurfaceHandle parent_window,
                               gpu::SurfaceHandle child_window) override;
@@ -262,6 +264,10 @@
 
   void OnBackgroundedOnMainThread();
 
+  // Attempts to cleanly exit the process but only if not running in host
+  // process. If |for_context_loss| is true an error message will be logged.
+  void MaybeExit(bool for_context_loss);
+
   scoped_refptr<base::SingleThreadTaskRunner> main_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
 
@@ -308,6 +314,7 @@
 
   // Callback that safely exits GPU process.
   base::OnceClosure exit_callback_;
+  base::AtomicFlag is_exiting_;
 
   base::Time start_time_;
 
diff --git a/content/browser/appcache/appcache_dispatcher_host.cc b/content/browser/appcache/appcache_dispatcher_host.cc
index 07792ff0..2cc32a04 100644
--- a/content/browser/appcache/appcache_dispatcher_host.cc
+++ b/content/browser/appcache/appcache_dispatcher_host.cc
@@ -19,12 +19,9 @@
 AppCacheDispatcherHost::AppCacheDispatcherHost(
     ChromeAppCacheService* appcache_service,
     int process_id)
-    : appcache_service_(appcache_service),
-      frontend_proxy_(process_id),
-      weak_factory_(this) {
-  if (appcache_service) {
-    backend_impl_.Initialize(appcache_service, &frontend_proxy_, process_id);
-  }
+    : frontend_proxy_(process_id) {
+  DCHECK(appcache_service);
+  backend_impl_.Initialize(appcache_service, &frontend_proxy_, process_id);
 }
 
 AppCacheDispatcherHost::~AppCacheDispatcherHost() = default;
@@ -48,72 +45,56 @@
 }
 
 void AppCacheDispatcherHost::RegisterHost(int32_t host_id) {
-  if (appcache_service_) {
-    // The AppCacheHost could have been precreated in which case we want to
-    // register it with the backend here.
-    std::unique_ptr<content::AppCacheHost> host =
-        AppCacheNavigationHandleCore::GetPrecreatedHost(host_id);
-    if (host.get()) {
-      backend_impl_.RegisterPrecreatedHost(std::move(host));
-      return;
-    }
+  // The AppCacheHost could have been precreated in which case we want to
+  // register it with the backend here.
+  std::unique_ptr<content::AppCacheHost> host =
+      AppCacheNavigationHandleCore::GetPrecreatedHost(host_id);
+  if (host.get()) {
+    backend_impl_.RegisterPrecreatedHost(std::move(host));
+    return;
+  }
 
-    if (!backend_impl_.RegisterHost(host_id)) {
-      mojo::ReportBadMessage("ACDH_REGISTER");
-    }
+  if (!backend_impl_.RegisterHost(host_id)) {
+    mojo::ReportBadMessage("ACDH_REGISTER");
   }
 }
 
 void AppCacheDispatcherHost::UnregisterHost(int32_t host_id) {
-  if (appcache_service_) {
-    if (!backend_impl_.UnregisterHost(host_id)) {
-      mojo::ReportBadMessage("ACDH_UNREGISTER");
-    }
+  if (!backend_impl_.UnregisterHost(host_id)) {
+    mojo::ReportBadMessage("ACDH_UNREGISTER");
   }
 }
 
 void AppCacheDispatcherHost::SetSpawningHostId(int32_t host_id,
                                                int spawning_host_id) {
-  if (appcache_service_) {
-    if (!backend_impl_.SetSpawningHostId(host_id, spawning_host_id))
-      mojo::ReportBadMessage("ACDH_SET_SPAWNING");
-  }
+  if (!backend_impl_.SetSpawningHostId(host_id, spawning_host_id))
+    mojo::ReportBadMessage("ACDH_SET_SPAWNING");
 }
 
 void AppCacheDispatcherHost::SelectCache(int32_t host_id,
                                          const GURL& document_url,
                                          int64_t cache_document_was_loaded_from,
                                          const GURL& opt_manifest_url) {
-  if (appcache_service_) {
-    if (!backend_impl_.SelectCache(host_id, document_url,
-                                   cache_document_was_loaded_from,
-                                   opt_manifest_url)) {
-      mojo::ReportBadMessage("ACDH_SELECT_CACHE");
-    }
-  } else {
-    frontend_proxy_.OnCacheSelected(host_id, blink::mojom::AppCacheInfo());
+  if (!backend_impl_.SelectCache(host_id, document_url,
+                                 cache_document_was_loaded_from,
+                                 opt_manifest_url)) {
+    mojo::ReportBadMessage("ACDH_SELECT_CACHE");
   }
 }
 
 void AppCacheDispatcherHost::SelectCacheForSharedWorker(int32_t host_id,
                                                         int64_t appcache_id) {
-  if (appcache_service_) {
-    if (!backend_impl_.SelectCacheForSharedWorker(host_id, appcache_id))
-      mojo::ReportBadMessage("ACDH_SELECT_CACHE_FOR_SHARED_WORKER");
-  } else {
-    frontend_proxy_.OnCacheSelected(host_id, blink::mojom::AppCacheInfo());
-  }
+  if (!backend_impl_.SelectCacheForSharedWorker(host_id, appcache_id))
+    mojo::ReportBadMessage("ACDH_SELECT_CACHE_FOR_SHARED_WORKER");
 }
 
 void AppCacheDispatcherHost::MarkAsForeignEntry(
     int32_t host_id,
     const GURL& document_url,
     int64_t cache_document_was_loaded_from) {
-  if (appcache_service_) {
-    if (!backend_impl_.MarkAsForeignEntry(host_id, document_url,
-                                          cache_document_was_loaded_from)) {
-      mojo::ReportBadMessage("ACDH_MARK_AS_FOREIGN_ENTRY");
-    }
+  if (!backend_impl_.MarkAsForeignEntry(host_id, document_url,
+                                        cache_document_was_loaded_from)) {
+    mojo::ReportBadMessage("ACDH_MARK_AS_FOREIGN_ENTRY");
   }
 }
 
@@ -121,26 +102,22 @@
                                              GetResourceListCallback callback) {
   std::vector<blink::mojom::AppCacheResourceInfo> params;
   std::vector<blink::mojom::AppCacheResourceInfoPtr> out;
-  if (appcache_service_) {
-    backend_impl_.GetResourceList(host_id, &params);
+  backend_impl_.GetResourceList(host_id, &params);
 
-    // Box up params for output.
-    out.reserve(params.size());
-    for (auto& p : params) {
-      out.emplace_back(base::in_place, std::move(p));
-    }
+  // Box up params for output.
+  out.reserve(params.size());
+  for (auto& p : params) {
+    out.emplace_back(base::in_place, std::move(p));
   }
   std::move(callback).Run(std::move(out));
 }
 
 void AppCacheDispatcherHost::GetStatus(int32_t host_id,
                                        GetStatusCallback callback) {
-  if (appcache_service_) {
-    if (backend_impl_.GetStatusWithCallback(host_id, &callback)) {
-      return;
-    } else {
-      mojo::ReportBadMessage("ACDH_GET_STATUS");
-    }
+  if (backend_impl_.GetStatusWithCallback(host_id, &callback)) {
+    return;
+  } else {
+    mojo::ReportBadMessage("ACDH_GET_STATUS");
   }
   if (callback) {
     std::move(callback).Run(
@@ -150,12 +127,10 @@
 
 void AppCacheDispatcherHost::StartUpdate(int32_t host_id,
                                          StartUpdateCallback callback) {
-  if (appcache_service_) {
-    if (backend_impl_.StartUpdateWithCallback(host_id, &callback)) {
-      return;
-    } else {
-      mojo::ReportBadMessage("ACDH_START_UPDATE");
-    }
+  if (backend_impl_.StartUpdateWithCallback(host_id, &callback)) {
+    return;
+  } else {
+    mojo::ReportBadMessage("ACDH_START_UPDATE");
   }
   if (callback)
     std::move(callback).Run(false);
@@ -163,12 +138,10 @@
 
 void AppCacheDispatcherHost::SwapCache(int32_t host_id,
                                        SwapCacheCallback callback) {
-  if (appcache_service_) {
-    if (backend_impl_.SwapCacheWithCallback(host_id, &callback)) {
-      return;
-    } else {
-      mojo::ReportBadMessage("ACDH_SWAP_CACHE");
-    }
+  if (backend_impl_.SwapCacheWithCallback(host_id, &callback)) {
+    return;
+  } else {
+    mojo::ReportBadMessage("ACDH_SWAP_CACHE");
   }
   if (callback)
     std::move(callback).Run(false);
diff --git a/content/browser/appcache/appcache_dispatcher_host.h b/content/browser/appcache/appcache_dispatcher_host.h
index 43570b2..d292814 100644
--- a/content/browser/appcache/appcache_dispatcher_host.h
+++ b/content/browser/appcache/appcache_dispatcher_host.h
@@ -12,7 +12,6 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
 #include "base/process/process.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
 #include "content/browser/appcache/appcache_frontend_proxy.h"
@@ -56,13 +55,9 @@
   void GetResourceList(int32_t host_id,
                        GetResourceListCallback callback) override;
 
-  // This object is owned by the |ChromeAppCacheService|, so this is safe.
-  ChromeAppCacheService* appcache_service_;
   AppCacheFrontendProxy frontend_proxy_;
   AppCacheBackendImpl backend_impl_;
 
-  base::WeakPtrFactory<AppCacheDispatcherHost> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(AppCacheDispatcherHost);
 };
 
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index 8e85a80e..a5a60cf 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -133,6 +133,8 @@
     return false;
   renderer_channel_.AttachSession(session);
   sessions_.push_back(session);
+  DCHECK(session_by_client_.find(session->client()) ==
+         session_by_client_.end());
   session_by_client_[session->client()] = std::move(session_owned);
   if (sessions_.size() == 1)
     NotifyAttached();
@@ -169,6 +171,7 @@
 void DevToolsAgentHostImpl::DetachInternal(DevToolsSession* session) {
   std::unique_ptr<DevToolsSession> session_owned =
       std::move(session_by_client_[session->client()]);
+  DCHECK_EQ(session, session_owned.get());
   // Make sure we dispose session prior to reporting it to the host.
   session->Dispose();
   sessions_.erase(std::remove(sessions_.begin(), sessions_.end(), session));
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 4aa391a6b..12e38b8b 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -1006,7 +1006,9 @@
 }
 
 void GpuProcessHost::DisableGpuCompositing() {
-#if !defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+  DLOG(ERROR) << "Can't disable GPU compositing";
+#else
   // TODO(crbug.com/819474): The switch from GPU to software compositing should
   // be handled here instead of by ImageTransportFactory.
   base::PostTaskWithTraits(
diff --git a/content/browser/oop_browsertest.cc b/content/browser/oop_browsertest.cc
index 3fcfe55..afd053f 100644
--- a/content/browser/oop_browsertest.cc
+++ b/content/browser/oop_browsertest.cc
@@ -54,13 +54,7 @@
 
 // This test calls into system GL which is not instrumented with MSAN.
 #if !defined(MEMORY_SANITIZER)
-// TODO(crbug.com/880948) Disabled for crashes on Linux CFI, see bug.
-#if defined(OS_LINUX)
-#define MAYBE_Basic DISABLED_Basic
-#else
-#define MAYBE_Basic Basic
-#endif
-IN_PROC_BROWSER_TEST_F(OOPBrowserTest, MAYBE_Basic) {
+IN_PROC_BROWSER_TEST_F(OOPBrowserTest, Basic) {
   // Create a div to ensure we don't use solid color quads.
   GURL url = GURL(
       "data:text/html,"
diff --git a/content/browser/resources/service_worker/serviceworker_internals.html b/content/browser/resources/service_worker/serviceworker_internals.html
index b236a6b..fc3f6e5 100644
--- a/content/browser/resources/service_worker/serviceworker_internals.html
+++ b/content/browser/resources/service_worker/serviceworker_internals.html
@@ -1,13 +1,13 @@
 <!doctype html>
-<html i18n-values="dir:textdirection;lang:language">
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
 <head>
   <meta charset="utf-8">
   <title>chrome://serviceworker-internals</title>
-  <link rel="stylesheet" href="chrome://resources/css/tabs.css">
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="chrome://resources/css/widgets.css">
   <link rel="stylesheet" href="serviceworker_internals.css">
 </head>
-<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+<body>
   <!-- templates -->
   <div style="display:none">
     <div id="serviceworker-version-template" class="serviceworker-version">
@@ -144,9 +144,6 @@
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://resources/js/cr.js"></script>
   <script src="serviceworker_internals.js"></script>
-  <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="chrome://resources/js/jstemplate_compiled.js"></script>
-  <script src="strings.js"></script>
-  <script src="chrome://resources/js/i18n_template.js"></script>
 </body>
 </html>
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index 9462ede7..580ac8f 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -123,8 +123,17 @@
 
 // If enabled, network service will run in it's own thread when running
 // in-process, otherwise it is run on the IO thread.
+// On ChromeOS the network service has to run on the IO thread because
+// ProfileIOData and NetworkContext both try to set up NSS, which has has to be
+// called from the IO thread.
 const base::Feature kNetworkServiceDedicatedThread{
-    "NetworkServiceDedicatedThread", base::FEATURE_ENABLED_BY_DEFAULT};
+  "NetworkServiceDedicatedThread",
+#if defined(OS_CHROMEOS)
+      base::FEATURE_DISABLED_BY_DEFAULT
+#else
+      base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
 
 void DestroyConnectorOnIOThread() { g_io_thread_connector.Get().reset(); }
 
diff --git a/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc b/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
index 1e6366e..20cd7e8 100644
--- a/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
+++ b/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
@@ -14,6 +14,7 @@
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "media/base/media_switches.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/video_capture/public/mojom/constants.mojom.h"
@@ -50,9 +51,11 @@
 // virtual devices at the service and checks in JavaScript that the list of
 // enumerated devices changes correspondingly.
 class WebRtcVideoCaptureServiceEnumerationBrowserTest
-    : public ContentBrowserTest {
+    : public ContentBrowserTest,
+      public video_capture::mojom::DevicesChangedObserver {
  public:
-  WebRtcVideoCaptureServiceEnumerationBrowserTest() {
+  WebRtcVideoCaptureServiceEnumerationBrowserTest()
+      : devices_changed_observer_binding_(this) {
     scoped_feature_list_.InitAndEnableFeature(features::kMojoVideoCapture);
   }
 
@@ -61,6 +64,11 @@
   void ConnectToService() {
     connector_->BindInterface(video_capture::mojom::kServiceName, &provider_);
     provider_->ConnectToDeviceFactory(mojo::MakeRequest(&factory_));
+    video_capture::mojom::DevicesChangedObserverPtr observer;
+    devices_changed_observer_binding_.Bind(mojo::MakeRequest(&observer));
+    factory_->RegisterVirtualDevicesChangedObserver(
+        std::move(observer),
+        false /*raise_event_if_virtual_devices_already_present*/);
   }
 
   void AddVirtualDevice(const std::string& device_id) {
@@ -69,10 +77,14 @@
     info.descriptor.set_display_name(device_id);
     info.descriptor.capture_api = media::VideoCaptureApi::VIRTUAL_DEVICE;
 
+    base::RunLoop wait_loop;
+    closure_to_be_called_on_devices_changed_ = wait_loop.QuitClosure();
     video_capture::mojom::TextureVirtualDevicePtr virtual_device;
     factory_->AddTextureVirtualDevice(info, mojo::MakeRequest(&virtual_device));
     virtual_devices_by_id_.insert(
         std::make_pair(device_id, std::move(virtual_device)));
+    // Wait for confirmation from the service.
+    wait_loop.Run();
   }
 
   void RemoveVirtualDevice(const std::string& device_id) {
@@ -109,6 +121,13 @@
     ASSERT_TRUE(ExecuteScript(shell(), kResetHasReceivedChangedEventFlag));
   }
 
+  // Implementation of video_capture::mojom::DevicesChangedObserver:
+  void OnDevicesChanged() override {
+    if (closure_to_be_called_on_devices_changed_) {
+      std::move(closure_to_be_called_on_devices_changed_).Run();
+    }
+  }
+
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     // Note: We are not planning to actually use any fake device, but we want
@@ -139,9 +158,12 @@
       virtual_devices_by_id_;
 
  private:
+  mojo::Binding<video_capture::mojom::DevicesChangedObserver>
+      devices_changed_observer_binding_;
   base::test::ScopedFeatureList scoped_feature_list_;
   video_capture::mojom::DeviceFactoryProviderPtr provider_;
   video_capture::mojom::DeviceFactoryPtr factory_;
+  base::OnceClosure closure_to_be_called_on_devices_changed_;
 
   DISALLOW_COPY_AND_ASSIGN(WebRtcVideoCaptureServiceEnumerationBrowserTest);
 };
@@ -152,11 +174,6 @@
   ConnectToService();
 
   // Exercise
-  // TODO(chfremer): It is probably not guaranteed that the Mojo IPC call to
-  // AddVirtualDevice arrives at the service before the request to enumerate
-  // devices triggered by JavaScript. To guarantee this, we would have to add
-  // a done-callback to AddVirtualDevice() and wait for that to arrive before
-  // doing the enumeration.
   AddVirtualDevice("test");
   EnumerateDevicesInRendererAndVerifyDeviceCount(1);
 
@@ -165,21 +182,8 @@
   DisconnectFromService();
 }
 
-#if defined(OS_LINUX) && defined(ADDRESS_SANITIZER)
-#define MAYBE_RemoveVirtualDeviceAfterItHasBeenEnumerated \
-  DISABLED_RemoveVirtualDeviceAfterItHasBeenEnumerated
-#else
-#define MAYBE_RemoveVirtualDeviceAfterItHasBeenEnumerated \
-  RemoveVirtualDeviceAfterItHasBeenEnumerated
-#endif
 IN_PROC_BROWSER_TEST_F(WebRtcVideoCaptureServiceEnumerationBrowserTest,
-                       MAYBE_RemoveVirtualDeviceAfterItHasBeenEnumerated) {
-  // TODO(chfremer): Remove this when https://crbug.com/876892 is resolved.
-  if (base::FeatureList::IsEnabled(features::kMediaDevicesSystemMonitorCache)) {
-    LOG(WARNING) << "Skipping test, because feature not yet supported when "
-                    "device monitoring is enabled.";
-    return;
-  }
+                       RemoveVirtualDeviceAfterItHasBeenEnumerated) {
   Initialize();
   ConnectToService();
 
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 75da2a9..d6479c6 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -337,8 +337,7 @@
 
   webrtc::PeerConnectionDependencies dependencies(observer);
   dependencies.allocator = CreatePortAllocator(web_frame);
-  dependencies.async_resolver_factory =
-      std::make_unique<ProxyAsyncResolverFactory>(socket_factory_.get());
+  dependencies.async_resolver_factory = CreateAsyncResolverFactory();
   return GetPcFactory()
       ->CreatePeerConnection(config, std::move(dependencies))
       .get();
@@ -462,6 +461,11 @@
   return port_allocator;
 }
 
+std::unique_ptr<webrtc::AsyncResolverFactory>
+PeerConnectionDependencyFactory::CreateAsyncResolverFactory() {
+  return std::make_unique<ProxyAsyncResolverFactory>(socket_factory_.get());
+}
+
 scoped_refptr<webrtc::MediaStreamInterface>
 PeerConnectionDependencyFactory::CreateLocalMediaStream(
     const std::string& label) {
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
index 0d9671b..137b36ac 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.h
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
@@ -87,6 +87,10 @@
   virtual std::unique_ptr<P2PPortAllocator> CreatePortAllocator(
       blink::WebLocalFrame* web_frame);
 
+  // Creates an AsyncResolverFactory that uses the networking Mojo service.
+  virtual std::unique_ptr<webrtc::AsyncResolverFactory>
+  CreateAsyncResolverFactory();
+
   // Creates a libjingle representation of a Session description. Used by a
   // RTCPeerConnectionHandler instance.
   virtual webrtc::SessionDescriptionInterface* CreateSessionDescription(
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 13cb1730..d69362ff 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -733,6 +733,16 @@
   return rtc_dependency_factory->CreatePortAllocator(frame);
 }
 
+std::unique_ptr<webrtc::AsyncResolverFactory>
+RendererBlinkPlatformImpl::CreateWebRtcAsyncResolverFactory() {
+  RenderThreadImpl* render_thread = RenderThreadImpl::current();
+  DCHECK(render_thread);
+  PeerConnectionDependencyFactory* rtc_dependency_factory =
+      render_thread->GetPeerConnectionDependencyFactory();
+  rtc_dependency_factory->EnsureInitialized();
+  return rtc_dependency_factory->CreateAsyncResolverFactory();
+}
+
 //------------------------------------------------------------------------------
 
 std::unique_ptr<WebCanvasCaptureHandler>
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 0052cff0..a65c2138 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -160,6 +160,8 @@
   rtc::Thread* GetWebRtcWorkerThreadRtcThread() override;
   std::unique_ptr<cricket::PortAllocator> CreateWebRtcPortAllocator(
       blink::WebLocalFrame* frame) override;
+  std::unique_ptr<webrtc::AsyncResolverFactory>
+  CreateWebRtcAsyncResolverFactory() override;
   std::unique_ptr<blink::WebCanvasCaptureHandler> CreateCanvasCaptureHandler(
       const blink::WebSize& size,
       double frame_rate,
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py
index e05b5b77..4e578de 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -70,7 +70,17 @@
     # TODO: remove this once the bug is addressed.
     if os.name == 'nt':
       browser_options.logging_verbosity = browser_options.VERBOSE_LOGGING
-      logging.getLogger().setLevel(logging.DEBUG)
+      # Fix up logging to provide filename and line number:
+      # First need to remove any existing handles so that logging.basicConfig
+      # works (see
+      # https://docs.python.org/2/library/logging.html#logging.basicConfig)
+      root_logger = logging.getLogger()
+      for handler in root_logger.handlers:
+        root_logger.removeHandler(handler)
+      # Now set the basic config so we can find the filename and line number:
+      FORMAT = "[%(levelname)s:%(filename)s:%(lineno)s] %(message)s"
+      logging.basicConfig(format=FORMAT)
+      root_logger.setLevel(logging.DEBUG)
 
     # A non-sandboxed, 15-seconds-delayed gpu process is currently running in
     # the browser to collect gpu info. A command line switch is added here to
diff --git a/docs/chromeos_glossary.md b/docs/chromeos_glossary.md
new file mode 100644
index 0000000..acbb099
--- /dev/null
+++ b/docs/chromeos_glossary.md
@@ -0,0 +1 @@
+See [Chromium OS Glossary](https://chromium.googlesource.com/chromiumos/docs/+/master/glossary.md)
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index 691b82a..6d6db7c 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -196,6 +196,7 @@
       "browser/shell_native_app_window_aura.h",
     ]
     deps += [
+      "//ui/base/user_activity",
       "//ui/platform_window",
       "//ui/wm",
       "//ui/wm/public",
diff --git a/fuchsia/browser/frame_impl.cc b/fuchsia/browser/frame_impl.cc
index 3744b0f..0433bdb 100644
--- a/fuchsia/browser/frame_impl.cc
+++ b/fuchsia/browser/frame_impl.cc
@@ -191,8 +191,11 @@
       binding_(this, std::move(frame_request)) {
   web_contents_->SetDelegate(this);
   Observe(web_contents_.get());
-  binding_.set_error_handler(
-      [this](zx_status_t status) { context_->DestroyFrame(this); });
+  binding_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " Frame disconnected.";
+    context_->DestroyFrame(this);
+  });
 
   content::UpdateFontRendererPreferencesFromSystemSettings(
       web_contents_->GetMutableRendererPrefs());
diff --git a/fuchsia/browser/frame_impl_browsertest.cc b/fuchsia/browser/frame_impl_browsertest.cc
index 5cf54a35..aa678a8 100644
--- a/fuchsia/browser/frame_impl_browsertest.cc
+++ b/fuchsia/browser/frame_impl_browsertest.cc
@@ -152,7 +152,10 @@
   EXPECT_TRUE(frame);
 
   base::RunLoop run_loop;
-  frame.set_error_handler([&run_loop](zx_status_t status) { run_loop.Quit(); });
+  frame.set_error_handler([&run_loop](zx_status_t status) {
+    EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
+    run_loop.Quit();
+  });
   context().Unbind();
   run_loop.Run();
   EXPECT_FALSE(frame);
diff --git a/fuchsia/browser/message_port_impl.cc b/fuchsia/browser/message_port_impl.cc
index c49b246..f7728e3 100644
--- a/fuchsia/browser/message_port_impl.cc
+++ b/fuchsia/browser/message_port_impl.cc
@@ -113,8 +113,8 @@
   connector_->set_connection_error_handler(
       base::BindOnce(&MessagePortImpl::OnDisconnected, base::Unretained(this)));
   binding_.set_error_handler([this](zx_status_t status) {
-    if (status != ZX_OK && status != ZX_ERR_PEER_CLOSED)
-      ZX_DLOG(INFO, status) << "Disconnected";
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " MessagePort disconnected.";
 
     OnDisconnected();
   });
diff --git a/fuchsia/browser/webrunner_browser_main_parts.cc b/fuchsia/browser/webrunner_browser_main_parts.cc
index 75581a2..c069b2f 100644
--- a/fuchsia/browser/webrunner_browser_main_parts.cc
+++ b/fuchsia/browser/webrunner_browser_main_parts.cc
@@ -8,6 +8,8 @@
 
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/fuchsia/fuchsia_logging.h"
+#include "base/logging.h"
 #include "content/public/browser/render_frame_host.h"
 #include "fuchsia/browser/context_impl.h"
 #include "fuchsia/browser/webrunner_browser_context.h"
@@ -52,7 +54,8 @@
 
   // Quit the browser main loop when the Context connection is dropped.
   context_binding_->set_error_handler([this](zx_status_t status) {
-    DLOG(WARNING) << "Client connection to Context service dropped.";
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " Context disconnected.";
     context_service_.reset();
     std::move(quit_closure_).Run();
   });
diff --git a/fuchsia/common/named_message_port_connector_browsertest.cc b/fuchsia/common/named_message_port_connector_browsertest.cc
index ef2bee25..fa88f1cd5 100644
--- a/fuchsia/common/named_message_port_connector_browsertest.cc
+++ b/fuchsia/common/named_message_port_connector_browsertest.cc
@@ -111,7 +111,8 @@
   // Ensure that the MessagePort is dropped when navigating away.
   {
     base::RunLoop run_loop;
-    (*message_port).set_error_handler([&run_loop](zx_status_t) {
+    (*message_port).set_error_handler([&run_loop](zx_status_t status) {
+      EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
       run_loop.Quit();
     });
     controller->LoadUrl("about:blank", nullptr);
diff --git a/fuchsia/http/url_loader_impl.cc b/fuchsia/http/url_loader_impl.cc
index 78bee86..e09aac9 100644
--- a/fuchsia/http/url_loader_impl.cc
+++ b/fuchsia/http/url_loader_impl.cc
@@ -122,7 +122,11 @@
       context_(std::move(context)),
       buffer_(new net::GrowableIOBuffer()),
       write_watch_(FROM_HERE) {
-  binding_.set_error_handler([this](zx_status_t status) { delete this; });
+  binding_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " URLLoader disconnected.";
+    delete this;
+  });
   g_active_requests++;
 }
 
diff --git a/fuchsia/runners/cast/cast_channel_bindings.cc b/fuchsia/runners/cast/cast_channel_bindings.cc
index 7e78b58..3512745 100644
--- a/fuchsia/runners/cast/cast_channel_bindings.cc
+++ b/fuchsia/runners/cast/cast_channel_bindings.cc
@@ -35,7 +35,7 @@
   DCHECK(frame_);
 
   channel_consumer_.set_error_handler([this](zx_status_t status) mutable {
-    ZX_LOG(ERROR, status) << "CastChannel error:";
+    ZX_LOG(ERROR, status) << " Agent disconnected.";
     std::move(on_error_closure_).Run();
   });
 
diff --git a/fuchsia/runners/common/web_component.cc b/fuchsia/runners/common/web_component.cc
index 50864fa..c86a450 100644
--- a/fuchsia/runners/common/web_component.cc
+++ b/fuchsia/runners/common/web_component.cc
@@ -9,6 +9,7 @@
 #include <lib/fit/function.h>
 #include <utility>
 
+#include "base/fuchsia/fuchsia_logging.h"
 #include "base/fuchsia/scoped_service_binding.h"
 #include "base/fuchsia/service_directory.h"
 #include "base/logging.h"
@@ -57,7 +58,10 @@
   if (controller_request.is_valid()) {
     controller_binding_.Bind(std::move(controller_request));
     controller_binding_.set_error_handler([this](zx_status_t status) {
-      // Signal graceful process termination.
+      ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+          << " ComponentController disconnected.";
+      // Teardown the component with dummy values, since ComponentController
+      // channel isn't there to receive them.
       DestroyComponent(0, fuchsia::sys::TerminationReason::EXITED);
     });
   }
diff --git a/fuchsia/service/context_provider_impl.cc b/fuchsia/service/context_provider_impl.cc
index 3a6082d..3183327 100644
--- a/fuchsia/service/context_provider_impl.cc
+++ b/fuchsia/service/context_provider_impl.cc
@@ -131,7 +131,6 @@
   ignore_result(launch_.Run(std::move(launch_command), launch_options));
 
   ignore_result(context_handle.release());
-  ignore_result(job.release());
 }
 
 void ContextProviderImpl::Bind(
diff --git a/fuchsia/service/context_provider_impl_unittest.cc b/fuchsia/service/context_provider_impl_unittest.cc
index ac744c1..f548786 100644
--- a/fuchsia/service/context_provider_impl_unittest.cc
+++ b/fuchsia/service/context_provider_impl_unittest.cc
@@ -7,6 +7,7 @@
 #include <lib/fdio/util.h>
 #include <lib/fidl/cpp/binding.h>
 #include <zircon/processargs.h>
+#include <zircon/types.h>
 
 #include <functional>
 #include <string>
@@ -22,12 +23,14 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/fuchsia/default_job.h"
 #include "base/fuchsia/file_utils.h"
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/fuchsia/service_directory.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
 #include "fuchsia/fidl/chromium/web/cpp/fidl_test_base.h"
 #include "fuchsia/service/common.h"
 #include "fuchsia/test/fake_context.h"
@@ -79,8 +82,10 @@
 
   // Quit the process when the context is destroyed.
   base::RunLoop run_loop;
-  context_binding.set_error_handler(
-      [&run_loop](zx_status_t status) { run_loop.Quit(); });
+  context_binding.set_error_handler([&run_loop](zx_status_t status) {
+    EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
+    run_loop.Quit();
+  });
   run_loop.Run();
 
   return 0;
@@ -108,12 +113,14 @@
     // Call a Context method and wait for it to invoke an observer call.
     base::RunLoop run_loop;
     context->set_error_handler([&run_loop](zx_status_t status) {
+      ZX_LOG(ERROR, status) << " Context lost.";
       ADD_FAILURE();
       run_loop.Quit();
     });
 
     chromium::web::FramePtr frame_ptr;
     frame_ptr.set_error_handler([&run_loop](zx_status_t status) {
+      ZX_LOG(ERROR, status) << " Frame lost.";
       ADD_FAILURE();
       run_loop.Quit();
     });
@@ -148,8 +155,10 @@
   void CheckContextUnresponsive(
       fidl::InterfacePtr<chromium::web::Context>* context) {
     base::RunLoop run_loop;
-    context->set_error_handler(
-        [&run_loop](zx_status_t status) { run_loop.Quit(); });
+    context->set_error_handler([&run_loop](zx_status_t status) {
+      EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
+      run_loop.Quit();
+    });
 
     chromium::web::FramePtr frame;
     (*context)->CreateFrame(frame.NewRequest());
@@ -268,4 +277,48 @@
   CheckContextUnresponsive(&context);
 }
 
+static bool WaitUntilJobIsEmpty(zx::unowned_job job, zx::duration timeout) {
+  zx_signals_t observed = 0;
+  zx_status_t status =
+      job->wait_one(ZX_JOB_NO_JOBS, zx::deadline_after(timeout), &observed);
+  ZX_CHECK(status == ZX_OK || status == ZX_ERR_TIMED_OUT, status);
+  return observed & ZX_JOB_NO_JOBS;
+}
+
+// Regression test for https://crbug.com/927403 (Job leak per-Context).
+TEST_F(ContextProviderImplTest, CleansUpContextJobs) {
+  // Replace the default job with one that is guaranteed to be empty.
+  zx::job job;
+  ASSERT_EQ(base::GetDefaultJob()->duplicate(ZX_RIGHT_SAME_RIGHTS, &job),
+            ZX_OK);
+  base::ScopedDefaultJobForTest empty_default_job(std::move(job));
+
+  // Bind to the ContextProvider.
+  chromium::web::ContextProviderPtr provider;
+  provider_->Bind(provider.NewRequest());
+
+  // Verify that our current default job is still empty.
+  ASSERT_TRUE(WaitUntilJobIsEmpty(base::GetDefaultJob(), zx::duration()));
+
+  // Create a Context and verify that it is functional.
+  chromium::web::ContextPtr context;
+  provider->Create(BuildCreateContextParams(), context.NewRequest());
+  CheckContextResponsive(&context);
+
+  // Verify that there is at least one job under our default job.
+  ASSERT_FALSE(WaitUntilJobIsEmpty(base::GetDefaultJob(), zx::duration()));
+
+  // Detach from the Context and ContextProvider, and spin the loop to allow
+  // those to be handled.
+  context.Unbind();
+  provider.Unbind();
+  base::RunLoop().RunUntilIdle();
+
+  // Wait until the default job signals that it no longer contains any child
+  // jobs; this should occur shortly after the Context process terminates.
+  EXPECT_TRUE(WaitUntilJobIsEmpty(
+      base::GetDefaultJob(),
+      zx::duration(TestTimeouts::action_timeout().InNanoseconds())));
+}
+
 }  // namespace webrunner
diff --git a/fuchsia/test/fake_context.cc b/fuchsia/test/fake_context.cc
index d2eafb6..c9a72dc 100644
--- a/fuchsia/test/fake_context.cc
+++ b/fuchsia/test/fake_context.cc
@@ -4,13 +4,17 @@
 
 #include "fuchsia/test/fake_context.h"
 
+#include "base/fuchsia/fuchsia_logging.h"
 #include "base/logging.h"
 
 namespace webrunner {
 
 FakeFrame::FakeFrame(fidl::InterfaceRequest<chromium::web::Frame> request)
     : binding_(this, std::move(request)) {
-  binding_.set_error_handler([this](zx_status_t status) { delete this; });
+  binding_.set_error_handler([this](zx_status_t status) {
+    ZX_CHECK(status == ZX_ERR_PEER_CLOSED, status);
+    delete this;
+  });
 }
 
 FakeFrame::~FakeFrame() = default;
diff --git a/gpu/command_buffer/service/gl_context_virtual.cc b/gpu/command_buffer/service/gl_context_virtual.cc
index fad50ab..8eea608 100644
--- a/gpu/command_buffer/service/gl_context_virtual.cc
+++ b/gpu/command_buffer/service/gl_context_virtual.cc
@@ -27,9 +27,7 @@
     base::WeakPtr<GLContextVirtualDelegate> delegate)
     : GLContext(share_group),
       shared_context_(shared_context),
-      delegate_(delegate) {
-  shared_context_->AddVirtualOwner(this);
-}
+      delegate_(delegate) {}
 
 bool GLContextVirtual::Initialize(gl::GLSurface* compatible_surface,
                                   const gl::GLContextAttribs& attribs) {
@@ -38,8 +36,7 @@
 }
 
 void GLContextVirtual::Destroy() {
-  ReleaseCurrent(nullptr);
-  shared_context_->RemoveVirtualOwner(this);
+  shared_context_->OnReleaseVirtuallyCurrent(this);
   shared_context_ = nullptr;
 }
 
@@ -57,17 +54,10 @@
 }
 
 void GLContextVirtual::ReleaseCurrent(gl::GLSurface* surface) {
-  if (!IsCurrent(surface))
-    return;
-
-  shared_context_->OnReleaseVirtuallyCurrent(this);
-
-  // If we are releasing a specific surface, we need to call ReleaseCurrent, as
-  // the surface may need to be destroyed.
-  // Additionally, if this is the last virtual context owner of a real context
-  // we may be tearing down and should also release.
-  if (surface || shared_context_->IsLastVirtualOwner(this))
+  if (IsCurrent(surface)) {
+    shared_context_->OnReleaseVirtuallyCurrent(this);
     shared_context_->ReleaseCurrent(surface);
+  }
 }
 
 bool GLContextVirtual::IsCurrent(gl::GLSurface* surface) {
diff --git a/gpu/command_buffer/service/gl_context_virtual.h b/gpu/command_buffer/service/gl_context_virtual.h
index 7b8dcc15..dc3d4d5 100644
--- a/gpu/command_buffer/service/gl_context_virtual.h
+++ b/gpu/command_buffer/service/gl_context_virtual.h
@@ -24,9 +24,7 @@
 class GLContextVirtualDelegate;
 
 // Encapsulates a virtual OpenGL context.
-// This class is final to avoid potential issues due to virtual function calls
-// in the destructor.
-class GPU_GLES2_EXPORT GLContextVirtual final : public gl::GLContext {
+class GPU_GLES2_EXPORT GLContextVirtual : public gl::GLContext {
  public:
   GLContextVirtual(gl::GLShareGroup* share_group,
                    gl::GLContext* shared_context,
diff --git a/gpu/command_buffer/service/gl_context_virtual_unittest.cc b/gpu/command_buffer/service/gl_context_virtual_unittest.cc
index d1553e1..fb9ab6c2 100644
--- a/gpu/command_buffer/service/gl_context_virtual_unittest.cc
+++ b/gpu/command_buffer/service/gl_context_virtual_unittest.cc
@@ -37,6 +37,12 @@
   EXPECT_CALL(*gl_, GetError())
       .Times(AnyNumber())
       .WillRepeatedly(Return(GL_NO_ERROR));
+  EXPECT_CALL(*gl_, GetString(GL_VERSION))
+      .Times(AnyNumber())
+      .WillRepeatedly(Return(reinterpret_cast<unsigned const char *>("2.0")));
+  EXPECT_CALL(*gl_, GetString(GL_EXTENSIONS))
+      .Times(AnyNumber())
+      .WillRepeatedly(Return(reinterpret_cast<unsigned const char *>("")));
   {
     scoped_refptr<gl::GLContextStub> base_context = new gl::GLContextStub;
     gl::GLShareGroup* share_group = base_context->share_group();
@@ -57,130 +63,6 @@
   }
 }
 
-// Tests that destroying the last virtual context referring to a real context
-// releases the real context.
-TEST_F(GLContextVirtualTest, DestroyMultiple) {
-  // Setup.
-  EXPECT_CALL(*gl_, GetError())
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(GL_NO_ERROR));
-  EXPECT_CALL(*gl_, GetString(GL_VERSION))
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(reinterpret_cast<unsigned const char*>("2.0")));
-  EXPECT_CALL(*gl_, GetString(GL_EXTENSIONS))
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(reinterpret_cast<unsigned const char*>("")));
-
-  scoped_refptr<gl::GLContextStub> base_context = new gl::GLContextStub;
-  gl::GLShareGroup* share_group = base_context->share_group();
-  share_group->SetSharedContext(GetGLSurface(), base_context.get());
-
-  // Create two virtual contexts.
-  scoped_refptr<GLContextVirtual> context_a(new GLContextVirtual(
-      share_group, base_context.get(), decoder_->AsWeakPtr()));
-  EXPECT_TRUE(context_a->Initialize(GetGLSurface(), gl::GLContextAttribs()));
-  EXPECT_TRUE(context_a->MakeCurrent(GetGLSurface()));
-
-  scoped_refptr<GLContextVirtual> context_b(new GLContextVirtual(
-      share_group, base_context.get(), decoder_->AsWeakPtr()));
-  EXPECT_TRUE(context_b->Initialize(GetGLSurface(), gl::GLContextAttribs()));
-  EXPECT_TRUE(context_b->MakeCurrent(GetGLSurface()));
-
-  // Ensure that the base context is current.
-  EXPECT_TRUE(base_context->IsCurrent(GetGLSurface()));
-
-  // Release the first context, base context should still be current.
-  context_a.reset();
-  EXPECT_TRUE(base_context->IsCurrent(GetGLSurface()));
-
-  // Release the second context, base context should now no longer be current.
-  context_b.reset();
-  EXPECT_FALSE(base_context->IsCurrent(GetGLSurface()));
-}
-
-// Tests that calling ReleaseCurrent on a virtual context does not release the
-// real context if other virtual contexts referring to it exist.
-TEST_F(GLContextVirtualTest, ReleaseLastOwner) {
-  // Setup.
-  EXPECT_CALL(*gl_, GetError())
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(GL_NO_ERROR));
-  EXPECT_CALL(*gl_, GetString(GL_VERSION))
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(reinterpret_cast<unsigned const char*>("2.0")));
-  EXPECT_CALL(*gl_, GetString(GL_EXTENSIONS))
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(reinterpret_cast<unsigned const char*>("")));
-
-  scoped_refptr<gl::GLContextStub> base_context = new gl::GLContextStub;
-  gl::GLShareGroup* share_group = base_context->share_group();
-  share_group->SetSharedContext(GetGLSurface(), base_context.get());
-
-  // Create two virtual contexts.
-  scoped_refptr<GLContextVirtual> context_a(new GLContextVirtual(
-      share_group, base_context.get(), decoder_->AsWeakPtr()));
-  EXPECT_TRUE(context_a->Initialize(GetGLSurface(), gl::GLContextAttribs()));
-  EXPECT_TRUE(context_a->MakeCurrent(GetGLSurface()));
-
-  scoped_refptr<GLContextVirtual> context_b(new GLContextVirtual(
-      share_group, base_context.get(), decoder_->AsWeakPtr()));
-  EXPECT_TRUE(context_b->Initialize(GetGLSurface(), gl::GLContextAttribs()));
-  EXPECT_TRUE(context_b->MakeCurrent(GetGLSurface()));
-
-  // Ensure that the base context is current.
-  EXPECT_TRUE(base_context->IsCurrent(GetGLSurface()));
-
-  // Release the first context, base context should still be current.
-  context_a->ReleaseCurrent(nullptr);
-  EXPECT_TRUE(base_context->IsCurrent(GetGLSurface()));
-
-  // Delete |context_a| - still no change.
-  context_a.reset();
-  EXPECT_TRUE(base_context->IsCurrent(GetGLSurface()));
-
-  // Release the second context, base context should now no longer be current.
-  context_b->ReleaseCurrent(nullptr);
-  EXPECT_FALSE(base_context->IsCurrent(GetGLSurface()));
-}
-
-// Tests that releasing a specific surface always calls ReleaseCurrent, even if
-// other virtual contextx exist.
-TEST_F(GLContextVirtualTest, ReleaseSpecificSurface) {
-  // Setup.
-  EXPECT_CALL(*gl_, GetError())
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(GL_NO_ERROR));
-  EXPECT_CALL(*gl_, GetString(GL_VERSION))
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(reinterpret_cast<unsigned const char*>("2.0")));
-  EXPECT_CALL(*gl_, GetString(GL_EXTENSIONS))
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(reinterpret_cast<unsigned const char*>("")));
-
-  scoped_refptr<gl::GLContextStub> base_context = new gl::GLContextStub;
-  gl::GLShareGroup* share_group = base_context->share_group();
-  share_group->SetSharedContext(GetGLSurface(), base_context.get());
-
-  // Create two virtual contexts.
-  scoped_refptr<GLContextVirtual> context_a(new GLContextVirtual(
-      share_group, base_context.get(), decoder_->AsWeakPtr()));
-  EXPECT_TRUE(context_a->Initialize(GetGLSurface(), gl::GLContextAttribs()));
-  EXPECT_TRUE(context_a->MakeCurrent(GetGLSurface()));
-
-  scoped_refptr<GLContextVirtual> context_b(new GLContextVirtual(
-      share_group, base_context.get(), decoder_->AsWeakPtr()));
-  EXPECT_TRUE(context_b->Initialize(GetGLSurface(), gl::GLContextAttribs()));
-  EXPECT_TRUE(context_b->MakeCurrent(GetGLSurface()));
-
-  // Ensure that the base context is current.
-  EXPECT_TRUE(base_context->IsCurrent(GetGLSurface()));
-
-  // Release a specific surface on the first context, base context should be
-  // released.
-  context_a->ReleaseCurrent(GetGLSurface());
-  EXPECT_FALSE(base_context->IsCurrent(GetGLSurface()));
-}
-
 }  // anonymous namespace
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index e270703..ec7662313 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -18507,7 +18507,7 @@
   // On Adreno Android devices we need to use a workaround to force caches to
   // clear.
   if (workarounds().unbind_egl_context_to_flush_driver_caches) {
-    context_->ReleaseCurrent(surface_.get());
+    context_->ReleaseCurrent(nullptr);
     context_->MakeCurrent(surface_.get());
   }
 }
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 3a349268..fc5aca5b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -4526,7 +4526,7 @@
   // On Adreno Android devices we need to use a workaround to force caches to
   // clear.
   if (feature_info_->workarounds().unbind_egl_context_to_flush_driver_caches) {
-    context_->ReleaseCurrent(surface_.get());
+    context_->ReleaseCurrent(nullptr);
     context_->MakeCurrent(surface_.get());
   }
   return error::kNoError;
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 753f26832..5fc6dec 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -382,6 +382,13 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
   TRACE_EVENT0("gpu", "InProcessCommandBuffer::InitializeOnGpuThread")
 
+  if (gpu_channel_manager_delegate_ &&
+      gpu_channel_manager_delegate_->IsExiting()) {
+    LOG(ERROR) << "ContextResult::kTransientFailure: trying to create command "
+                  "buffer during process shutdown.";
+    return gpu::ContextResult::kTransientFailure;
+  }
+
   // TODO(crbug.com/832243): This could use the TransferBufferManager owned by
   // |context_group_| instead.
   transfer_buffer_manager_ = std::make_unique<TransferBufferManager>(nullptr);
@@ -752,6 +759,19 @@
   // error and make the race benign.
   UpdateLastStateOnGpuThread();
 
+  bool was_lost_by_robustness =
+      decoder_ && decoder_->WasContextLostByRobustnessExtension();
+
+  // Work around issues with recovery by allowing a new GPU process to launch.
+  if (was_lost_by_robustness) {
+    GpuDriverBugWorkarounds workarounds(
+        GetGpuFeatureInfo().enabled_gpu_driver_bug_workarounds);
+    if (workarounds.exit_on_context_lost && gpu_channel_manager_delegate_)
+      gpu_channel_manager_delegate_->MaybeExitOnContextLost();
+
+    // TODO(crbug.com/924148): Check if we should force lose all contexts too.
+  }
+
   PostOrRunClientCallback(
       base::BindOnce(&InProcessCommandBuffer::OnContextLost,
                      client_thread_weak_ptr_factory_.GetWeakPtr()));
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc
index 899ad32..de1ea8c 100644
--- a/gpu/ipc/service/command_buffer_stub.cc
+++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -378,7 +378,7 @@
     // might bypass the 3D API blocking logic.
     if ((surface_handle_ == gpu::kNullSurfaceHandle) &&
         !active_url_.is_empty() &&
-        !gpu_channel_manager->is_exiting_for_lost_context()) {
+        !gpu_channel_manager->delegate()->IsExiting()) {
       gpu_channel_manager->delegate()->DidDestroyOffscreenContext(active_url_);
     }
   }
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc
index 9546122..16e539de 100644
--- a/gpu/ipc/service/gpu_channel.cc
+++ b/gpu/ipc/service/gpu_channel.cc
@@ -597,7 +597,7 @@
     return;
   }
 
-  if (gpu_channel_manager_->is_exiting_for_lost_context()) {
+  if (gpu_channel_manager_->delegate()->IsExiting()) {
     LOG(ERROR) << "ContextResult::kTransientFailure: trying to create command "
                   "buffer during process shutdown.";
     *result = gpu::ContextResult::kTransientFailure;
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index b0bc3bc..ebf60ad5 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -82,7 +82,6 @@
       gpu_memory_buffer_factory_(gpu_memory_buffer_factory),
       gpu_feature_info_(gpu_feature_info),
       image_decode_accelerator_worker_(image_decode_accelerator_worker),
-      exiting_for_lost_context_(false),
       activity_flags_(std::move(activity_flags)),
       memory_pressure_listener_(
           base::BindRepeating(&GpuChannelManager::HandleMemoryPressure,
@@ -208,18 +207,6 @@
                                         weak_factory_.GetWeakPtr()));
 }
 
-void GpuChannelManager::MaybeExitOnContextLost() {
-  if (gpu_preferences().single_process || gpu_preferences().in_process_gpu)
-    return;
-
-  if (!exiting_for_lost_context_) {
-    LOG(ERROR) << "Exiting GPU process because some drivers cannot recover"
-               << " from problems.";
-    exiting_for_lost_context_ = true;
-    delegate_->ExitProcess();
-  }
-}
-
 void GpuChannelManager::DestroyAllChannels() {
   gpu_channels_.clear();
 }
@@ -455,16 +442,19 @@
 }
 
 void GpuChannelManager::OnContextLost(bool synthetic_loss) {
+  if (synthetic_loss)
+    return;
+
   // Work around issues with recovery by allowing a new GPU process to launch.
-  if (!synthetic_loss && gpu_driver_bug_workarounds_.exit_on_context_lost)
-    MaybeExitOnContextLost();
+  if (gpu_driver_bug_workarounds_.exit_on_context_lost)
+    delegate_->MaybeExitOnContextLost();
 
   // Lose all other contexts.
-  if (!synthetic_loss &&
-      (gl::GLContext::LosesAllContextsOnContextLost() ||
-       (shared_context_state_ &&
-        shared_context_state_->use_virtualized_gl_contexts())))
+  if (gl::GLContext::LosesAllContextsOnContextLost() ||
+      (shared_context_state_ &&
+       shared_context_state_->use_virtualized_gl_contexts())) {
     LoseAllContexts();
+  }
 }
 
 void GpuChannelManager::ScheduleGrContextCleanup() {
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h
index 665ee36a..cae718b 100644
--- a/gpu/ipc/service/gpu_channel_manager.h
+++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -144,8 +144,6 @@
 
   void OnApplicationBackgrounded();
 
-  bool is_exiting_for_lost_context() { return exiting_for_lost_context_; }
-
   MailboxManager* mailbox_manager() { return mailbox_manager_.get(); }
 
   gl::GLShareGroup* share_group() const { return share_group_.get(); }
@@ -183,7 +181,6 @@
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
 
   void LoseAllContexts();
-  void MaybeExitOnContextLost();
 
   // These objects manage channels to individual renderer processes. There is
   // one channel for each renderer process that has connected to this GPU
@@ -225,9 +222,6 @@
 
   ImageDecodeAcceleratorWorker* image_decode_accelerator_worker_ = nullptr;
 
-  // Set during intentional GPU process shutdown.
-  bool exiting_for_lost_context_;
-
   // Flags which indicate GPU process activity. Read by the browser process
   // on GPU process crash.
   GpuProcessActivityFlags activity_flags_;
diff --git a/gpu/ipc/service/gpu_channel_manager_delegate.h b/gpu/ipc/service/gpu_channel_manager_delegate.h
index 6f0688d3..a129472 100644
--- a/gpu/ipc/service/gpu_channel_manager_delegate.h
+++ b/gpu/ipc/service/gpu_channel_manager_delegate.h
@@ -12,6 +12,8 @@
 
 namespace gpu {
 
+// TODO(kylechar): Rename this class. It's used to provide GpuServiceImpl
+// functionality to multiple classes in src/gpu/ so delegate is inaccurate.
 class GpuChannelManagerDelegate {
  public:
   // Called on any successful context creation.
@@ -40,8 +42,14 @@
                                  const std::string& key,
                                  const std::string& shader) = 0;
 
-  // Cleanly exits the GPU process in response to an unrecoverable error.
-  virtual void ExitProcess() = 0;
+  // Cleanly exits the GPU process in response to an error. This will not exit
+  // with in-process GPU as that would also exit the browser. This can only be
+  // called from the GPU thread.
+  virtual void MaybeExitOnContextLost() = 0;
+
+  // Returns true if the GPU process is exiting. This can be called from any
+  // thread.
+  virtual bool IsExiting() const = 0;
 
 #if defined(OS_WIN)
   // Tells the delegate that |child_window| was created in the GPU process and
diff --git a/gpu/ipc/service/gpu_channel_test_common.cc b/gpu/ipc/service/gpu_channel_test_common.cc
index 4a3ba8f4..2d970a8 100644
--- a/gpu/ipc/service/gpu_channel_test_common.cc
+++ b/gpu/ipc/service/gpu_channel_test_common.cc
@@ -36,13 +36,16 @@
   void StoreShaderToDisk(int32_t client_id,
                          const std::string& key,
                          const std::string& shader) override {}
-  void ExitProcess() override {}
+  void MaybeExitOnContextLost() override { is_exiting_ = true; }
+  bool IsExiting() const override { return is_exiting_; }
 #if defined(OS_WIN)
   void SendCreatedChildWindow(SurfaceHandle parent_window,
                               SurfaceHandle child_window) override {}
 #endif
 
  private:
+  bool is_exiting_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(TestGpuChannelManagerDelegate);
 };
 
diff --git a/ios/chrome/browser/signin/ios_chrome_signin_client.mm b/ios/chrome/browser/signin/ios_chrome_signin_client.mm
index b685e3f7..452259d1 100644
--- a/ios/chrome/browser/signin/ios_chrome_signin_client.mm
+++ b/ios/chrome/browser/signin/ios_chrome_signin_client.mm
@@ -7,7 +7,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/metrics/metrics_service.h"
 #include "components/signin/core/browser/cookie_settings_util.h"
-#include "components/signin/core/browser/device_id_helper.h"
 #include "components/signin/ios/browser/account_consistency_service.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/browser_state_info_cache.h"
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index a13495d..f61e21d 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -3395,8 +3395,8 @@
 
   WebStateList* webStateList = self.tabModel.webStateList;
   web::WebState* current_web_state = webStateList->GetActiveWebState();
-  DCHECK(current_web_state);
-  if (transitionType & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) {
+  if (current_web_state &&
+      (transitionType & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)) {
     bool isExpectingVoiceSearch =
         VoiceSearchNavigationTabHelper::FromWebState(current_web_state)
             ->IsExpectingVoiceSearch();
diff --git a/ios/web/find_in_page/find_in_page_manager_impl.h b/ios/web/find_in_page/find_in_page_manager_impl.h
index 4ee00f4..57423ac 100644
--- a/ios/web/find_in_page/find_in_page_manager_impl.h
+++ b/ios/web/find_in_page/find_in_page_manager_impl.h
@@ -29,6 +29,8 @@
   // FindInPageManager overrides
   void Find(NSString* query, FindInPageOptions options) override;
   void StopFinding() override;
+  FindInPageManagerDelegate* GetDelegate() override;
+  void SetDelegate(FindInPageManagerDelegate* delegate) override;
 
  private:
   friend class web::WebStateUserData<FindInPageManagerImpl>;
@@ -36,6 +38,7 @@
   struct FindRequest {
     FindRequest();
     ~FindRequest();
+    int GetTotalMatchCount() const;
     // Unique identifier for each find used to check that it is the most recent
     // find. This ensures that an old find doesn't decrement
     // |pending_frame_calls_count| after it has been reset by the new find.
@@ -65,6 +68,7 @@
 
   // Holds the state of the most recent find in page request.
   FindRequest last_find_request_;
+  FindInPageManagerDelegate* delegate_ = nullptr;
   web::WebState* web_state_ = nullptr;
   base::WeakPtrFactory<FindInPageManagerImpl> weak_factory_;
 };
diff --git a/ios/web/find_in_page/find_in_page_manager_impl.mm b/ios/web/find_in_page/find_in_page_manager_impl.mm
index 8a11623..29852644 100644
--- a/ios/web/find_in_page/find_in_page_manager_impl.mm
+++ b/ios/web/find_in_page/find_in_page_manager_impl.mm
@@ -7,6 +7,7 @@
 #import "base/strings/sys_string_conversions.h"
 #include "base/values.h"
 #import "ios/web/find_in_page/find_in_page_constants.h"
+#import "ios/web/public/find_in_page/find_in_page_manager_delegate.h"
 #import "ios/web/public/web_state/web_frame.h"
 #include "ios/web/public/web_state/web_frame_util.h"
 #import "ios/web/public/web_state/web_frames_manager.h"
@@ -51,10 +52,25 @@
   }
 }
 
+FindInPageManagerDelegate* FindInPageManagerImpl::GetDelegate() {
+  return delegate_;
+}
+void FindInPageManagerImpl::SetDelegate(FindInPageManagerDelegate* delegate) {
+  delegate_ = delegate;
+}
+
 FindInPageManagerImpl::FindRequest::FindRequest() {}
 
 FindInPageManagerImpl::FindRequest::~FindRequest() {}
 
+int FindInPageManagerImpl::FindRequest::GetTotalMatchCount() const {
+  int matches = 0;
+  for (auto pair : frame_match_count) {
+    matches += pair.second;
+  }
+  return matches;
+}
+
 void FindInPageManagerImpl::WebFrameDidBecomeAvailable(WebState* web_state,
                                                        WebFrame* web_frame) {
   const std::string frame_id = web_frame->GetFrameId();
@@ -118,35 +134,45 @@
     // New find was started.
     return;
   }
+  if (!web_state_) {
+    // WebState was destroyed before find finished.
+    return;
+  }
 
   last_find_request_.pending_frame_call_count--;
   WebFrame* frame = GetWebFrameWithId(web_state_, frame_id);
-  // The frame no longer exists. If frame is removed during find, result will
-  // be null.
   if (!result || !frame) {
-    return;
-  }
+    // The frame no longer exists or the function call timed out. In both cases,
+    // result will be null.
+    // Zero out count to ensure every frame is updated for every find.
+    last_find_request_.frame_match_count[frame_id] = 0;
+  } else {
+    int match_count = 0;
+    if (result->is_double()) {
+      // Valid match number returned. If not, match count will be 0 in order to
+      // zero-out count from previous find.
+      match_count = static_cast<int>(result->GetDouble());
+    }
+    // If response is equal to kFindInPagePending, find did not finish in the
+    // JavaScript. Call pumpSearch to continue find.
+    if (match_count == kFindInPagePending) {
+      std::vector<base::Value> params;
+      params.push_back(base::Value(kFindInPageFindTimeout));
+      frame->CallJavaScriptFunction(
+          kFindInPagePump, params,
+          base::BindOnce(&FindInPageManagerImpl::ProcessFindInPageResult,
+                         weak_factory_.GetWeakPtr(), query, frame_id,
+                         unique_id),
+          base::TimeDelta::FromSeconds(kJavaScriptFunctionCallTimeout));
+      return;
+    }
 
-  int matches_count = 0;
-  if (result->is_double()) {
-    // Valid match number returned. If not, match count will be 0 in order to
-    // zero-out count from previous find.
-    matches_count = static_cast<int>(result->GetDouble());
+    last_find_request_.frame_match_count[frame_id] = match_count;
   }
-  // If response is equal to kFindInPagePending, find did not finish in the
-  // JavaScript. Call pumpSearch to continue find.
-  if (matches_count == kFindInPagePending) {
-    std::vector<base::Value> params;
-    params.push_back(base::Value(kFindInPageFindTimeout));
-    frame->CallJavaScriptFunction(
-        kFindInPagePump, params,
-        base::BindOnce(&FindInPageManagerImpl::ProcessFindInPageResult,
-                       weak_factory_.GetWeakPtr(), query, frame_id, unique_id),
-        base::TimeDelta::FromSeconds(kJavaScriptFunctionCallTimeout));
-    return;
+  if (last_find_request_.pending_frame_call_count == 0) {
+    int total_match_count = last_find_request_.GetTotalMatchCount();
+    delegate_->DidCountMatches(web_state_, total_match_count, query);
   }
-
-  last_find_request_.frame_match_count[frame_id] = matches_count;
 }
 
 }  // namespace web
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.mm b/ios/web/navigation/legacy_navigation_manager_impl.mm
index 42b3bcf8..72b6289 100644
--- a/ios/web/navigation/legacy_navigation_manager_impl.mm
+++ b/ios/web/navigation/legacy_navigation_manager_impl.mm
@@ -318,7 +318,7 @@
   } else {
     [session_controller_ discardNonCommittedItems];
     [session_controller_ setPendingItemIndex:index];
-    delegate_->LoadCurrentItem();
+    delegate_->LoadCurrentItem(type);
   }
 }
 
diff --git a/ios/web/navigation/navigation_manager_delegate.h b/ios/web/navigation/navigation_manager_delegate.h
index 9c1bcf3..f855e8f 100644
--- a/ios/web/navigation/navigation_manager_delegate.h
+++ b/ios/web/navigation/navigation_manager_delegate.h
@@ -40,10 +40,10 @@
   virtual void WillChangeUserAgentType() = 0;
 
   // Instructs the delegate to load the current navigation item.
-  virtual void LoadCurrentItem() = 0;
+  virtual void LoadCurrentItem(NavigationInitiationType type) = 0;
 
   // Instructs the delegate to load the current navigation item if the current
-  // page has not loaded yet.
+  // page has not loaded yet. The navigation should be browser-initiated.
   virtual void LoadIfNecessary() = 0;
 
   // Instructs the delegate to reload.
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index 283c1379..f9a0a2a 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -264,7 +264,8 @@
                                NavigationInitiationType type,
                                bool has_user_gesture) = 0;
   virtual void FinishReload();
-  virtual void FinishLoadURLWithParams();
+  virtual void FinishLoadURLWithParams(
+      NavigationInitiationType initiation_type);
 
   // Returns true if the subclass uses placeholder URLs and this is such a URL.
   virtual bool IsPlaceholderUrl(const GURL& url) const;
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm
index d0ea0e2..584f6086 100644
--- a/ios/web/navigation/navigation_manager_impl.mm
+++ b/ios/web/navigation/navigation_manager_impl.mm
@@ -323,7 +323,7 @@
     added_item->SetShouldSkipRepostFormConfirmation(true);
   }
 
-  FinishLoadURLWithParams();
+  FinishLoadURLWithParams(initiation_type);
 }
 
 void NavigationManagerImpl::AddTransientURLRewriter(
@@ -518,8 +518,9 @@
   delegate_->Reload();
 }
 
-void NavigationManagerImpl::FinishLoadURLWithParams() {
-  delegate_->LoadCurrentItem();
+void NavigationManagerImpl::FinishLoadURLWithParams(
+    NavigationInitiationType initiation_type) {
+  delegate_->LoadCurrentItem(initiation_type);
 }
 
 bool NavigationManagerImpl::IsPlaceholderUrl(const GURL& url) const {
diff --git a/ios/web/navigation/navigation_manager_impl_unittest.mm b/ios/web/navigation/navigation_manager_impl_unittest.mm
index 638a01f..834746f 100644
--- a/ios/web/navigation/navigation_manager_impl_unittest.mm
+++ b/ios/web/navigation/navigation_manager_impl_unittest.mm
@@ -84,7 +84,7 @@
   MOCK_METHOD2(OnGoToIndexSameDocumentNavigation,
                void(NavigationInitiationType type, bool has_user_gesture));
   MOCK_METHOD0(WillChangeUserAgentType, void());
-  MOCK_METHOD0(LoadCurrentItem, void());
+  MOCK_METHOD1(LoadCurrentItem, void(NavigationInitiationType type));
   MOCK_METHOD0(LoadIfNecessary, void());
   MOCK_METHOD0(Reload, void());
   MOCK_METHOD1(OnNavigationItemsPruned, void(size_t));
@@ -1767,7 +1767,8 @@
   EXPECT_CALL(navigation_manager_delegate(), WillChangeUserAgentType());
   EXPECT_CALL(navigation_manager_delegate(), RecordPageStateInNavigationItem());
   EXPECT_CALL(navigation_manager_delegate(), ClearTransientContent());
-  EXPECT_CALL(navigation_manager_delegate(), LoadCurrentItem());
+  EXPECT_CALL(navigation_manager_delegate(),
+              LoadCurrentItem(NavigationInitiationType::BROWSER_INITIATED));
 
   navigation_manager()->ReloadWithUserAgentType(UserAgentType::DESKTOP);
 
@@ -2239,7 +2240,9 @@
   EXPECT_CALL(navigation_manager_delegate(), RecordPageStateInNavigationItem())
       .Times(1);
   EXPECT_CALL(navigation_manager_delegate(), ClearTransientContent()).Times(1);
-  EXPECT_CALL(navigation_manager_delegate(), LoadCurrentItem()).Times(1);
+  EXPECT_CALL(navigation_manager_delegate(),
+              LoadCurrentItem(NavigationInitiationType::BROWSER_INITIATED))
+      .Times(1);
 
   navigation_manager()->LoadURLWithParams(params);
 
@@ -2270,7 +2273,9 @@
   EXPECT_CALL(navigation_manager_delegate(), RecordPageStateInNavigationItem())
       .Times(1);
   EXPECT_CALL(navigation_manager_delegate(), ClearTransientContent()).Times(1);
-  EXPECT_CALL(navigation_manager_delegate(), LoadCurrentItem()).Times(1);
+  EXPECT_CALL(navigation_manager_delegate(),
+              LoadCurrentItem(NavigationInitiationType::BROWSER_INITIATED))
+      .Times(1);
 
   navigation_manager()->LoadURLWithParams(params);
 
@@ -2353,7 +2358,8 @@
                     NavigationInitiationType::BROWSER_INITIATED,
                     /*has_user_gesture=*/true))
         .Times(0);
-    EXPECT_CALL(navigation_manager_delegate(), LoadCurrentItem());
+    EXPECT_CALL(navigation_manager_delegate(),
+                LoadCurrentItem(NavigationInitiationType::BROWSER_INITIATED));
   }
 
   navigation_manager()->GoToIndex(0);
@@ -2427,7 +2433,8 @@
                   NavigationInitiationType::BROWSER_INITIATED,
                   /*has_user_gesture=*/true))
       .Times(0);
-  EXPECT_CALL(navigation_manager_delegate(), LoadCurrentItem());
+  EXPECT_CALL(navigation_manager_delegate(),
+              LoadCurrentItem(NavigationInitiationType::BROWSER_INITIATED));
 
   navigation_manager()->GoToIndex(0);
   EXPECT_TRUE(navigation_manager()->GetItemAtIndex(0)->GetTransitionType() &
@@ -2473,7 +2480,8 @@
                 OnGoToIndexSameDocumentNavigation(
                     NavigationInitiationType::BROWSER_INITIATED,
                     /*has_user_gesture=*/true));
-    EXPECT_CALL(navigation_manager_delegate(), LoadCurrentItem()).Times(0);
+    EXPECT_CALL(navigation_manager_delegate(), LoadCurrentItem(testing::_))
+        .Times(0);
   }
 
   navigation_manager()->GoToIndex(0);
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.h b/ios/web/navigation/wk_based_navigation_manager_impl.h
index 57cbc22..a1a21449 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl.h
+++ b/ios/web/navigation/wk_based_navigation_manager_impl.h
@@ -215,7 +215,8 @@
                        NavigationInitiationType initiation_type,
                        bool has_user_gesture) override;
   void FinishReload() override;
-  void FinishLoadURLWithParams() override;
+  void FinishLoadURLWithParams(
+      NavigationInitiationType initiation_type) override;
   bool IsPlaceholderUrl(const GURL& url) const override;
 
   // Restores the specified navigation session in the current web view. This
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm
index a083c47..cf38f77a 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -691,7 +691,8 @@
   delegate_->Reload();
 }
 
-void WKBasedNavigationManagerImpl::FinishLoadURLWithParams() {
+void WKBasedNavigationManagerImpl::FinishLoadURLWithParams(
+    NavigationInitiationType initiation_type) {
   if (!web_view_cache_.IsAttachedToWebView()) {
     DCHECK_EQ(pending_item_index_, -1);
     if (pending_item_ && web_view_cache_.GetBackForwardListItemCount() > 0) {
@@ -711,7 +712,7 @@
     web_view_cache_.ResetToAttached();
   }
 
-  delegate_->LoadCurrentItem();
+  delegate_->LoadCurrentItem(initiation_type);
 }
 
 bool WKBasedNavigationManagerImpl::IsPlaceholderUrl(const GURL& url) const {
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
index a65b410..fae6bea 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
@@ -74,7 +74,7 @@
   MOCK_METHOD2(OnGoToIndexSameDocumentNavigation,
                void(NavigationInitiationType type, bool has_user_gesture));
   MOCK_METHOD0(WillChangeUserAgentType, void());
-  MOCK_METHOD0(LoadCurrentItem, void());
+  MOCK_METHOD1(LoadCurrentItem, void(NavigationInitiationType type));
   MOCK_METHOD0(LoadIfNecessary, void());
   MOCK_METHOD0(Reload, void());
   MOCK_METHOD1(OnNavigationItemsPruned, void(size_t));
diff --git a/ios/web/public/find_in_page/BUILD.gn b/ios/web/public/find_in_page/BUILD.gn
index c27758a..0cf31df 100644
--- a/ios/web/public/find_in_page/BUILD.gn
+++ b/ios/web/public/find_in_page/BUILD.gn
@@ -10,6 +10,7 @@
 
   sources = [
     "find_in_page_manager.h",
+    "find_in_page_manager_delegate.h",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/web/public/find_in_page/find_in_page_manager.h b/ios/web/public/find_in_page/find_in_page_manager.h
index e5c7798..f264c08 100644
--- a/ios/web/public/find_in_page/find_in_page_manager.h
+++ b/ios/web/public/find_in_page/find_in_page_manager.h
@@ -12,6 +12,8 @@
 
 namespace web {
 
+class FindInPageManagerDelegate;
+
 // Indicates what action the FindinPageManager should take.
 enum class FindInPageOptions {
   // Search for a string. Highlight and scroll to the first result if
@@ -35,12 +37,21 @@
   // on |options|. |query| must not be null if |options| is |FindInPageSearch|.
   // |query| is ignored if |options| is not |FindInPageSearch|. If new search is
   // started before previous search finishes, old request will be discarded.
+  //
+  // FindInPageManagerDelegate::DidCountMatches() will be called to return the
+  // total matches found if FindInPageSearch is passed, assuming it hasn't been
+  // discarded. FindInPageManagerDelegate::DidHighlightMatch() will also be
+  // called if matches were found to inform client of the new match that was
+  // highlighted for all FindInPageOptions.
   virtual void Find(NSString* query, FindInPageOptions options) = 0;
 
   // Removes any highlighting. Does nothing if Find() with
   // FindInPageOptions::FindInPageSearch is never called.
   virtual void StopFinding() = 0;
 
+  virtual FindInPageManagerDelegate* GetDelegate() = 0;
+  virtual void SetDelegate(FindInPageManagerDelegate* delegate) = 0;
+
   ~FindInPageManager() override {}
 
  protected:
diff --git a/ios/web/public/find_in_page/find_in_page_manager_delegate.h b/ios/web/public/find_in_page/find_in_page_manager_delegate.h
new file mode 100644
index 0000000..f9fb9126
--- /dev/null
+++ b/ios/web/public/find_in_page/find_in_page_manager_delegate.h
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_FIND_IN_PAGE_FIND_IN_PAGE_MANAGER_DELEGATE_H_
+#define IOS_WEB_PUBLIC_FIND_IN_PAGE_FIND_IN_PAGE_MANAGER_DELEGATE_H_
+
+#include <string>
+
+namespace web {
+
+class WebState;
+
+class FindInPageManagerDelegate {
+ public:
+  FindInPageManagerDelegate() = default;
+
+  // Called when a search for |query| finished with |match_count| found after
+  // calling FindInPageManager::Find() with FindInPageSearch. Even if no matches
+  // are found, call will be made once a find has completed, assuming it has not
+  // been interrupted by another find. Client should check |query| to ensure
+  // that it is processing |match_count| for the correct find.
+  virtual void DidCountMatches(WebState* web_state,
+                               int match_count,
+                               const std::string& query) = 0;
+
+  // Called when a match number |index| is highlighted. This is triggered by
+  // calling FindInPageManager::Find() with any FindInPageOptions to indicate
+  // the new match number that was highlighted. This method is not called if
+  // |FindInPageManager::Find| did not find any matches.
+  virtual void DidHighlightMatch(WebState* web_state, int index) = 0;
+
+ protected:
+  virtual ~FindInPageManagerDelegate() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FindInPageManagerDelegate);
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_PUBLIC_FIND_IN_PAGE_FIND_IN_PAGE_MANAGER_DELEGATE_H_
diff --git a/ios/web/test/fakes/fake_navigation_manager_delegate.h b/ios/web/test/fakes/fake_navigation_manager_delegate.h
index 9378f3d..4d3370f 100644
--- a/ios/web/test/fakes/fake_navigation_manager_delegate.h
+++ b/ios/web/test/fakes/fake_navigation_manager_delegate.h
@@ -18,7 +18,7 @@
   void OnGoToIndexSameDocumentNavigation(NavigationInitiationType type,
                                          bool has_user_gesture) override;
   void WillChangeUserAgentType() override;
-  void LoadCurrentItem() override;
+  void LoadCurrentItem(NavigationInitiationType type) override;
   void LoadIfNecessary() override;
   void Reload() override;
   void OnNavigationItemsPruned(size_t pruned_item_count) override;
diff --git a/ios/web/test/fakes/fake_navigation_manager_delegate.mm b/ios/web/test/fakes/fake_navigation_manager_delegate.mm
index 19a906f..ae0f1493 100644
--- a/ios/web/test/fakes/fake_navigation_manager_delegate.mm
+++ b/ios/web/test/fakes/fake_navigation_manager_delegate.mm
@@ -18,7 +18,8 @@
     NavigationInitiationType type,
     bool has_user_gesture) {}
 void FakeNavigationManagerDelegate::WillChangeUserAgentType() {}
-void FakeNavigationManagerDelegate::LoadCurrentItem() {}
+void FakeNavigationManagerDelegate::LoadCurrentItem(
+    NavigationInitiationType type) {}
 void FakeNavigationManagerDelegate::LoadIfNecessary() {}
 void FakeNavigationManagerDelegate::Reload() {}
 void FakeNavigationManagerDelegate::OnNavigationItemsPruned(
diff --git a/ios/web/web_state/navigation_context_impl.h b/ios/web/web_state/navigation_context_impl.h
index b815cdc..b5c760b 100644
--- a/ios/web/web_state/navigation_context_impl.h
+++ b/ios/web/web_state/navigation_context_impl.h
@@ -58,7 +58,6 @@
   void SetError(NSError* error);
   void SetResponseHeaders(
       const scoped_refptr<net::HttpResponseHeaders>& response_headers);
-  void SetIsRendererInitiated(bool is_renderer_initiated);
 
   // Optional unique id of the navigation item associated with this navigaiton.
   int GetNavigationItemUniqueID() const;
diff --git a/ios/web/web_state/navigation_context_impl.mm b/ios/web/web_state/navigation_context_impl.mm
index 7a5895d4..fbc28ef 100644
--- a/ios/web/web_state/navigation_context_impl.mm
+++ b/ios/web/web_state/navigation_context_impl.mm
@@ -129,10 +129,6 @@
   response_headers_ = response_headers;
 }
 
-void NavigationContextImpl::SetIsRendererInitiated(bool is_renderer_initiated) {
-  is_renderer_initiated_ = is_renderer_initiated;
-}
-
 int NavigationContextImpl::GetNavigationItemUniqueID() const {
   return navigation_item_unique_id_;
 }
diff --git a/ios/web/web_state/navigation_context_impl_unittest.mm b/ios/web/web_state/navigation_context_impl_unittest.mm
index 8a57457..ad4be8f 100644
--- a/ios/web/web_state/navigation_context_impl_unittest.mm
+++ b/ios/web/web_state/navigation_context_impl_unittest.mm
@@ -184,18 +184,6 @@
   EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders());
   EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
 
-  // SetIsRendererInitiated
-  context->SetIsRendererInitiated(true);
-  EXPECT_EQ(new_url, context->GetUrl());
-  EXPECT_TRUE(context->IsSameDocument());
-  EXPECT_TRUE(context->HasCommitted());
-  EXPECT_TRUE(context->IsDownload());
-  ASSERT_TRUE(context->IsPost());
-  EXPECT_EQ(error, context->GetError());
-  EXPECT_TRUE(context->IsRendererInitiated());
-  EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders());
-  EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
-
   // SetWKNavigationType
   context->SetWKNavigationType(WKNavigationTypeBackForward);
   EXPECT_EQ(new_url, context->GetUrl());
@@ -204,7 +192,7 @@
   EXPECT_TRUE(context->IsDownload());
   ASSERT_TRUE(context->IsPost());
   EXPECT_EQ(error, context->GetError());
-  EXPECT_TRUE(context->IsRendererInitiated());
+  EXPECT_FALSE(context->IsRendererInitiated());
   EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders());
   EXPECT_EQ(WKNavigationTypeBackForward, context->GetWKNavigationType());
 }
diff --git a/ios/web/web_state/ui/crw_web_controller.h b/ios/web/web_state/ui/crw_web_controller.h
index e61beb8..9ee6c45 100644
--- a/ios/web/web_state/ui/crw_web_controller.h
+++ b/ios/web/web_state/ui/crw_web_controller.h
@@ -157,7 +157,7 @@
 - (void)stopLoading;
 
 // Loads the URL indicated by current session state.
-- (void)loadCurrentURL;
+- (void)loadCurrentURLWithRendererInitiatedNavigation:(BOOL)rendererInitiated;
 
 // Loads the URL indicated by current session state if the current page has not
 // loaded yet. This method should never be called directly. Use
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 9fc7217..a43c54c 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -526,7 +526,8 @@
 // to notify WebStateObservers.
 - (void)presentNativeContentForNavigationItem:(web::NavigationItem*)item;
 // Notifies WebStateObservers the completion of this navigation.
-- (void)didLoadNativeContentForNavigationItem:(web::NavigationItemImpl*)item;
+- (void)didLoadNativeContentForNavigationItem:(web::NavigationItemImpl*)item
+                            rendererInitiated:(BOOL)rendererInitiated;
 // Loads a blank page directly into WKWebView as a placeholder for a Native View
 // or WebUI URL. This page has the URL about:blank?for=<encoded original URL>.
 // If |originalContext| is provided, reuse it for the placeholder navigation
@@ -534,6 +535,7 @@
 // section of go/bling-navigation-experiment for details.
 - (web::NavigationContextImpl*)
     loadPlaceholderInWebViewForURL:(const GURL&)originalURL
+                 rendererInitiated:(BOOL)rendererInitiated
                         forContext:(std::unique_ptr<web::NavigationContextImpl>)
                                        originalContext;
 // Executes the command specified by the ErrorRetryStateMachine.
@@ -604,21 +606,23 @@
 // transition based on user interaction state. Returns navigation context for
 // this request.
 - (std::unique_ptr<web::NavigationContextImpl>)
-registerLoadRequestForURL:(const GURL&)URL
-   sameDocumentNavigation:(BOOL)sameDocumentNavigation
-           hasUserGesture:(BOOL)hasUserGesture
-    placeholderNavigation:(BOOL)placeholderNavigation;
+    registerLoadRequestForURL:(const GURL&)URL
+       sameDocumentNavigation:(BOOL)sameDocumentNavigation
+               hasUserGesture:(BOOL)hasUserGesture
+            rendererInitiated:(BOOL)rendererInitiated
+        placeholderNavigation:(BOOL)placeholderNavigation;
 // Prepares web controller and delegates for anticipated page change.
 // Allows several methods to invoke webWill/DidAddPendingURL on anticipated page
 // change, using the same cached request and calculated transition types.
 // Returns navigation context for this request.
 - (std::unique_ptr<web::NavigationContextImpl>)
-registerLoadRequestForURL:(const GURL&)URL
-                 referrer:(const web::Referrer&)referrer
-               transition:(ui::PageTransition)transition
-   sameDocumentNavigation:(BOOL)sameDocumentNavigation
-           hasUserGesture:(BOOL)hasUserGesture
-    placeholderNavigation:(BOOL)placeholderNavigation;
+    registerLoadRequestForURL:(const GURL&)URL
+                     referrer:(const web::Referrer&)referrer
+                   transition:(ui::PageTransition)transition
+       sameDocumentNavigation:(BOOL)sameDocumentNavigation
+               hasUserGesture:(BOOL)hasUserGesture
+            rendererInitiated:(BOOL)rendererInitiated
+        placeholderNavigation:(BOOL)placeholderNavigation;
 // Maps WKNavigationType to ui::PageTransition.
 - (ui::PageTransition)pageTransitionFromNavigationType:
     (WKNavigationType)navigationType;
@@ -1366,10 +1370,11 @@
 }
 
 - (std::unique_ptr<web::NavigationContextImpl>)
-registerLoadRequestForURL:(const GURL&)URL
-   sameDocumentNavigation:(BOOL)sameDocumentNavigation
-           hasUserGesture:(BOOL)hasUserGesture
-    placeholderNavigation:(BOOL)placeholderNavigation {
+    registerLoadRequestForURL:(const GURL&)URL
+       sameDocumentNavigation:(BOOL)sameDocumentNavigation
+               hasUserGesture:(BOOL)hasUserGesture
+            rendererInitiated:(BOOL)rendererInitiated
+        placeholderNavigation:(BOOL)placeholderNavigation {
   // Get the navigation type from the last main frame load request, and try to
   // map that to a PageTransition.
   WKNavigationType navigationType =
@@ -1398,18 +1403,20 @@
                            transition:transition
                sameDocumentNavigation:sameDocumentNavigation
                        hasUserGesture:hasUserGesture
+                    rendererInitiated:rendererInitiated
                 placeholderNavigation:placeholderNavigation];
   context->SetWKNavigationType(navigationType);
   return context;
 }
 
 - (std::unique_ptr<web::NavigationContextImpl>)
-registerLoadRequestForURL:(const GURL&)requestURL
-                 referrer:(const web::Referrer&)referrer
-               transition:(ui::PageTransition)transition
-   sameDocumentNavigation:(BOOL)sameDocumentNavigation
-           hasUserGesture:(BOOL)hasUserGesture
-    placeholderNavigation:(BOOL)placeholderNavigation {
+    registerLoadRequestForURL:(const GURL&)requestURL
+                     referrer:(const web::Referrer&)referrer
+                   transition:(ui::PageTransition)transition
+       sameDocumentNavigation:(BOOL)sameDocumentNavigation
+               hasUserGesture:(BOOL)hasUserGesture
+            rendererInitiated:(BOOL)rendererInitiated
+        placeholderNavigation:(BOOL)placeholderNavigation {
   // Transfer time is registered so that further transitions within the time
   // envelope are not also registered as links.
   _lastTransferTimeInSeconds = CFAbsoluteTimeGetCurrent();
@@ -1434,7 +1441,8 @@
   } else {
     self.navigationManagerImpl->AddPendingItem(
         requestURL, referrer, transition,
-        web::NavigationInitiationType::RENDERER_INITIATED,
+        rendererInitiated ? web::NavigationInitiationType::RENDERER_INITIATED
+                          : web::NavigationInitiationType::BROWSER_INITIATED,
         NavigationManager::UserAgentOverrideOption::INHERIT);
     item =
         self.navigationManagerImpl->GetPendingItemInCurrentOrRestoredSession();
@@ -1462,15 +1470,10 @@
     [self recordStateInHistory];
   }
 
-  bool isRendererInitiated =
-      item ? (static_cast<web::NavigationItemImpl*>(item)
-                  ->NavigationInitiationType() ==
-              web::NavigationInitiationType::RENDERER_INITIATED)
-           : true;
   std::unique_ptr<web::NavigationContextImpl> context =
       web::NavigationContextImpl::CreateNavigationContext(
           _webStateImpl, requestURL, hasUserGesture, transition,
-          isRendererInitiated);
+          rendererInitiated);
   context->SetPlaceholderNavigation(placeholderNavigation);
 
   // TODO(crbug.com/676129): LegacyNavigationManagerImpl::AddPendingItem does
@@ -1812,18 +1815,21 @@
 // stack. If the new navigation stack is used, start loading a placeholder
 // into the web view, upon the completion of which the native controller will
 // be triggered.
-- (void)loadCurrentURLInNativeView {
+- (void)loadCurrentURLInNativeViewWithRendererInitiatedNavigation:
+    (BOOL)rendererInitiated {
   if (!web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
     // Free the web view.
     [self removeWebView];
     [self presentNativeContentForNavigationItem:self.currentNavItem];
-    [self didLoadNativeContentForNavigationItem:self.currentNavItem];
+    [self didLoadNativeContentForNavigationItem:self.currentNavItem
+                              rendererInitiated:rendererInitiated];
   } else {
     // Just present the native view now. Leave the rest of native content load
     // until the placeholder navigation finishes.
     [self presentNativeContentForNavigationItem:self.currentNavItem];
     web::NavigationContextImpl* context = [self
         loadPlaceholderInWebViewForURL:self.currentNavItem->GetVirtualURL()
+                     rendererInitiated:rendererInitiated
                             forContext:nullptr];
     context->SetIsNativeContentPresented(true);
   }
@@ -1847,7 +1853,8 @@
   }
 }
 
-- (void)didLoadNativeContentForNavigationItem:(web::NavigationItemImpl*)item {
+- (void)didLoadNativeContentForNavigationItem:(web::NavigationItemImpl*)item
+                            rendererInitiated:(BOOL)rendererInitiated {
   const GURL targetURL = item ? item->GetURL() : GURL::EmptyGURL();
   const web::Referrer referrer;
   std::unique_ptr<web::NavigationContextImpl> context =
@@ -1856,6 +1863,7 @@
                            transition:self.currentTransition
                sameDocumentNavigation:NO
                        hasUserGesture:YES
+                    rendererInitiated:rendererInitiated
                 placeholderNavigation:NO];
 
   _webStateImpl->OnNavigationStarted(context.get());
@@ -1884,6 +1892,7 @@
 
 - (web::NavigationContextImpl*)
     loadPlaceholderInWebViewForURL:(const GURL&)originalURL
+                 rendererInitiated:(BOOL)rendererInitiated
                         forContext:(std::unique_ptr<web::NavigationContextImpl>)
                                        originalContext {
   GURL placeholderURL = CreatePlaceholderUrlForUrl(originalURL);
@@ -1902,6 +1911,7 @@
     navigationContext = [self registerLoadRequestForURL:originalURL
                                  sameDocumentNavigation:NO
                                          hasUserGesture:NO
+                                      rendererInitiated:rendererInitiated
                                   placeholderNavigation:YES];
   }
   [_navigationStates setContext:std::move(navigationContext)
@@ -1925,6 +1935,7 @@
       std::unique_ptr<web::NavigationContextImpl> originalContext =
           [_navigationStates removeNavigation:originalNavigation];
       [self loadPlaceholderInWebViewForURL:item->GetURL()
+                         rendererInitiated:context->IsRendererInitiated()
                                 forContext:std::move(originalContext)];
     } break;
 
@@ -1941,6 +1952,7 @@
           [self registerLoadRequestForURL:item->GetURL()
                    sameDocumentNavigation:NO
                            hasUserGesture:NO
+                        rendererInitiated:context->IsRendererInitiated()
                     placeholderNavigation:NO];
       WKNavigation* navigation =
           [_webView loadHTMLString:@""
@@ -1956,7 +1968,7 @@
   }
 }
 
-- (void)loadCurrentURL {
+- (void)loadCurrentURLWithRendererInitiatedNavigation:(BOOL)rendererInitiated {
   // If the content view doesn't exist, the tab has either been evicted, or
   // never displayed. Bail, and let the URL be loaded when the tab is shown.
   if (!_containerView)
@@ -2009,10 +2021,13 @@
   // replace the appropriate view if so, or transition back to a web view from
   // a native view.
   if ([self shouldLoadURLInNativeView:currentURL]) {
-    [self loadCurrentURLInNativeView];
+    [self loadCurrentURLInNativeViewWithRendererInitiatedNavigation:
+              rendererInitiated];
   } else if (web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
              isCurrentURLAppSpecific && _webStateImpl->HasWebUI()) {
-    [self loadPlaceholderInWebViewForURL:currentURL forContext:nullptr];
+    [self loadPlaceholderInWebViewForURL:currentURL
+                       rendererInitiated:rendererInitiated
+                              forContext:nullptr];
   } else {
     [self loadCurrentURLInWebView];
   }
@@ -2020,7 +2035,7 @@
 
 - (void)loadCurrentURLIfNecessary {
   if (_webProcessCrashed) {
-    [self loadCurrentURL];
+    [self loadCurrentURLWithRendererInitiatedNavigation:NO];
   } else if (!_currentURLLoadWasTrigerred) {
     [self ensureContainerViewCreated];
 
@@ -2031,7 +2046,7 @@
     // TODO(crbug.com/796608): end the practice of calling |loadCurrentURL|
     // when it is possible there is no current URL. If the call performs
     // necessary initialization, break that out.
-    [self loadCurrentURL];
+    [self loadCurrentURLWithRendererInitiatedNavigation:NO];
   }
 }
 
@@ -2052,7 +2067,7 @@
          [_nativeProvider hasControllerForURL:url];
 }
 
-- (void)reloadWithRendererInitiatedNavigation:(BOOL)isRendererInitiated {
+- (void)reloadWithRendererInitiatedNavigation:(BOOL)rendererInitiated {
   // Clear last user interaction.
   // TODO(crbug.com/546337): Move to after the load commits, in the subclass
   // implementation. This will be inaccurate if the reload fails or is
@@ -2067,8 +2082,8 @@
                        transition:ui::PageTransition::PAGE_TRANSITION_RELOAD
            sameDocumentNavigation:NO
                    hasUserGesture:YES
+                rendererInitiated:rendererInitiated
             placeholderNavigation:NO];
-    navigationContext->SetIsRendererInitiated(isRendererInitiated);
     _webStateImpl->OnNavigationStarted(navigationContext.get());
     [self didStartLoading];
     self.navigationManagerImpl->CommitPendingItem();
@@ -2105,11 +2120,12 @@
                            transition:ui::PageTransition::PAGE_TRANSITION_RELOAD
                sameDocumentNavigation:NO
                        hasUserGesture:YES
+                    rendererInitiated:rendererInitiated
                 placeholderNavigation:NO];
         [_navigationStates setContext:std::move(navigationContext)
                         forNavigation:navigation];
       } else {
-        [self loadCurrentURL];
+        [self loadCurrentURLWithRendererInitiatedNavigation:rendererInitiated];
       }
     }
   }
@@ -3186,6 +3202,8 @@
              provisionalLoad:(BOOL)provisionalLoad {
   if ([self shouldCancelLoadForCancelledError:error
                               provisionalLoad:provisionalLoad]) {
+    web::NavigationContextImpl* navigationContext =
+        [_navigationStates contextForNavigation:navigation];
     [self loadCancelled];
     self.navigationManagerImpl->DiscardNonCommittedItems();
     // If discarding the non-committed entries results in native content URL,
@@ -3196,13 +3214,11 @@
         !self.nativeController) {
       GURL lastCommittedURL = self.webState->GetLastCommittedURL();
       if ([self shouldLoadURLInNativeView:lastCommittedURL]) {
-        [self loadCurrentURLInNativeView];
+        [self loadCurrentURLInNativeViewWithRendererInitiatedNavigation:
+                  navigationContext->IsRendererInitiated()];
       }
     }
 
-    web::NavigationContextImpl* navigationContext =
-        [_navigationStates contextForNavigation:navigation];
-
     if (provisionalLoad) {
       _webStateImpl->OnNavigationFinished(navigationContext);
     }
@@ -3916,7 +3932,10 @@
           _webStateImpl->GetSessionCertificatePolicyCache()
               ->RegisterAllowedCertificate(
                   leafCert, base::SysNSStringToUTF8(host), info.cert_status);
-          [self loadCurrentURL];
+          // New navigation is a different navigation from the original one.
+          // The new navigation is always browser-initiated and happens when
+          // the browser allows to proceed with the load.
+          [self loadCurrentURLWithRendererInitiatedNavigation:NO];
         } else {
           // If discarding non-committed items results in a NavigationItem that
           // should be loaded via a native controller, load that URL, as its
@@ -3930,8 +3949,12 @@
           web::NavigationItem* item =
               navigationManager ? navigationManager->GetLastCommittedItem()
                                 : nullptr;
-          if (item && [self shouldLoadURLInNativeView:item->GetURL()])
-            [self loadCurrentURL];
+          if (item && [self shouldLoadURLInNativeView:item->GetURL()]) {
+            // RendererInitiated flag is meaningless for showing previous native
+            // content page. RendererInitiated is used as less previledged.
+            [self
+                loadCurrentURLInNativeViewWithRendererInitiatedNavigation:YES];
+          }
         }
       }));
 
@@ -4191,9 +4214,9 @@
                                    transition:loadHTMLTransition
                        sameDocumentNavigation:NO
                                hasUserGesture:YES
+                            rendererInitiated:NO
                         placeholderNavigation:NO];
   }
-  context->SetIsRendererInitiated(false);
   context->SetLoadingHtmlString(true);
   [_navigationStates setContext:std::move(context) forNavigation:navigation];
 }
@@ -4217,7 +4240,9 @@
   // reload it in its native view.
   if (!self.nativeController &&
       [self shouldLoadURLInNativeView:navigationURL]) {
-    [self loadCurrentURLInNativeView];
+    // RendererInitiated flag is meaningless for showing previous native
+    // content page. RendererInitiated is used as less previledged.
+    [self loadCurrentURLInNativeViewWithRendererInitiatedNavigation:YES];
   }
 }
 
@@ -4780,6 +4805,7 @@
       [self registerLoadRequestForURL:webViewURL
                sameDocumentNavigation:NO
                        hasUserGesture:[_pendingNavigationInfo hasUserGesture]
+                    rendererInitiated:YES
                 placeholderNavigation:IsPlaceholderUrl(webViewURL)];
   _webStateImpl->OnNavigationStarted(navigationContext.get());
   [_navigationStates setContext:std::move(navigationContext)
@@ -4939,7 +4965,24 @@
   // |context| will be nil if this navigation has been already committed and
   // finished.
   if (context) {
-    context->SetHasCommitted(true);
+    web::NavigationManager* navigationManager =
+        _webStateImpl->GetNavigationManager();
+    if ((navigationManager->GetPendingItem()) ||
+        (context->IsLoadingHtmlString()) ||
+        (!web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
+         ui::PageTransitionCoreTypeIs(context->GetPageTransition(),
+                                      ui::PAGE_TRANSITION_RELOAD) &&
+         navigationManager->GetLastCommittedItem())) {
+      // Commit navigation if at least one of these is true:
+      //  - Navigation has pending item (this should always be true, but
+      //    pending item may not exist due to crbug.com/925304).
+      //  - Navigation is loadHTMLString:baseURL: navigation, which does not
+      //    create a pending item, but modifies committed item instead.
+      //  - Transition type is reload with Legacy Navigation Manager (Legacy
+      //    Navigation Manager does not create pending item for reload due to
+      //    crbug.com/676129)
+      context->SetHasCommitted(true);
+    }
     context->SetResponseHeaders(_webStateImpl->GetHttpResponseHeaders());
   }
 
@@ -5222,11 +5265,15 @@
 
       if ([self shouldLoadURLInNativeView:item->GetURL()]) {
         // Native content may have already been presented if this navigation is
-        // started in |-loadCurrentURLInNativeView|. If not, present it now.
+        // started in
+        // |-loadCurrentURLInNativeViewWithRendererInitiatedNavigation:|. If
+        // not, present it now.
         if (!context->IsNativeContentPresented()) {
           [self presentNativeContentForNavigationItem:item];
         }
-        [self didLoadNativeContentForNavigationItem:item];
+        bool rendererInitiated = context->IsRendererInitiated();
+        [self didLoadNativeContentForNavigationItem:item
+                                  rendererInitiated:rendererInitiated];
       } else if (_webUIManager) {
         [_webUIManager loadWebUIForURL:item->GetURL()];
       }
@@ -5462,6 +5509,7 @@
           [self registerLoadRequestForURL:webViewURL
                    sameDocumentNavigation:isSameDocumentNavigation
                            hasUserGesture:NO
+                        rendererInitiated:YES
                     placeholderNavigation:IsPlaceholderUrl(webViewURL)];
       [self webPageChangedWithContext:newContext.get()];
       newContext->SetHasCommitted(!isSameDocumentNavigation);
@@ -5740,6 +5788,7 @@
       newNavigationContext = [self registerLoadRequestForURL:newURL
                                       sameDocumentNavigation:YES
                                               hasUserGesture:NO
+                                           rendererInitiated:YES
                                        placeholderNavigation:NO];
 
       // With slim nav, the web page title is stored in WKBackForwardListItem
@@ -5867,6 +5916,7 @@
                                transition:self.currentTransition
                    sameDocumentNavigation:sameDocumentNavigation
                            hasUserGesture:YES
+                        rendererInitiated:NO
                     placeholderNavigation:NO];
       WKNavigation* navigation = [self loadPOSTRequest:request];
       [_navigationStates setContext:std::move(navigationContext)
@@ -5889,8 +5939,8 @@
                              transition:self.currentTransition
                  sameDocumentNavigation:sameDocumentNavigation
                          hasUserGesture:YES
+                      rendererInitiated:NO
                   placeholderNavigation:IsPlaceholderUrl(navigationURL)];
-    navigationContext->SetIsRendererInitiated(false);
 
     WKNavigation* navigation = nil;
     GURL virtualURL = item ? item->GetVirtualURL() : GURL::EmptyGURL();
@@ -5947,8 +5997,8 @@
                              transition:self.currentTransition
                  sameDocumentNavigation:sameDocumentNavigation
                          hasUserGesture:YES
+                      rendererInitiated:NO
                   placeholderNavigation:NO];
-    navigationContext->SetIsRendererInitiated(false);
     WKNavigation* navigation = nil;
     if (navigationURL == net::GURLWithNSURL([_webView URL])) {
       navigation = [_webView reload];
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 7b61532..b379c95 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -205,6 +205,10 @@
                      return YES;
                    }]];
     [[result stub] setUIDelegate:OCMOCK_ANY];
+    [[result stub] frame];
+    [[result stub] setCustomUserAgent:OCMOCK_ANY];
+    [[result stub] customUserAgent];
+    [static_cast<WKWebView*>([result stub]) loadRequest:OCMOCK_ANY];
     [[result stub] setFrame:GetExpectedWebViewFrame()];
     [[result stub] addObserver:web_controller()
                     forKeyPath:OCMOCK_ANY
@@ -296,7 +300,7 @@
   AddPendingItem(native_url, ui::PAGE_TRANSITION_TYPED);
 
   // Trigger a placeholder navigation.
-  [web_controller() loadCurrentURL];
+  [web_controller() loadCurrentURLWithRendererInitiatedNavigation:NO];
 
   // Simulate the WKNavigationDelegate callbacks for the placeholder navigation
   // arriving after another pending item has already been created.
@@ -610,6 +614,7 @@
   // Simulate data:// url response with text/html MIME type.
   GURL url(kTestDataURL);
   AddPendingItem(url, ui::PAGE_TRANSITION_TYPED);
+  [web_controller() loadCurrentURLWithRendererInitiatedNavigation:NO];
   SetWebViewURL(@(kTestDataURL));
   NSURLResponse* response = [[NSHTTPURLResponse alloc]
        initWithURL:[NSURL URLWithString:@(kTestDataURL)]
@@ -834,7 +839,7 @@
         URL, Referrer(), ui::PAGE_TRANSITION_TYPED,
         NavigationInitiationType::BROWSER_INITIATED,
         NavigationManager::UserAgentOverrideOption::INHERIT);
-    [web_controller() loadCurrentURL];
+    [web_controller() loadCurrentURLWithRendererInitiatedNavigation:NO];
 
     // Native URL is loaded asynchronously with WKBasedNavigationManager. Wait
     // for navigation to finish before asserting.
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index 98defc2f..643a8094 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -276,7 +276,7 @@
   void OnGoToIndexSameDocumentNavigation(NavigationInitiationType type,
                                          bool has_user_gesture) override;
   void WillChangeUserAgentType() override;
-  void LoadCurrentItem() override;
+  void LoadCurrentItem(NavigationInitiationType type) override;
   void LoadIfNecessary() override;
   void Reload() override;
   void OnNavigationItemsPruned(size_t pruned_item_count) override;
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 58e6503..c67c159 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -835,8 +835,9 @@
   [web_controller_ requirePageReconstruction];
 }
 
-void WebStateImpl::LoadCurrentItem() {
-  [web_controller_ loadCurrentURL];
+void WebStateImpl::LoadCurrentItem(NavigationInitiationType type) {
+  [web_controller_ loadCurrentURLWithRendererInitiatedNavigation:
+                       type == NavigationInitiationType::RENDERER_INITIATED];
 }
 
 void WebStateImpl::LoadIfNecessary() {
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.mm b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
index b4ad7dc..2d73cb0 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.mm
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
@@ -5,7 +5,6 @@
 #include "ios/web_view/internal/signin/ios_web_view_signin_client.h"
 
 #include "components/signin/core/browser/cookie_settings_util.h"
-#include "components/signin/core/browser/device_id_helper.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #import "ios/web_view/internal/sync/cwv_sync_controller_internal.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/net/BUILD.gn b/net/BUILD.gn
index ace5ca4..aca9ff9f 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1047,8 +1047,6 @@
       "socket/socks_client_socket.h",
       "socket/socks_connect_job.cc",
       "socket/socks_connect_job.h",
-      "socket/ssl_client_socket_pool.cc",
-      "socket/ssl_client_socket_pool.h",
       "socket/ssl_server_socket.h",
       "socket/ssl_server_socket_impl.cc",
       "socket/ssl_server_socket_impl.h",
diff --git a/net/base/address_tracker_linux.cc b/net/base/address_tracker_linux.cc
index a42ede20..02bb379 100644
--- a/net/base/address_tracker_linux.cc
+++ b/net/base/address_tracker_linux.cc
@@ -118,7 +118,6 @@
       address_callback_(base::DoNothing()),
       link_callback_(base::DoNothing()),
       tunnel_callback_(base::DoNothing()),
-      netlink_fd_(-1),
       watcher_(FROM_HERE),
       ignored_interfaces_(),
       connection_type_initialized_(false),
@@ -136,7 +135,6 @@
       address_callback_(address_callback),
       link_callback_(link_callback),
       tunnel_callback_(tunnel_callback),
-      netlink_fd_(-1),
       watcher_(FROM_HERE),
       ignored_interfaces_(ignored_interfaces),
       connection_type_initialized_(false),
@@ -149,12 +147,12 @@
 }
 
 AddressTrackerLinux::~AddressTrackerLinux() {
-  CloseSocket();
+  watcher_.StopWatchingFileDescriptor();
 }
 
 void AddressTrackerLinux::Init() {
-  netlink_fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-  if (netlink_fd_ < 0) {
+  netlink_fd_.reset(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
+  if (!netlink_fd_.is_valid()) {
     PLOG(ERROR) << "Could not create NETLINK socket";
     AbortAndForceOnline();
     return;
@@ -171,8 +169,8 @@
     // http://crbug.com/113993
     addr.nl_groups =
         RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY | RTMGRP_LINK;
-    rv = bind(
-        netlink_fd_, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
+    rv = bind(netlink_fd_.get(), reinterpret_cast<struct sockaddr*>(&addr),
+              sizeof(addr));
     if (rv < 0) {
       PLOG(ERROR) << "Could not bind NETLINK socket";
       AbortAndForceOnline();
@@ -195,9 +193,9 @@
   request.header.nlmsg_pid = getpid();
   request.msg.rtgen_family = AF_UNSPEC;
 
-  rv = HANDLE_EINTR(sendto(netlink_fd_, &request, request.header.nlmsg_len,
-                           0, reinterpret_cast<struct sockaddr*>(&peer),
-                           sizeof(peer)));
+  rv = HANDLE_EINTR(
+      sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
+             reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
   if (rv < 0) {
     PLOG(ERROR) << "Could not send NETLINK request";
     AbortAndForceOnline();
@@ -214,9 +212,9 @@
   // Request dump of link state
   request.header.nlmsg_type = RTM_GETLINK;
 
-  rv = HANDLE_EINTR(sendto(netlink_fd_, &request, request.header.nlmsg_len, 0,
-                           reinterpret_cast<struct sockaddr*>(&peer),
-                           sizeof(peer)));
+  rv = HANDLE_EINTR(
+      sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
+             reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
   if (rv < 0) {
     PLOG(ERROR) << "Could not send NETLINK request";
     AbortAndForceOnline();
@@ -233,7 +231,8 @@
 
   if (tracking_) {
     rv = base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
-        netlink_fd_, true, base::MessagePumpForIO::WATCH_READ, &watcher_, this);
+        netlink_fd_.get(), true, base::MessagePumpForIO::WATCH_READ, &watcher_,
+        this);
     if (rv < 0) {
       PLOG(ERROR) << "Could not watch NETLINK socket";
       AbortAndForceOnline();
@@ -243,7 +242,8 @@
 }
 
 void AddressTrackerLinux::AbortAndForceOnline() {
-  CloseSocket();
+  watcher_.StopWatchingFileDescriptor();
+  netlink_fd_.reset();
   AddressTrackerAutoLock lock(*this, connection_type_lock_);
   current_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
   connection_type_initialized_ = true;
@@ -300,7 +300,7 @@
     }
 
     for (;;) {
-      int rv = HANDLE_EINTR(recv(netlink_fd_, buffer, sizeof(buffer),
+      int rv = HANDLE_EINTR(recv(netlink_fd_.get(), buffer, sizeof(buffer),
                                  // Block the first time through loop.
                                  first_loop ? 0 : MSG_DONTWAIT));
       first_loop = false;
@@ -425,7 +425,7 @@
 }
 
 void AddressTrackerLinux::OnFileCanReadWithoutBlocking(int fd) {
-  DCHECK_EQ(netlink_fd_, fd);
+  DCHECK_EQ(netlink_fd_.get(), fd);
   bool address_changed;
   bool link_changed;
   bool tunnel_changed;
@@ -440,12 +440,6 @@
 
 void AddressTrackerLinux::OnFileCanWriteWithoutBlocking(int /* fd */) {}
 
-void AddressTrackerLinux::CloseSocket() {
-  if (netlink_fd_ >= 0 && IGNORE_EINTR(close(netlink_fd_)) < 0)
-    PLOG(ERROR) << "Could not close NETLINK socket.";
-  netlink_fd_ = -1;
-}
-
 bool AddressTrackerLinux::IsTunnelInterface(int interface_index) const {
   char buf[IFNAMSIZ] = {0};
   return IsTunnelInterfaceName(get_interface_name_(interface_index, buf));
diff --git a/net/base/address_tracker_linux.h b/net/base/address_tracker_linux.h
index 66e82a6..0fd3f09 100644
--- a/net/base/address_tracker_linux.h
+++ b/net/base/address_tracker_linux.h
@@ -17,6 +17,7 @@
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/message_loop/message_pump_for_io.h"
 #include "base/synchronization/condition_variable.h"
@@ -132,9 +133,6 @@
   void OnFileCanReadWithoutBlocking(int fd) override;
   void OnFileCanWriteWithoutBlocking(int /* fd */) override;
 
-  // Close |netlink_fd_|
-  void CloseSocket();
-
   // Does |interface_index| refer to a tunnel interface?
   bool IsTunnelInterface(int interface_index) const;
 
@@ -157,7 +155,8 @@
   base::Closure link_callback_;
   base::Closure tunnel_callback_;
 
-  int netlink_fd_;
+  // Note that |watcher_| must be inactive when |netlink_fd_| is closed.
+  base::ScopedFD netlink_fd_;
   base::MessagePumpForIO::FdWatchController watcher_;
 
   mutable base::Lock address_map_lock_;
diff --git a/net/base/filename_util.cc b/net/base/filename_util.cc
index 5cbdeca..a2bfb499 100644
--- a/net/base/filename_util.cc
+++ b/net/base/filename_util.cc
@@ -124,7 +124,7 @@
 
 #if defined(OS_WIN)
   if (base::IsStringUTF8(path)) {
-    file_path_str.assign(base::UTF8ToWide(path));
+    file_path_str.assign(base::UTF8ToUTF16(path));
     // We used to try too hard and see if |path| made up entirely of
     // the 1st 256 characters in the Unicode was a zero-extended UTF-16.
     // If so, we converted it to 'Latin-1' and checked if the result was UTF-8.
@@ -136,7 +136,7 @@
     // are giving the conversion function a nonempty string, and it may fail if
     // the given string is not in the current encoding and give us an empty
     // string back. We detect this and report failure.
-    file_path_str = base::SysNativeMBToWide(path);
+    file_path_str = base::WideToUTF16(base::SysNativeMBToWide(path));
   }
 #else  // defined(OS_WIN)
   // Collapse multiple path slashes into a single path slash.
@@ -185,7 +185,7 @@
       "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2",  "lpt3",
       "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "clock$"};
 #if defined(OS_WIN)
-  std::string filename_lower = base::ToLowerASCII(base::WideToUTF8(filename));
+  std::string filename_lower = base::ToLowerASCII(base::UTF16ToUTF8(filename));
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   std::string filename_lower = base::ToLowerASCII(filename);
 #endif
diff --git a/net/base/filename_util_unittest.cc b/net/base/filename_util_unittest.cc
index ddd008f..4d592d9 100644
--- a/net/base/filename_util_unittest.cc
+++ b/net/base/filename_util_unittest.cc
@@ -35,16 +35,18 @@
 };
 
 // The expected filenames are coded as wchar_t for convenience.
+// TODO(https://crbug.com/911896): Make these char16_t once base::string16 is
+// std::u16string.
 std::wstring FilePathAsWString(const base::FilePath& path) {
 #if defined(OS_WIN)
-  return path.value();
+  return base::UTF16ToWide(path.value());
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   return base::UTF8ToWide(path.value());
 #endif
 }
 base::FilePath WStringAsFilePath(const std::wstring& str) {
 #if defined(OS_WIN)
-  return base::FilePath(str);
+  return base::FilePath(base::WideToUTF16(str));
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   return base::FilePath(base::WideToUTF8(str));
 #endif
@@ -305,8 +307,9 @@
 #if defined(OS_WIN)
     // On Windows, invalid UTF-8 bytes are interpreted using the default ANSI
     // code page. This defaults to Windows-1252 (which we assume here).
-    const wchar_t expected_output[] = L"D:\\Blah\\\u2026\u2122.doc";
-    EXPECT_EQ(std::wstring(expected_output), output.value());
+    const base::FilePath::CharType expected_output[] =
+        FILE_PATH_LITERAL("D:\\Blah\\\u2026\u2122.doc");
+    EXPECT_EQ(expected_output, output.value());
 #elif defined(OS_POSIX)
     // No conversion should happen, and the invalid UTF-8 should be preserved.
     const char expected_output[] = "/d:/Blah/\x85\x99.doc";
@@ -321,8 +324,9 @@
 #if defined(OS_WIN)
     // On Windows, invalid UTF-8 bytes are interpreted using the default ANSI
     // code page. This defaults to Windows-1252 (which we assume here).
-    const wchar_t expected_output[] = L"D:\\Blah\\\u2026\u2122.doc";
-    EXPECT_EQ(std::wstring(expected_output), output.value());
+    const base::FilePath::CharType expected_output[] =
+        FILE_PATH_LITERAL("D:\\Blah\\\u2026\u2122.doc");
+    EXPECT_EQ(expected_output, output.value());
 #elif defined(OS_POSIX)
     // No conversion should happen, and the invalid UTF-8 should be preserved.
     const char expected_output[] = "/d:/Blah/\x85\x99.doc";
@@ -380,7 +384,7 @@
   };
 
 #if defined(OS_WIN)
-  base::FilePath base_path(L"C:\\foo");
+  base::FilePath base_path(FILE_PATH_LITERAL("C:\\foo"));
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   base::FilePath base_path("/foo");
 #endif
diff --git a/net/base/network_change_notifier_fuchsia.cc b/net/base/network_change_notifier_fuchsia.cc
index a774f42..a8044df 100644
--- a/net/base/network_change_notifier_fuchsia.cc
+++ b/net/base/network_change_notifier_fuchsia.cc
@@ -52,7 +52,7 @@
   DCHECK(netstack_);
 
   netstack_.set_error_handler([](zx_status_t status) {
-    ZX_LOG(ERROR, status) << "Lost connection to netstack.";
+    ZX_LOG(FATAL, status) << "Lost connection to netstack.";
   });
   netstack_.events().OnInterfacesChanged =
       [this](std::vector<fuchsia::netstack::NetInterface> interfaces) {
diff --git a/net/base/platform_mime_util_win.cc b/net/base/platform_mime_util_win.cc
index 89b36ec..47f61827 100644
--- a/net/base/platform_mime_util_win.cc
+++ b/net/base/platform_mime_util_win.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/registry.h"
 
@@ -17,11 +18,11 @@
     const base::FilePath::StringType& ext, std::string* result) const {
   // check windows registry for file extension's mime type (registry key
   // names are not case-sensitive).
-  std::wstring value, key = L"." + ext;
-  base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).ReadValue(
-      L"Content Type", &value);
+  base::FilePath::StringType value, key = FILE_PATH_LITERAL(".") + ext;
+  base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ)
+      .ReadValue(STRING16_LITERAL("Content Type"), &value);
   if (!value.empty()) {
-    *result = base::WideToUTF8(value);
+    *result = base::UTF16ToUTF8(value);
     return true;
   }
   return false;
@@ -30,14 +31,15 @@
 bool PlatformMimeUtil::GetPlatformPreferredExtensionForMimeType(
     const std::string& mime_type,
     base::FilePath::StringType* ext) const {
-  std::wstring key(
-      L"MIME\\Database\\Content Type\\" + base::UTF8ToWide(mime_type));
-  if (base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).ReadValue(
-          L"Extension", ext) != ERROR_SUCCESS) {
+  base::FilePath::StringType key =
+      STRING16_LITERAL("MIME\\Database\\Content Type\\") +
+      base::UTF8ToUTF16(mime_type);
+  if (base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ)
+          .ReadValue(STRING16_LITERAL("Extension"), ext) != ERROR_SUCCESS) {
     return false;
   }
   // Strip off the leading dot, this should always be the case.
-  if (!ext->empty() && ext->at(0) == L'.')
+  if (!ext->empty() && ext->front() == '.')
     ext->erase(ext->begin());
 
   return true;
diff --git a/net/cert/cert_verify_proc_win.cc b/net/cert/cert_verify_proc_win.cc
index 272288d..af48f719 100644
--- a/net/cert/cert_verify_proc_win.cc
+++ b/net/cert/cert_verify_proc_win.cc
@@ -1113,8 +1113,7 @@
   // routine that has better support for RFC 6125 name matching.
   extra_policy_para.fdwChecks =
       0x00001000;  // SECURITY_FLAG_IGNORE_CERT_CN_INVALID
-  extra_policy_para.pwszServerName =
-      const_cast<base::char16*>(hostname16.c_str());
+  extra_policy_para.pwszServerName = base::wdata(hostname16);
 
   CERT_CHAIN_POLICY_PARA policy_para;
   memset(&policy_para, 0, sizeof(policy_para));
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 2f48171..40289d3f 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -3842,12 +3842,13 @@
 #if defined(OS_WIN)
   DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
   DWORD access = GENERIC_READ | GENERIC_WRITE;
-  base::win::ScopedHandle file2(CreateFile(
-      name.value().c_str(), access, sharing, NULL, OPEN_EXISTING, 0, NULL));
+  base::win::ScopedHandle file2(CreateFile(base::wdata(name.value()), access,
+                                           sharing, NULL, OPEN_EXISTING, 0,
+                                           NULL));
   EXPECT_FALSE(file2.IsValid());
 
   sharing |= FILE_SHARE_DELETE;
-  file2.Set(CreateFile(name.value().c_str(), access, sharing, NULL,
+  file2.Set(CreateFile(base::wdata(name.value()), access, sharing, NULL,
                        OPEN_EXISTING, 0, NULL));
   EXPECT_TRUE(file2.IsValid());
 #endif
diff --git a/net/disk_cache/blockfile/file_win.cc b/net/disk_cache/blockfile/file_win.cc
index 278e316..5fc5f59b 100644
--- a/net/disk_cache/blockfile/file_win.cc
+++ b/net/disk_cache/blockfile/file_win.cc
@@ -11,6 +11,7 @@
 #include "base/lazy_instance.h"
 #include "base/message_loop/message_loop_current.h"
 #include "base/message_loop/message_pump_for_io.h"
+#include "base/strings/string_util.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
 
@@ -115,7 +116,7 @@
   DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
   DWORD access = GENERIC_READ | GENERIC_WRITE | DELETE;
   base_file_ =
-      base::File(CreateFile(name.value().c_str(), access, sharing, NULL,
+      base::File(CreateFile(base::wdata(name.value()), access, sharing, NULL,
                             OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL));
 
   if (!base_file_.IsValid())
@@ -125,9 +126,9 @@
       base_file_.GetPlatformFile(), CompletionHandler::Get());
 
   init_ = true;
-  sync_base_file_  =
-    base::File(CreateFile(name.value().c_str(), access, sharing, NULL,
-                          OPEN_EXISTING, 0, NULL));
+  sync_base_file_ =
+      base::File(CreateFile(base::wdata(name.value()), access, sharing, NULL,
+                            OPEN_EXISTING, 0, NULL));
 
   if (!sync_base_file_.IsValid())
     return false;
diff --git a/net/disk_cache/cache_util_win.cc b/net/disk_cache/cache_util_win.cc
index 9d76069..408d34e 100644
--- a/net/disk_cache/cache_util_win.cc
+++ b/net/disk_cache/cache_util_win.cc
@@ -8,6 +8,7 @@
 
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/strings/string_util.h"
 #include "base/win/scoped_handle.h"
 
 namespace disk_cache {
@@ -15,7 +16,8 @@
 bool MoveCache(const base::FilePath& from_path, const base::FilePath& to_path) {
   // I don't want to use the shell version of move because if something goes
   // wrong, that version will attempt to move file by file and fail at the end.
-  if (!MoveFileEx(from_path.value().c_str(), to_path.value().c_str(), 0)) {
+  if (!MoveFileEx(base::wdata(from_path.value()), base::wdata(to_path.value()),
+                  0)) {
     LOG(ERROR) << "Unable to move the cache: " << GetLastError();
     return false;
   }
@@ -25,15 +27,16 @@
 bool DeleteCacheFile(const base::FilePath& name) {
   // We do a simple delete, without ever falling back to SHFileOperation, as the
   // version from base does.
-  if (!DeleteFile(name.value().c_str())) {
+  if (!DeleteFile(base::wdata(name.value()))) {
     // There is an error, but we share delete access so let's see if there is a
     // file to open. Note that this code assumes that we have a handle to the
     // file at all times (even now), so nobody can have a handle that prevents
     // us from opening the file again (unless it was deleted).
     DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
     DWORD access = SYNCHRONIZE;
-    base::win::ScopedHandle file(CreateFile(
-        name.value().c_str(), access, sharing, NULL, OPEN_EXISTING, 0, NULL));
+    base::win::ScopedHandle file(CreateFile(base::wdata(name.value()), access,
+                                            sharing, NULL, OPEN_EXISTING, 0,
+                                            NULL));
     if (file.IsValid())
       return false;
 
diff --git a/net/disk_cache/simple/simple_util_win.cc b/net/disk_cache/simple/simple_util_win.cc
index d296cb3..8707a551 100644
--- a/net/disk_cache/simple/simple_util_win.cc
+++ b/net/disk_cache/simple/simple_util_win.cc
@@ -9,6 +9,7 @@
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
 #include "base/rand_util.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "net/disk_cache/cache_util.h"
 
@@ -30,8 +31,8 @@
       path.DirName().AppendASCII(base::StringPrintf("todelete_%016" PRIx64,
                                                     base::RandUint64()));
 
-  bool rename_succeeded = !!MoveFile(path.value().c_str(),
-                                     rename_target.value().c_str());
+  bool rename_succeeded =
+      !!MoveFile(base::wdata(path.value()), base::wdata(rename_target.value()));
   if (rename_succeeded)
     return DeleteCacheFile(rename_target);
 
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index 400b7cce..27c576e 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -1020,13 +1020,7 @@
   EXPECT_FALSE(response0.complete());
 }
 
-#if defined(THREAD_SANITIZER)
-// Use of WorkerPool in HostResolverImpl causes a data race. crbug.com/334140
-#define MAYBE_NumericIPv4Address DISABLED_NumericIPv4Address
-#else
-#define MAYBE_NumericIPv4Address NumericIPv4Address
-#endif
-TEST_F(HostResolverImplTest, MAYBE_NumericIPv4Address) {
+TEST_F(HostResolverImplTest, NumericIPv4Address) {
   // Stevens says dotted quads with AI_UNSPEC resolve to a single sockaddr_in.
   Request* req = CreateRequest("127.1.2.3", 5555);
   EXPECT_THAT(req->Resolve(), IsOk());
@@ -1034,14 +1028,7 @@
   EXPECT_TRUE(req->HasOneAddress("127.1.2.3", 5555));
 }
 
-#if defined(THREAD_SANITIZER)
-// Use of WorkerPool in HostResolverImpl causes a data race. crbug.com/334140
-#define MAYBE_NumericIPv4Address_ResolveHost \
-  DISABLED_NumericIPv4Address_ResolveHost
-#else
-#define MAYBE_NumericIPv4Address_ResolveHost NumericIPv4Address_ResolveHost
-#endif
-TEST_F(HostResolverImplTest, MAYBE_NumericIPv4Address_ResolveHost) {
+TEST_F(HostResolverImplTest, NumericIPv4Address_ResolveHost) {
   ResolveHostResponseHelper response(resolver_->CreateRequest(
       HostPortPair("127.1.2.3", 5555), NetLogWithSource(), base::nullopt));
 
@@ -1050,13 +1037,7 @@
               testing::ElementsAre(CreateExpected("127.1.2.3", 5555)));
 }
 
-#if defined(THREAD_SANITIZER)
-// Use of WorkerPool in HostResolverImpl causes a data race. crbug.com/334140
-#define MAYBE_NumericIPv6Address DISABLED_NumericIPv6Address
-#else
-#define MAYBE_NumericIPv6Address NumericIPv6Address
-#endif
-TEST_F(HostResolverImplTest, MAYBE_NumericIPv6Address) {
+TEST_F(HostResolverImplTest, NumericIPv6Address) {
   // Resolve a plain IPv6 address.  Don't worry about [brackets], because
   // the caller should have removed them.
   Request* req = CreateRequest("2001:db8::1", 5555);
@@ -1065,14 +1046,7 @@
   EXPECT_TRUE(req->HasOneAddress("2001:db8::1", 5555));
 }
 
-#if defined(THREAD_SANITIZER)
-// Use of WorkerPool in HostResolverImpl causes a data race. crbug.com/334140
-#define MAYBE_NumericIPv6Address_ResolveHost \
-  DISABLED_NumericIPv6Address_ResolveHost
-#else
-#define MAYBE_NumericIPv6Address_ResolveHost NumericIPv6Address_ResolveHost
-#endif
-TEST_F(HostResolverImplTest, MAYBE_NumericIPv6Address_ResolveHost) {
+TEST_F(HostResolverImplTest, NumericIPv6Address_ResolveHost) {
   // Resolve a plain IPv6 address.  Don't worry about [brackets], because
   // the caller should have removed them.
   ResolveHostResponseHelper response(resolver_->CreateRequest(
@@ -1083,24 +1057,12 @@
               testing::ElementsAre(CreateExpected("2001:db8::1", 5555)));
 }
 
-#if defined(THREAD_SANITIZER)
-// Use of WorkerPool in HostResolverImpl causes a data race. crbug.com/334140
-#define MAYBE_EmptyHost DISABLED_EmptyHost
-#else
-#define MAYBE_EmptyHost EmptyHost
-#endif
-TEST_F(HostResolverImplTest, MAYBE_EmptyHost) {
+TEST_F(HostResolverImplTest, EmptyHost) {
   Request* req = CreateRequest(std::string(), 5555);
   EXPECT_THAT(req->Resolve(), IsError(ERR_NAME_NOT_RESOLVED));
 }
 
-#if defined(THREAD_SANITIZER)
-// Use of WorkerPool in HostResolverImpl causes a data race. crbug.com/334140
-#define MAYBE_EmptyHost_ResolveHost DISABLED_EmptyHost_ResolveHost
-#else
-#define MAYBE_EmptyHost_ResolveHost EmptyHost_ResolveHost
-#endif
-TEST_F(HostResolverImplTest, MAYBE_EmptyHost_ResolveHost) {
+TEST_F(HostResolverImplTest, EmptyHost_ResolveHost) {
   ResolveHostResponseHelper response(resolver_->CreateRequest(
       HostPortPair(std::string(), 5555), NetLogWithSource(), base::nullopt));
 
@@ -1108,32 +1070,14 @@
   EXPECT_FALSE(response.request()->GetAddressResults());
 }
 
-#if defined(THREAD_SANITIZER)
-// There's a data race in this test that may lead to use-after-free.
-// If the test starts to crash without ThreadSanitizer it needs to be disabled
-// globally. See http://crbug.com/268946 (stacks for this test in
-// crbug.com/333567).
-#define MAYBE_EmptyDotsHost DISABLED_EmptyDotsHost
-#else
-#define MAYBE_EmptyDotsHost EmptyDotsHost
-#endif
-TEST_F(HostResolverImplTest, MAYBE_EmptyDotsHost) {
+TEST_F(HostResolverImplTest, EmptyDotsHost) {
   for (int i = 0; i < 16; ++i) {
     Request* req = CreateRequest(std::string(i, '.'), 5555);
     EXPECT_THAT(req->Resolve(), IsError(ERR_NAME_NOT_RESOLVED));
   }
 }
 
-#if defined(THREAD_SANITIZER)
-// There's a data race in this test that may lead to use-after-free.
-// If the test starts to crash without ThreadSanitizer it needs to be disabled
-// globally. See http://crbug.com/268946 (stacks for this test in
-// crbug.com/333567).
-#define MAYBE_EmptyDotsHost_ResolveHost DISABLED_EmptyDotsHost_ResolveHost
-#else
-#define MAYBE_EmptyDotsHost_ResolveHost EmptyDotsHost_ResolveHost
-#endif
-TEST_F(HostResolverImplTest, MAYBE_EmptyDotsHost_ResolveHost) {
+TEST_F(HostResolverImplTest, EmptyDotsHost_ResolveHost) {
   for (int i = 0; i < 16; ++i) {
     ResolveHostResponseHelper response(
         resolver_->CreateRequest(HostPortPair(std::string(i, '.'), 5555),
@@ -1144,28 +1088,12 @@
   }
 }
 
-#if defined(THREAD_SANITIZER)
-// There's a data race in this test that may lead to use-after-free.
-// If the test starts to crash without ThreadSanitizer it needs to be disabled
-// globally. See http://crbug.com/268946.
-#define MAYBE_LongHost DISABLED_LongHost
-#else
-#define MAYBE_LongHost LongHost
-#endif
-TEST_F(HostResolverImplTest, MAYBE_LongHost) {
+TEST_F(HostResolverImplTest, LongHost) {
   Request* req = CreateRequest(std::string(4097, 'a'), 5555);
   EXPECT_THAT(req->Resolve(), IsError(ERR_NAME_NOT_RESOLVED));
 }
 
-#if defined(THREAD_SANITIZER)
-// There's a data race in this test that may lead to use-after-free.
-// If the test starts to crash without ThreadSanitizer it needs to be disabled
-// globally. See http://crbug.com/268946.
-#define MAYBE_LongHost_ResolveHost DISABLED_LongHost_ResolveHost
-#else
-#define MAYBE_LongHost_ResolveHost LongHost_ResolveHost
-#endif
-TEST_F(HostResolverImplTest, MAYBE_LongHost_ResolveHost) {
+TEST_F(HostResolverImplTest, LongHost_ResolveHost) {
   ResolveHostResponseHelper response(
       resolver_->CreateRequest(HostPortPair(std::string(4097, 'a'), 5555),
                                NetLogWithSource(), base::nullopt));
diff --git a/net/http/http_auth_sspi_win.cc b/net/http/http_auth_sspi_win.cc
index cfd8a874..4b105d3 100644
--- a/net/http/http_auth_sspi_win.cc
+++ b/net/http/http_auth_sspi_win.cc
@@ -55,14 +55,14 @@
                                CredHandle* cred) {
   SEC_WINNT_AUTH_IDENTITY identity;
   identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
-  identity.User =
-      reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(user.c_str()));
+  identity.User = reinterpret_cast<unsigned short*>(
+      const_cast<wchar_t*>(base::wdata(user)));
   identity.UserLength = user.size();
-  identity.Domain =
-      reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(domain.c_str()));
+  identity.Domain = reinterpret_cast<unsigned short*>(
+      const_cast<wchar_t*>(base::wdata(domain)));
   identity.DomainLength = domain.size();
-  identity.Password =
-      reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(password.c_str()));
+  identity.Password = reinterpret_cast<unsigned short*>(
+      const_cast<wchar_t*>(base::wdata(password)));
   identity.PasswordLength = password.size();
 
   TimeStamp expiry;
@@ -422,18 +422,18 @@
   DWORD context_attribute;
   base::string16 spn16 = base::ASCIIToUTF16(spn);
   SECURITY_STATUS status = library_->InitializeSecurityContext(
-      &cred_,                                    // phCredential
-      ctxt_ptr,                                  // phContext
-      const_cast<base::char16*>(spn16.c_str()),  // pszTargetName
-      context_flags,                             // fContextReq
-      0,                                         // Reserved1 (must be 0)
-      SECURITY_NATIVE_DREP,                      // TargetDataRep
-      in_buffer_desc_ptr,                        // pInput
-      0,                                         // Reserved2 (must be 0)
-      &ctxt_,                                    // phNewContext
-      &out_buffer_desc,                          // pOutput
-      &context_attribute,                        // pfContextAttr
-      nullptr);                                  // ptsExpiry
+      &cred_,                // phCredential
+      ctxt_ptr,              // phContext
+      base::wdata(spn16),    // pszTargetName
+      context_flags,         // fContextReq
+      0,                     // Reserved1 (must be 0)
+      SECURITY_NATIVE_DREP,  // TargetDataRep
+      in_buffer_desc_ptr,    // pInput
+      0,                     // Reserved2 (must be 0)
+      &ctxt_,                // phNewContext
+      &out_buffer_desc,      // pOutput
+      &context_attribute,    // pfContextAttr
+      nullptr);              // ptsExpiry
   int rv = MapInitializeSecurityContextStatusToError(status);
   if (rv != OK) {
     ResetSecurityContext();
diff --git a/net/http/http_auth_sspi_win_unittest.cc b/net/http/http_auth_sspi_win_unittest.cc
index 9b78718..33c796d 100644
--- a/net/http/http_auth_sspi_win_unittest.cc
+++ b/net/http/http_auth_sspi_win_unittest.cc
@@ -18,11 +18,11 @@
 
 namespace {
 
-void MatchDomainUserAfterSplit(const std::wstring& combined,
-                               const std::wstring& expected_domain,
-                               const std::wstring& expected_user) {
-  std::wstring actual_domain;
-  std::wstring actual_user;
+void MatchDomainUserAfterSplit(const base::string16& combined,
+                               const base::string16& expected_domain,
+                               const base::string16& expected_user) {
+  base::string16 actual_domain;
+  base::string16 actual_user;
   SplitDomainAndUser(combined, &actual_domain, &actual_user);
   EXPECT_EQ(expected_domain, actual_domain);
   EXPECT_EQ(expected_user, actual_user);
@@ -39,8 +39,10 @@
 }  // namespace
 
 TEST(HttpAuthSSPITest, SplitUserAndDomain) {
-  MatchDomainUserAfterSplit(L"foobar", L"", L"foobar");
-  MatchDomainUserAfterSplit(L"FOO\\bar", L"FOO", L"bar");
+  MatchDomainUserAfterSplit(STRING16_LITERAL("foobar"), STRING16_LITERAL(""),
+                            STRING16_LITERAL("foobar"));
+  MatchDomainUserAfterSplit(STRING16_LITERAL("FOO\\bar"),
+                            STRING16_LITERAL("FOO"), STRING16_LITERAL("bar"));
 }
 
 TEST(HttpAuthSSPITest, DetermineMaxTokenLength_Normal) {
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 75cd94d..0143fa39 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -125,8 +125,6 @@
       quic_migrate_sessions_on_network_change_v2(false),
       quic_migrate_sessions_early_v2(false),
       quic_retry_on_alternate_network_before_handshake(false),
-      quic_race_stale_dns_on_connection(false),
-      quic_go_away_on_path_degrading(false),
       quic_max_time_on_non_default_network(
           base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs)),
       quic_max_migrations_to_non_default_network_on_write_error(
@@ -135,6 +133,8 @@
           kMaxMigrationsToNonDefaultNetworkOnPathDegrading),
       quic_allow_server_migration(false),
       quic_allow_remote_alt_svc(true),
+      quic_race_stale_dns_on_connection(false),
+      quic_go_away_on_path_degrading(false),
       quic_disable_bidirectional_streams(false),
       quic_force_hol_blocking(false),
       quic_race_cert_verification(false),
@@ -225,12 +225,12 @@
           params.quic_migrate_sessions_on_network_change_v2,
           params.quic_migrate_sessions_early_v2,
           params.quic_retry_on_alternate_network_before_handshake,
-          params.quic_race_stale_dns_on_connection,
-          params.quic_go_away_on_path_degrading,
           params.quic_max_time_on_non_default_network,
           params.quic_max_migrations_to_non_default_network_on_write_error,
           params.quic_max_migrations_to_non_default_network_on_path_degrading,
           params.quic_allow_server_migration,
+          params.quic_race_stale_dns_on_connection,
+          params.quic_go_away_on_path_degrading,
           params.quic_race_cert_verification,
           params.quic_estimate_initial_rtt,
           params.quic_headers_include_h2_stream_dependency,
@@ -306,7 +306,7 @@
   return GetSocketPoolManager(pool_type)->GetTransportSocketPool();
 }
 
-SSLClientSocketPool* HttpNetworkSession::GetSSLSocketPool(
+TransportClientSocketPool* HttpNetworkSession::GetSSLSocketPool(
     SocketPoolType pool_type) {
   return GetSocketPoolManager(pool_type)->GetSSLSocketPool();
 }
@@ -325,7 +325,7 @@
       http_proxy);
 }
 
-SSLClientSocketPool* HttpNetworkSession::GetSocketPoolForSSLWithProxy(
+TransportClientSocketPool* HttpNetworkSession::GetSocketPoolForSSLWithProxy(
     SocketPoolType pool_type,
     const ProxyServer& proxy_server) {
   return GetSocketPoolManager(pool_type)->GetSocketPoolForSSLWithProxy(
@@ -387,10 +387,6 @@
                    params_.quic_migrate_sessions_early_v2);
   dict->SetBoolean("retry_on_alternate_network_before_handshake",
                    params_.quic_retry_on_alternate_network_before_handshake);
-  dict->SetBoolean("race_stale_dns_on_connection",
-                   params_.quic_race_stale_dns_on_connection);
-  dict->SetBoolean("go_away_on_path_degrading",
-                   params_.quic_go_away_on_path_degrading);
   dict->SetInteger("max_time_on_non_default_network_seconds",
                    params_.quic_max_time_on_non_default_network.InSeconds());
   dict->SetInteger(
@@ -401,6 +397,10 @@
       params_.quic_max_migrations_to_non_default_network_on_path_degrading);
   dict->SetBoolean("allow_server_migration",
                    params_.quic_allow_server_migration);
+  dict->SetBoolean("race_stale_dns_on_connection",
+                   params_.quic_race_stale_dns_on_connection);
+  dict->SetBoolean("go_away_on_path_degrading",
+                   params_.quic_go_away_on_path_degrading);
   dict->SetBoolean("estimate_initial_rtt", params_.quic_estimate_initial_rtt);
   dict->SetBoolean("force_hol_blocking", params_.quic_force_hol_blocking);
   dict->SetBoolean("server_push_cancellation",
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index e38e051b..20691e6 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -76,7 +76,6 @@
 class ReportingService;
 #endif
 class SocketPerformanceWatcherFactory;
-class SSLClientSocketPool;
 class SSLConfigService;
 class TransportClientSocketPool;
 class TransportSecurityState;
@@ -192,11 +191,6 @@
     // If true, a new connection may be kicked off on an alternate network when
     // a connection fails on the default network before handshake is confirmed.
     bool quic_retry_on_alternate_network_before_handshake;
-    // If true, the quic stream factory may race connection from stale dns
-    // result with the original dns resolution
-    bool quic_race_stale_dns_on_connection;
-    // If true, the quic session may mark itself as GOAWAY on path degrading.
-    bool quic_go_away_on_path_degrading;
     // Maximum time the session could be on the non-default network before
     // migrates back to default network. Defaults to
     // kMaxTimeOnNonDefaultNetwork.
@@ -213,6 +207,11 @@
     // If true, allows QUIC to use alternative services with a different
     // hostname from the origin.
     bool quic_allow_remote_alt_svc;
+    // If true, the quic stream factory may race connection from stale dns
+    // result with the original dns resolution
+    bool quic_race_stale_dns_on_connection;
+    // If true, the quic session may mark itself as GOAWAY on path degrading.
+    bool quic_go_away_on_path_degrading;
     // If true, bidirectional streams over QUIC will be disabled.
     bool quic_disable_bidirectional_streams;
     // If true, enable force HOL blocking.  For measurement purposes.
@@ -293,7 +292,7 @@
   void RemoveResponseDrainer(HttpResponseBodyDrainer* drainer);
 
   TransportClientSocketPool* GetTransportSocketPool(SocketPoolType pool_type);
-  SSLClientSocketPool* GetSSLSocketPool(SocketPoolType pool_type);
+  TransportClientSocketPool* GetSSLSocketPool(SocketPoolType pool_type);
   // Currently only works for SOCKS proxies.
   TransportClientSocketPool* GetSocketPoolForSOCKSProxy(
       SocketPoolType pool_type,
@@ -301,7 +300,7 @@
   HttpProxyClientSocketPool* GetSocketPoolForHTTPLikeProxy(
       SocketPoolType pool_type,
       const ProxyServer& http_proxy);
-  SSLClientSocketPool* GetSocketPoolForSSLWithProxy(
+  TransportClientSocketPool* GetSocketPoolForSSLWithProxy(
       SocketPoolType pool_type,
       const ProxyServer& proxy_server);
 
diff --git a/net/http/http_network_session_peer.cc b/net/http/http_network_session_peer.cc
index 4841c5e2..96d69753 100644
--- a/net/http/http_network_session_peer.cc
+++ b/net/http/http_network_session_peer.cc
@@ -7,7 +7,6 @@
 #include "net/http/http_proxy_client_socket_pool.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/socket/client_socket_pool_manager.h"
-#include "net/socket/ssl_client_socket_pool.h"
 #include "net/socket/transport_client_socket_pool.h"
 
 namespace net {
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 521d4ed5..e545204 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -685,8 +685,6 @@
 CaptureGroupNameTransportSocketPool;
 typedef CaptureGroupNameSocketPool<HttpProxyClientSocketPool>
 CaptureGroupNameHttpProxySocketPool;
-typedef CaptureGroupNameSocketPool<SSLClientSocketPool>
-CaptureGroupNameSSLSocketPool;
 
 template <typename ParentPool>
 CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool(
@@ -714,26 +712,6 @@
     CertVerifier* /* cert_verifier */)
     : HttpProxyClientSocketPool(0, 0, NULL, NULL, NULL, NULL, NULL) {}
 
-template <>
-CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
-    HostResolver* /* host_resolver */,
-    CertVerifier* cert_verifier)
-    : SSLClientSocketPool(0,
-                          0,
-                          cert_verifier,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL) {}
-
 //-----------------------------------------------------------------------------
 
 // Helper functions for validating that AuthChallengeInfo's are correctly
@@ -11080,8 +11058,8 @@
     HttpNetworkSessionPeer peer(session.get());
     CaptureGroupNameTransportSocketPool* transport_conn_pool =
         new CaptureGroupNameTransportSocketPool(nullptr, nullptr);
-    CaptureGroupNameSSLSocketPool* ssl_conn_pool =
-        new CaptureGroupNameSSLSocketPool(nullptr, nullptr);
+    CaptureGroupNameTransportSocketPool* ssl_conn_pool =
+        new CaptureGroupNameTransportSocketPool(nullptr, nullptr);
     auto mock_pool_manager = std::make_unique<MockClientSocketPoolManager>();
     mock_pool_manager->SetTransportSocketPool(transport_conn_pool);
     mock_pool_manager->SetSSLSocketPool(ssl_conn_pool);
@@ -11141,8 +11119,8 @@
                              HostPortPair("http_proxy", 80));
     CaptureGroupNameHttpProxySocketPool* http_proxy_pool =
         new CaptureGroupNameHttpProxySocketPool(NULL, NULL);
-    CaptureGroupNameSSLSocketPool* ssl_conn_pool =
-        new CaptureGroupNameSSLSocketPool(NULL, NULL);
+    CaptureGroupNameTransportSocketPool* ssl_conn_pool =
+        new CaptureGroupNameTransportSocketPool(NULL, NULL);
     auto mock_pool_manager = std::make_unique<MockClientSocketPoolManager>();
     mock_pool_manager->SetSocketPoolForHTTPProxy(
         proxy_server, base::WrapUnique(http_proxy_pool));
@@ -11213,8 +11191,8 @@
     ASSERT_TRUE(proxy_server.is_valid());
     CaptureGroupNameTransportSocketPool* socks_conn_pool =
         new CaptureGroupNameTransportSocketPool(NULL, NULL);
-    CaptureGroupNameSSLSocketPool* ssl_conn_pool =
-        new CaptureGroupNameSSLSocketPool(NULL, NULL);
+    CaptureGroupNameTransportSocketPool* ssl_conn_pool =
+        new CaptureGroupNameTransportSocketPool(NULL, NULL);
     auto mock_pool_manager = std::make_unique<MockClientSocketPoolManager>();
     mock_pool_manager->SetSocketPoolForProxy(proxy_server,
                                              base::WrapUnique(socks_conn_pool));
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc
index 2b3b908..3a5e170 100644
--- a/net/http/http_proxy_client_socket_pool.cc
+++ b/net/http/http_proxy_client_socket_pool.cc
@@ -31,7 +31,7 @@
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/client_socket_pool_base.h"
 #include "net/socket/ssl_client_socket.h"
-#include "net/socket/ssl_client_socket_pool.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/spdy/spdy_proxy_client_socket.h"
@@ -176,7 +176,7 @@
     const scoped_refptr<HttpProxySocketParams>& params,
     ProxyDelegate* proxy_delegate,
     TransportClientSocketPool* transport_pool,
-    SSLClientSocketPool* ssl_pool,
+    TransportClientSocketPool* ssl_pool,
     NetworkQualityEstimator* network_quality_estimator,
     Delegate* delegate,
     NetLog* net_log)
@@ -308,7 +308,7 @@
 HttpProxyClientSocketPool::HttpProxyConnectJobFactory::
     HttpProxyConnectJobFactory(
         TransportClientSocketPool* transport_pool,
-        SSLClientSocketPool* ssl_pool,
+        TransportClientSocketPool* ssl_pool,
         ProxyDelegate* proxy_delegate,
         NetworkQualityEstimator* network_quality_estimator,
         NetLog* net_log)
@@ -334,7 +334,7 @@
     int max_sockets,
     int max_sockets_per_group,
     TransportClientSocketPool* transport_pool,
-    SSLClientSocketPool* ssl_pool,
+    TransportClientSocketPool* ssl_pool,
     ProxyDelegate* proxy_delegate,
     NetworkQualityEstimator* network_quality_estimator,
     NetLog* net_log)
diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h
index a3af462..1e43b8e 100644
--- a/net/http/http_proxy_client_socket_pool.h
+++ b/net/http/http_proxy_client_socket_pool.h
@@ -35,7 +35,6 @@
 class NetworkQualityEstimator;
 class ProxyDelegate;
 class QuicStreamFactory;
-class SSLClientSocketPool;
 class SSLSocketParams;
 class SpdySessionPool;
 class TransportClientSocketPool;
@@ -119,7 +118,7 @@
                       const scoped_refptr<HttpProxySocketParams>& params,
                       ProxyDelegate* proxy_delegate,
                       TransportClientSocketPool* transport_pool,
-                      SSLClientSocketPool* ssl_pool,
+                      TransportClientSocketPool* ssl_pool,
                       NetworkQualityEstimator* network_quality_estimator,
                       Delegate* delegate,
                       NetLog* net_log);
@@ -172,7 +171,7 @@
   HttpProxyClientSocketPool(int max_sockets,
                             int max_sockets_per_group,
                             TransportClientSocketPool* transport_pool,
-                            SSLClientSocketPool* ssl_pool,
+                            TransportClientSocketPool* ssl_pool,
                             ProxyDelegate* proxy_delegate,
                             NetworkQualityEstimator* network_quality_estimator,
                             NetLog* net_log);
@@ -244,7 +243,7 @@
    public:
     HttpProxyConnectJobFactory(
         TransportClientSocketPool* transport_pool,
-        SSLClientSocketPool* ssl_pool,
+        TransportClientSocketPool* ssl_pool,
         ProxyDelegate* proxy_delegate,
         NetworkQualityEstimator* network_quality_estimator,
         NetLog* net_log);
@@ -260,7 +259,7 @@
                              ProxyPoolTimeoutWithConnectionProperty);
 
     TransportClientSocketPool* const transport_pool_;
-    SSLClientSocketPool* const ssl_pool_;
+    TransportClientSocketPool* const ssl_pool_;
     ProxyDelegate* const proxy_delegate_;
     NetworkQualityEstimator* const network_quality_estimator_;
 
@@ -270,7 +269,7 @@
   };
 
   TransportClientSocketPool* const transport_pool_;
-  SSLClientSocketPool* const ssl_pool_;
+  TransportClientSocketPool* const ssl_pool_;
   PoolBase base_;
 
   DISALLOW_COPY_AND_ASSIGN(HttpProxyClientSocketPool);
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index 31b97cb..64ddf53 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -32,6 +32,7 @@
 #include "net/socket/socket_tag.h"
 #include "net/socket/socket_test_util.h"
 #include "net/socket/socks_connect_job.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/spdy/spdy_test_util_common.h"
@@ -89,19 +90,22 @@
                                nullptr /* net_log */),
         ssl_socket_pool_(kMaxSockets,
                          kMaxSocketsPerGroup,
-                         session_deps_.cert_verifier.get(),
-                         NULL /* channel_id_store */,
-                         NULL /* transport_security_state */,
-                         NULL /* cert_transparency_verifier */,
-                         NULL /* ct_policy_enforcer */,
-                         NULL /* ssl_client_session_cache */,
                          &socket_factory_,
-                         &transport_socket_pool_,
-                         NULL /* socks_pool */,
-                         NULL /* http_proxy_pool */,
+                         session_deps_.host_resolver.get(),
+                         session_deps_.cert_verifier.get(),
+                         session_deps_.channel_id_service.get(),
+                         session_deps_.transport_security_state.get(),
+                         session_deps_.cert_transparency_verifier.get(),
+                         session_deps_.ct_policy_enforcer.get(),
+                         nullptr /* ssl_client_session_cache */,
+                         std::string() /* ssl_session_cache_shard */,
                          session_deps_.ssl_config_service.get(),
-                         NULL /* network_quality_estimator */,
-                         NetLogWithSource().net_log()),
+                         nullptr /* socket_performance_watcher_factory */,
+                         nullptr /* network_quality_estimator */,
+                         nullptr /* net_log */,
+                         &transport_socket_pool_,
+                         nullptr /* socks_pool */,
+                         nullptr /* http_proxy_pool */),
         field_trial_list_(nullptr),
         pool_(
             std::make_unique<HttpProxyClientSocketPool>(kMaxSockets,
@@ -247,7 +251,7 @@
   TransportClientSocketPool* transport_socket_pool() {
     return &transport_socket_pool_;
   }
-  SSLClientSocketPool* ssl_socket_pool() { return &ssl_socket_pool_; }
+  TransportClientSocketPool* ssl_socket_pool() { return &ssl_socket_pool_; }
 
   base::TimeDelta GetProxyConnectionTimeout() {
     // Doesn't actually matter whether or not this is for a tunnel - the
@@ -264,7 +268,7 @@
   TestNetworkQualityEstimator estimator_;
 
   TransportClientSocketPool transport_socket_pool_;
-  SSLClientSocketPool ssl_socket_pool_;
+  TransportClientSocketPool ssl_socket_pool_;
 
   std::unique_ptr<HttpNetworkSession> session_;
 
diff --git a/net/http/http_proxy_client_socket_wrapper.cc b/net/http/http_proxy_client_socket_wrapper.cc
index dcc9c6a..64af2ee 100644
--- a/net/http/http_proxy_client_socket_wrapper.cc
+++ b/net/http/http_proxy_client_socket_wrapper.cc
@@ -23,6 +23,7 @@
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/socket_tag.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/spdy/spdy_proxy_client_socket.h"
@@ -43,7 +44,7 @@
     base::TimeDelta connect_timeout_duration,
     base::TimeDelta proxy_negotiation_timeout_duration,
     TransportClientSocketPool* transport_pool,
-    SSLClientSocketPool* ssl_pool,
+    TransportClientSocketPool* ssl_pool,
     const scoped_refptr<TransportSocketParams>& transport_params,
     const scoped_refptr<SSLSocketParams>& ssl_params,
     quic::QuicTransportVersion quic_version,
@@ -557,7 +558,10 @@
   next_state_ = STATE_SSL_CONNECT_COMPLETE;
   transport_socket_handle_.reset(new ClientSocketHandle());
   return transport_socket_handle_->Init(
-      group_name_, ssl_params_, priority_, initial_socket_tag_, respect_limits_,
+      group_name_,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          ssl_params_),
+      priority_, initial_socket_tag_, respect_limits_,
       base::Bind(&HttpProxyClientSocketWrapper::OnIOComplete,
                  base::Unretained(this)),
       ssl_pool_, net_log_);
diff --git a/net/http/http_proxy_client_socket_wrapper.h b/net/http/http_proxy_client_socket_wrapper.h
index a28efa3..e2ad59f 100644
--- a/net/http/http_proxy_client_socket_wrapper.h
+++ b/net/http/http_proxy_client_socket_wrapper.h
@@ -25,7 +25,6 @@
 #include "net/quic/quic_stream_factory.h"
 #include "net/socket/next_proto.h"
 #include "net/socket/ssl_client_socket.h"
-#include "net/socket/ssl_client_socket_pool.h"
 #include "net/spdy/spdy_session.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
@@ -39,7 +38,7 @@
 class IOBuffer;
 class ProxyDelegate;
 class SpdySessionPool;
-class SSLClientSocketPool;
+class SSLSocketParams;
 class TransportClientSocketPool;
 class TransportSocketParams;
 
@@ -65,7 +64,7 @@
       base::TimeDelta connect_timeout_duration,
       base::TimeDelta proxy_negotiation_timeout_duration,
       TransportClientSocketPool* transport_pool,
-      SSLClientSocketPool* ssl_pool,
+      TransportClientSocketPool* ssl_pool,
       const scoped_refptr<TransportSocketParams>& transport_params,
       const scoped_refptr<SSLSocketParams>& ssl_params,
       quic::QuicTransportVersion quic_version,
@@ -198,7 +197,7 @@
   const base::TimeDelta proxy_negotiation_timeout_duration_;
 
   TransportClientSocketPool* const transport_pool_;
-  SSLClientSocketPool* const ssl_pool_;
+  TransportClientSocketPool* const ssl_pool_;
   const scoped_refptr<TransportSocketParams> transport_params_;
   const scoped_refptr<SSLSocketParams> ssl_params_;
 
diff --git a/net/http/http_proxy_client_socket_wrapper_unittest.cc b/net/http/http_proxy_client_socket_wrapper_unittest.cc
index cb09248..2fccc2d 100644
--- a/net/http/http_proxy_client_socket_wrapper_unittest.cc
+++ b/net/http/http_proxy_client_socket_wrapper_unittest.cc
@@ -23,6 +23,7 @@
 #include "net/socket/socket_tag.h"
 #include "net/socket/socket_test_util.h"
 #include "net/socket/socks_connect_job.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
@@ -143,14 +144,13 @@
         /*migrate_sessions_on_network_change_v2=*/false,
         /*migrate_sessions_early_v2=*/false,
         /*retry_on_alternate_network_before_handshake=*/false,
-        /*race_stale_dns_on_connection=*/false,
-        /*go_away_on_path_degrading=*/false,
         base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
         kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
-        allow_server_migration_, race_cert_verification_, estimate_initial_rtt_,
-        client_headers_include_h2_stream_dependency_, connection_options_,
-        client_connection_options_,
+        allow_server_migration_, /*race_stale_dns_on_connection=*/false,
+        /*go_away_on_path_degrading=*/false, race_cert_verification_,
+        estimate_initial_rtt_, client_headers_include_h2_stream_dependency_,
+        connection_options_, client_connection_options_,
         /*enable_socket_recv_optimization=*/false));
   }
 
diff --git a/net/http/http_stream_factory_job.cc b/net/http/http_stream_factory_job.cc
index 6dbe6287..c949feb 100644
--- a/net/http/http_stream_factory_job.cc
+++ b/net/http/http_stream_factory_job.cc
@@ -46,7 +46,6 @@
 #include "net/socket/client_socket_pool.h"
 #include "net/socket/client_socket_pool_manager.h"
 #include "net/socket/ssl_client_socket.h"
-#include "net/socket/ssl_client_socket_pool.h"
 #include "net/socket/stream_socket.h"
 #include "net/spdy/bidirectional_stream_spdy_impl.h"
 #include "net/spdy/http2_push_promise_index.h"
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index 97bb46d..8488072 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -52,6 +52,7 @@
 #include "net/socket/socket_tag.h"
 #include "net/socket/socket_test_util.h"
 #include "net/socket/socks_connect_job.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/spdy/spdy_session.h"
 #include "net/spdy/spdy_session_pool.h"
@@ -448,8 +449,6 @@
     CapturePreconnectsTransportSocketPool;
 typedef CapturePreconnectsSocketPool<HttpProxyClientSocketPool>
     CapturePreconnectsHttpProxySocketPool;
-typedef CapturePreconnectsSocketPool<SSLClientSocketPool>
-    CapturePreconnectsSSLSocketPool;
 
 template <typename ParentPool>
 CapturePreconnectsSocketPool<ParentPool>::CapturePreconnectsSocketPool(
@@ -491,30 +490,6 @@
                                 nullptr),
       last_num_streams_(-1) {}
 
-template <>
-CapturePreconnectsSSLSocketPool::CapturePreconnectsSocketPool(
-    HostResolver* /* host_resolver */,
-    CertVerifier* cert_verifier,
-    TransportSecurityState* transport_security_state,
-    CTVerifier* cert_transparency_verifier,
-    CTPolicyEnforcer* ct_policy_enforcer)
-    : SSLClientSocketPool(0,
-                          0,
-                          cert_verifier,
-                          nullptr,  // channel_id_store
-                          transport_security_state,
-                          cert_transparency_verifier,
-                          ct_policy_enforcer,
-                          nullptr,   // ssl_client_session_cache
-                          nullptr,   // deterministic_socket_factory
-                          nullptr,   // transport_socket_pool
-                          nullptr,   // socks_pool
-                          nullptr,   // http_proxy_pool
-                          nullptr,   // ssl_config_service
-                          nullptr,   // network_quality_estimator
-                          nullptr),  // net_log
-      last_num_streams_(-1) {}
-
 using HttpStreamFactoryTest = TestWithScopedTaskEnvironment;
 
 TEST_F(HttpStreamFactoryTest, PreconnectDirect) {
@@ -530,8 +505,8 @@
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
             session_deps.ct_policy_enforcer.get());
-    CapturePreconnectsSSLSocketPool* ssl_conn_pool =
-        new CapturePreconnectsSSLSocketPool(
+    CapturePreconnectsTransportSocketPool* ssl_conn_pool =
+        new CapturePreconnectsTransportSocketPool(
             session_deps.host_resolver.get(), session_deps.cert_verifier.get(),
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
@@ -563,8 +538,8 @@
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
             session_deps.ct_policy_enforcer.get());
-    CapturePreconnectsSSLSocketPool* ssl_conn_pool =
-        new CapturePreconnectsSSLSocketPool(
+    CapturePreconnectsTransportSocketPool* ssl_conn_pool =
+        new CapturePreconnectsTransportSocketPool(
             session_deps.host_resolver.get(), session_deps.cert_verifier.get(),
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
@@ -598,8 +573,8 @@
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
             session_deps.ct_policy_enforcer.get());
-    CapturePreconnectsSSLSocketPool* ssl_conn_pool =
-        new CapturePreconnectsSSLSocketPool(
+    CapturePreconnectsTransportSocketPool* ssl_conn_pool =
+        new CapturePreconnectsTransportSocketPool(
             session_deps.host_resolver.get(), session_deps.cert_verifier.get(),
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
@@ -639,8 +614,8 @@
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
             session_deps.ct_policy_enforcer.get());
-    CapturePreconnectsSSLSocketPool* ssl_conn_pool =
-        new CapturePreconnectsSSLSocketPool(
+    CapturePreconnectsTransportSocketPool* ssl_conn_pool =
+        new CapturePreconnectsTransportSocketPool(
             session_deps.host_resolver.get(), session_deps.cert_verifier.get(),
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
@@ -1227,8 +1202,8 @@
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
             session_deps.ct_policy_enforcer.get());
-    CapturePreconnectsSSLSocketPool* ssl_conn_pool =
-        new CapturePreconnectsSSLSocketPool(
+    CapturePreconnectsTransportSocketPool* ssl_conn_pool =
+        new CapturePreconnectsTransportSocketPool(
             session_deps.host_resolver.get(), session_deps.cert_verifier.get(),
             session_deps.transport_security_state.get(),
             session_deps.cert_transparency_verifier.get(),
@@ -1288,8 +1263,8 @@
                 session_deps.transport_security_state.get(),
                 session_deps.cert_transparency_verifier.get(),
                 session_deps.ct_policy_enforcer.get());
-        CapturePreconnectsSSLSocketPool* ssl_conn_pool =
-            new CapturePreconnectsSSLSocketPool(
+        CapturePreconnectsTransportSocketPool* ssl_conn_pool =
+            new CapturePreconnectsTransportSocketPool(
                 session_deps.host_resolver.get(),
                 session_deps.cert_verifier.get(),
                 session_deps.transport_security_state.get(),
@@ -1381,8 +1356,8 @@
           session_deps.transport_security_state.get(),
           session_deps.cert_transparency_verifier.get(),
           session_deps.ct_policy_enforcer.get());
-  CapturePreconnectsSSLSocketPool* ssl_conn_pool =
-      new CapturePreconnectsSSLSocketPool(
+  CapturePreconnectsTransportSocketPool* ssl_conn_pool =
+      new CapturePreconnectsTransportSocketPool(
           session_deps.host_resolver.get(), session_deps.cert_verifier.get(),
           session_deps.transport_security_state.get(),
           session_deps.cert_transparency_verifier.get(),
@@ -1548,7 +1523,7 @@
 
   std::unique_ptr<HttpNetworkSession> session(
       SpdySessionDependencies::SpdyCreateSession(&session_deps));
-  SSLClientSocketPool* ssl_pool =
+  TransportClientSocketPool* ssl_pool =
       session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL);
 
   EXPECT_EQ(GetSocketPoolGroupCount(ssl_pool), 0);
@@ -2212,8 +2187,11 @@
                             ssl_config, PRIVACY_MODE_DISABLED));
     std::string group_name = "ssl/" + host_port_pair.ToString();
     int rv = connection->Init(
-        group_name, ssl_params, MEDIUM, SocketTag(),
-        ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
+        group_name,
+        TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+            ssl_params),
+        MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
+        callback.callback(),
         session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL),
         NetLogWithSource());
     rv = callback.GetResult(rv);
diff --git a/net/http/url_security_manager_win.cc b/net/http/url_security_manager_win.cc
index cafdba41..b4b50e43 100644
--- a/net/http/url_security_manager_win.cc
+++ b/net/http/url_security_manager_win.cc
@@ -55,11 +55,9 @@
   base::string16 url16 = base::ASCIIToUTF16(auth_origin.spec());
   DWORD policy = 0;
   HRESULT hr;
-  hr = security_manager_->ProcessUrlAction(url16.c_str(),
-                                           URLACTION_CREDENTIALS_USE,
-                                           reinterpret_cast<BYTE*>(&policy),
-                                           sizeof(policy), NULL, 0,
-                                           PUAF_NOUI, 0);
+  hr = security_manager_->ProcessUrlAction(
+      base::wdata(url16), URLACTION_CREDENTIALS_USE,
+      reinterpret_cast<BYTE*>(&policy), sizeof(policy), NULL, 0, PUAF_NOUI, 0);
   if (FAILED(hr)) {
     LOG(ERROR) << "IInternetSecurityManager::ProcessUrlAction failed: " << hr;
     return false;
@@ -83,7 +81,7 @@
       // URLZONE_INTERNET      3
       // URLZONE_UNTRUSTED     4
       DWORD zone = 0;
-      hr = security_manager_->MapUrlToZone(url16.c_str(), &zone, 0);
+      hr = security_manager_->MapUrlToZone(base::wdata(url16), &zone, 0);
       if (FAILED(hr)) {
         LOG(ERROR) << "IInternetSecurityManager::MapUrlToZone failed: " << hr;
         return false;
diff --git a/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win_unittest.cc b/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win_unittest.cc
index 353d3976..cdc39aa 100644
--- a/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win_unittest.cc
+++ b/net/proxy_resolution/dhcp_pac_file_adapter_fetcher_win_unittest.cc
@@ -182,7 +182,7 @@
   client.WaitForResult(ERR_PAC_NOT_IN_DHCP);
   ASSERT_TRUE(client.fetcher_->DidFinish());
   EXPECT_THAT(client.fetcher_->GetResult(), IsError(ERR_PAC_NOT_IN_DHCP));
-  EXPECT_EQ(base::string16(L""), client.fetcher_->GetPacScript());
+  EXPECT_EQ(base::string16(), client.fetcher_->GetPacScript());
 }
 
 TEST(DhcpPacFileAdapterFetcher, NormalCaseURLInDhcp) {
@@ -193,7 +193,8 @@
   client.WaitForResult(OK);
   ASSERT_TRUE(client.fetcher_->DidFinish());
   EXPECT_THAT(client.fetcher_->GetResult(), IsOk());
-  EXPECT_EQ(base::string16(L"bingo"), client.fetcher_->GetPacScript());
+  EXPECT_EQ(base::string16(STRING16_LITERAL("bingo")),
+            client.fetcher_->GetPacScript());
   EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL());
 }
 
@@ -218,7 +219,7 @@
 
   ASSERT_TRUE(client.fetcher_->DidFinish());
   EXPECT_THAT(client.fetcher_->GetResult(), IsError(ERR_TIMED_OUT));
-  EXPECT_EQ(base::string16(L""), client.fetcher_->GetPacScript());
+  EXPECT_EQ(base::string16(), client.fetcher_->GetPacScript());
   EXPECT_EQ(GURL(), client.fetcher_->GetPacURL());
   client.FinishTestAllowCleanup();
 }
@@ -233,7 +234,7 @@
   ASSERT_FALSE(client.fetcher_->DidFinish());
   ASSERT_TRUE(client.fetcher_->WasCancelled());
   EXPECT_THAT(client.fetcher_->GetResult(), IsError(ERR_ABORTED));
-  EXPECT_EQ(base::string16(L""), client.fetcher_->GetPacScript());
+  EXPECT_EQ(base::string16(), client.fetcher_->GetPacScript());
   EXPECT_EQ(GURL(), client.fetcher_->GetPacURL());
   client.FinishTestAllowCleanup();
 }
@@ -256,7 +257,7 @@
   ASSERT_FALSE(client.fetcher_->DidFinish());
   ASSERT_TRUE(client.fetcher_->WasCancelled());
   EXPECT_THAT(client.fetcher_->GetResult(), IsError(ERR_ABORTED));
-  EXPECT_EQ(base::string16(L""), client.fetcher_->GetPacScript());
+  EXPECT_EQ(base::string16(), client.fetcher_->GetPacScript());
   // GetPacURL() still returns the URL fetched in this case.
   EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL());
   client.FinishTestAllowCleanup();
@@ -273,7 +274,8 @@
   // are identical expectations to the NormalCaseURLInDhcp test.
   ASSERT_TRUE(client.fetcher_->DidFinish());
   EXPECT_THAT(client.fetcher_->GetResult(), IsOk());
-  EXPECT_EQ(base::string16(L"bingo"), client.fetcher_->GetPacScript());
+  EXPECT_EQ(base::string16(STRING16_LITERAL("bingo")),
+            client.fetcher_->GetPacScript());
   EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL());
   client.FinishTestAllowCleanup();
 }
@@ -318,7 +320,7 @@
   client.WaitForResult(OK);
   ASSERT_TRUE(client.fetcher_->DidFinish());
   EXPECT_THAT(client.fetcher_->GetResult(), IsOk());
-  EXPECT_EQ(base::string16(L"-downloadable.pac-\n"),
+  EXPECT_EQ(base::string16(STRING16_LITERAL("-downloadable.pac-\n")),
             client.fetcher_->GetPacScript());
   EXPECT_EQ(configured_url,
             client.fetcher_->GetPacURL());
diff --git a/net/proxy_resolution/dhcp_pac_file_fetcher_win_unittest.cc b/net/proxy_resolution/dhcp_pac_file_fetcher_win_unittest.cc
index 7ea2182..b47d84b 100644
--- a/net/proxy_resolution/dhcp_pac_file_fetcher_win_unittest.cc
+++ b/net/proxy_resolution/dhcp_pac_file_fetcher_win_unittest.cc
@@ -217,7 +217,7 @@
       : DhcpPacFileAdapterFetcher(context, runner),
         did_finish_(false),
         result_(OK),
-        pac_script_(L"bingo"),
+        pac_script_(STRING16_LITERAL("bingo")),
         fetch_delay_ms_(1) {}
 
   void Fetch(const std::string& adapter_name,
@@ -424,7 +424,7 @@
   void ResetTestState() {
     finished_ = false;
     result_ = ERR_UNEXPECTED;
-    pac_text_ = L"";
+    pac_text_.clear();
     fetcher_.ResetTestState();
   }
 
@@ -445,12 +445,12 @@
   TestURLRequestContext context;
   std::unique_ptr<DummyDhcpPacFileAdapterFetcher> adapter_fetcher(
       new DummyDhcpPacFileAdapterFetcher(&context, client->GetTaskRunner()));
-  adapter_fetcher->Configure(true, OK, L"bingo", 1);
+  adapter_fetcher->Configure(true, OK, STRING16_LITERAL("bingo"), 1);
   client->fetcher_.PushBackAdapter("a", adapter_fetcher.release());
   client->RunTest();
   client->RunMessageLoopUntilComplete();
   ASSERT_THAT(client->result_, IsOk());
-  ASSERT_EQ(L"bingo", client->pac_text_);
+  ASSERT_EQ(STRING16_LITERAL("bingo"), client->pac_text_);
 }
 
 TEST(DhcpPacFileFetcherWin, NormalCaseURLConfiguredOneAdapter) {
@@ -462,16 +462,18 @@
 
 void TestNormalCaseURLConfiguredMultipleAdapters(FetcherClient* client) {
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "most_preferred", true, ERR_PAC_NOT_IN_DHCP, L"",
+      "most_preferred", true, ERR_PAC_NOT_IN_DHCP, base::string16(),
       base::TimeDelta::FromMilliseconds(1));
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "second", true, OK, L"bingo", base::TimeDelta::FromMilliseconds(50));
+      "second", true, OK, STRING16_LITERAL("bingo"),
+      base::TimeDelta::FromMilliseconds(50));
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "third", true, OK, L"rocko", base::TimeDelta::FromMilliseconds(1));
+      "third", true, OK, STRING16_LITERAL("rocko"),
+      base::TimeDelta::FromMilliseconds(1));
   client->RunTest();
   client->RunMessageLoopUntilComplete();
   ASSERT_THAT(client->result_, IsOk());
-  ASSERT_EQ(L"bingo", client->pac_text_);
+  ASSERT_EQ(STRING16_LITERAL("bingo"), client->pac_text_);
 }
 
 TEST(DhcpPacFileFetcherWin, NormalCaseURLConfiguredMultipleAdapters) {
@@ -484,18 +486,19 @@
 void TestNormalCaseURLConfiguredMultipleAdaptersWithTimeout(
     FetcherClient* client) {
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "most_preferred", true, ERR_PAC_NOT_IN_DHCP, L"",
+      "most_preferred", true, ERR_PAC_NOT_IN_DHCP, base::string16(),
       base::TimeDelta::FromMilliseconds(1));
   // This will time out.
+  client->fetcher_.ConfigureAndPushBackAdapter("second", false, ERR_IO_PENDING,
+                                               STRING16_LITERAL("bingo"),
+                                               TestTimeouts::action_timeout());
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "second", false, ERR_IO_PENDING, L"bingo",
-      TestTimeouts::action_timeout());
-  client->fetcher_.ConfigureAndPushBackAdapter(
-      "third", true, OK, L"rocko", base::TimeDelta::FromMilliseconds(1));
+      "third", true, OK, STRING16_LITERAL("rocko"),
+      base::TimeDelta::FromMilliseconds(1));
   client->RunTest();
   client->RunMessageLoopUntilComplete();
   ASSERT_THAT(client->result_, IsOk());
-  ASSERT_EQ(L"rocko", client->pac_text_);
+  ASSERT_EQ(STRING16_LITERAL("rocko"), client->pac_text_);
 }
 
 TEST(DhcpPacFileFetcherWin,
@@ -509,24 +512,24 @@
 void TestFailureCaseURLConfiguredMultipleAdaptersWithTimeout(
     FetcherClient* client) {
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "most_preferred", true, ERR_PAC_NOT_IN_DHCP, L"",
+      "most_preferred", true, ERR_PAC_NOT_IN_DHCP, base::string16(),
       base::TimeDelta::FromMilliseconds(1));
   // This will time out.
-  client->fetcher_.ConfigureAndPushBackAdapter(
-      "second", false, ERR_IO_PENDING, L"bingo",
-      TestTimeouts::action_timeout());
+  client->fetcher_.ConfigureAndPushBackAdapter("second", false, ERR_IO_PENDING,
+                                               STRING16_LITERAL("bingo"),
+                                               TestTimeouts::action_timeout());
   // This is the first non-ERR_PAC_NOT_IN_DHCP error and as such
   // should be chosen.
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "third", true, ERR_PAC_STATUS_NOT_OK, L"",
+      "third", true, ERR_PAC_STATUS_NOT_OK, base::string16(),
       base::TimeDelta::FromMilliseconds(1));
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "fourth", true, ERR_NOT_IMPLEMENTED, L"",
+      "fourth", true, ERR_NOT_IMPLEMENTED, base::string16(),
       base::TimeDelta::FromMilliseconds(1));
   client->RunTest();
   client->RunMessageLoopUntilComplete();
   ASSERT_THAT(client->result_, IsError(ERR_PAC_STATUS_NOT_OK));
-  ASSERT_EQ(L"", client->pac_text_);
+  ASSERT_EQ(base::string16(), client->pac_text_);
 }
 
 TEST(DhcpPacFileFetcherWin,
@@ -539,21 +542,21 @@
 
 void TestFailureCaseNoURLConfigured(FetcherClient* client) {
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "most_preferred", true, ERR_PAC_NOT_IN_DHCP, L"",
+      "most_preferred", true, ERR_PAC_NOT_IN_DHCP, base::string16(),
       base::TimeDelta::FromMilliseconds(1));
   // This will time out.
-  client->fetcher_.ConfigureAndPushBackAdapter(
-      "second", false, ERR_IO_PENDING, L"bingo",
-      TestTimeouts::action_timeout());
+  client->fetcher_.ConfigureAndPushBackAdapter("second", false, ERR_IO_PENDING,
+                                               STRING16_LITERAL("bingo"),
+                                               TestTimeouts::action_timeout());
   // This is the first non-ERR_PAC_NOT_IN_DHCP error and as such
   // should be chosen.
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "third", true, ERR_PAC_NOT_IN_DHCP, L"",
+      "third", true, ERR_PAC_NOT_IN_DHCP, base::string16(),
       base::TimeDelta::FromMilliseconds(1));
   client->RunTest();
   client->RunMessageLoopUntilComplete();
   ASSERT_THAT(client->result_, IsError(ERR_PAC_NOT_IN_DHCP));
-  ASSERT_EQ(L"", client->pac_text_);
+  ASSERT_EQ(base::string16(), client->pac_text_);
 }
 
 TEST(DhcpPacFileFetcherWin, FailureCaseNoURLConfigured) {
@@ -567,7 +570,7 @@
   client->RunTest();
   client->RunMessageLoopUntilComplete();
   ASSERT_THAT(client->result_, IsError(ERR_PAC_NOT_IN_DHCP));
-  ASSERT_EQ(L"", client->pac_text_);
+  ASSERT_EQ(base::string16(), client->pac_text_);
   ASSERT_EQ(0, client->fetcher_.num_fetchers_created_);
 }
 
@@ -584,13 +587,14 @@
   // time.  Verify that we complete quickly and do not wait for the slow
   // adapters, i.e. we finish before timeout.
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "1", true, ERR_PAC_NOT_IN_DHCP, L"",
+      "1", true, ERR_PAC_NOT_IN_DHCP, base::string16(),
       base::TimeDelta::FromMilliseconds(1));
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "2", true, OK, L"bingo",
+      "2", true, OK, STRING16_LITERAL("bingo"),
       base::TimeDelta::FromMilliseconds(1));
   client->fetcher_.ConfigureAndPushBackAdapter(
-      "3", true, OK, L"wrongo", TestTimeouts::action_max_timeout());
+      "3", true, OK, STRING16_LITERAL("wrongo"),
+      TestTimeouts::action_max_timeout());
 
   // Increase the timeout to ensure the short circuit mechanism has
   // time to kick in before the timeout waiting for more adapters kicks in.
@@ -619,7 +623,7 @@
   TestURLRequestContext context;
   std::unique_ptr<DummyDhcpPacFileAdapterFetcher> adapter_fetcher(
       new DummyDhcpPacFileAdapterFetcher(&context, client->GetTaskRunner()));
-  adapter_fetcher->Configure(true, OK, L"bingo", 1);
+  adapter_fetcher->Configure(true, OK, STRING16_LITERAL("bingo"), 1);
   client->fetcher_.PushBackAdapter("a", adapter_fetcher.release());
   client->RunTest();
   client->fetcher_.Cancel();
@@ -680,7 +684,7 @@
   TestURLRequestContext context;
   std::unique_ptr<DummyDhcpPacFileAdapterFetcher> adapter_fetcher(
       new DummyDhcpPacFileAdapterFetcher(&context, client.GetTaskRunner()));
-  adapter_fetcher->Configure(true, OK, L"bingo", 1);
+  adapter_fetcher->Configure(true, OK, STRING16_LITERAL("bingo"), 1);
   client.fetcher_.PushBackAdapter("a", adapter_fetcher.release());
   client.RunTest();
 
diff --git a/net/proxy_resolution/proxy_config_service_win.cc b/net/proxy_resolution/proxy_config_service_win.cc
index b14abc7a..e729fca 100644
--- a/net/proxy_resolution/proxy_config_service_win.cc
+++ b/net/proxy_resolution/proxy_config_service_win.cc
@@ -78,20 +78,21 @@
 
   AddKeyToWatchList(
       HKEY_CURRENT_USER,
-      L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+      STRING16_LITERAL("Software\\Microsoft\\Windows\\CurrentVersion\\")
+          STRING16_LITERAL("Internet Settings"));
 
   AddKeyToWatchList(
       HKEY_LOCAL_MACHINE,
-      L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+      STRING16_LITERAL("Software\\Microsoft\\Windows\\CurrentVersion\\")
+          STRING16_LITERAL("Internet Settings"));
 
-  AddKeyToWatchList(
-      HKEY_LOCAL_MACHINE,
-      L"SOFTWARE\\Policies\\Microsoft\\Windows\\CurrentVersion\\"
-      L"Internet Settings");
+  AddKeyToWatchList(HKEY_LOCAL_MACHINE,
+                    STRING16_LITERAL("SOFTWARE\\Policies\\Microsoft\\Windows\\")
+                        STRING16_LITERAL("CurrentVersion\\Internet Settings"));
 }
 
 bool ProxyConfigServiceWin::AddKeyToWatchList(HKEY rootkey,
-                                              const wchar_t* subkey) {
+                                              const base::char16* subkey) {
   std::unique_ptr<base::win::RegKey> key =
       std::make_unique<base::win::RegKey>();
   if (key->Create(rootkey, subkey, KEY_NOTIFY) != ERROR_SUCCESS)
@@ -153,10 +154,10 @@
     // lpszProxy may be a single proxy, or a proxy per scheme. The format
     // is compatible with ProxyConfig::ProxyRules's string format.
     config->proxy_rules().ParseFromString(
-        base::UTF16ToASCII(ie_config.lpszProxy));
+        base::WideToUTF8(ie_config.lpszProxy));
   }
   if (ie_config.lpszProxyBypass) {
-    std::string proxy_bypass = base::UTF16ToASCII(ie_config.lpszProxyBypass);
+    std::string proxy_bypass = base::WideToUTF8(ie_config.lpszProxyBypass);
 
     base::StringTokenizer proxy_server_bypass_list(proxy_bypass, ";, \t\n\r");
     while (proxy_server_bypass_list.GetNext()) {
@@ -165,7 +166,8 @@
     }
   }
   if (ie_config.lpszAutoConfigUrl)
-    config->set_pac_url(GURL(ie_config.lpszAutoConfigUrl));
+    config->set_pac_url(
+        GURL(base::CastToStringPiece16(ie_config.lpszAutoConfigUrl)));
 }
 
 }  // namespace net
diff --git a/net/proxy_resolution/proxy_config_service_win.h b/net/proxy_resolution/proxy_config_service_win.h
index cd050a6..aa3df2f7 100644
--- a/net/proxy_resolution/proxy_config_service_win.h
+++ b/net/proxy_resolution/proxy_config_service_win.h
@@ -13,6 +13,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
+#include "base/strings/string16.h"
 #include "net/base/net_export.h"
 #include "net/proxy_resolution/polling_proxy_config_service.h"
 #include "net/proxy_resolution/proxy_config_with_annotation.h"
@@ -64,7 +65,7 @@
 
   // Creates a new key and appends it to |keys_to_watch_|. If the key fails to
   // be created, it is not appended to the list and we return false.
-  bool AddKeyToWatchList(HKEY rootkey, const wchar_t* subkey);
+  bool AddKeyToWatchList(HKEY rootkey, const base::char16* subkey);
 
   // This is called whenever one of the registry keys we are watching change.
   void OnObjectSignaled(base::win::RegKey* key);
diff --git a/net/proxy_resolution/proxy_resolver_winhttp.cc b/net/proxy_resolution/proxy_resolver_winhttp.cc
index ccd4815..9963822 100644
--- a/net/proxy_resolution/proxy_resolver_winhttp.cc
+++ b/net/proxy_resolution/proxy_resolver_winhttp.cc
@@ -118,7 +118,7 @@
   options.fAutoLogonIfChallenged = FALSE;
   options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
   base::string16 pac_url16 = base::ASCIIToUTF16(pac_url_.spec());
-  options.lpszAutoConfigUrl = pac_url16.c_str();
+  options.lpszAutoConfigUrl = base::wdata(pac_url16);
 
   WINHTTP_PROXY_INFO info = {0};
   DCHECK(session_handle_);
@@ -129,14 +129,16 @@
   // get good performance in the case where WinHTTP uses an out-of-process
   // resolver.  This is important for Vista and Win2k3.
   BOOL ok = WinHttpGetProxyForUrl(
-      session_handle_, base::ASCIIToUTF16(mutable_query_url.spec()).c_str(),
-      &options, &info);
+      session_handle_,
+      base::wdata(base::ASCIIToUTF16(mutable_query_url.spec())), &options,
+      &info);
   if (!ok) {
     if (ERROR_WINHTTP_LOGIN_FAILURE == GetLastError()) {
       options.fAutoLogonIfChallenged = TRUE;
       ok = WinHttpGetProxyForUrl(
-          session_handle_, base::ASCIIToUTF16(mutable_query_url.spec()).c_str(),
-          &options, &info);
+          session_handle_,
+          base::wdata(base::ASCIIToUTF16(mutable_query_url.spec())), &options,
+          &info);
     }
     if (!ok) {
       DWORD error = GetLastError();
@@ -171,7 +173,7 @@
       // things like "foopy1:80;foopy2:80". It strips out the non-HTTP
       // proxy types, and stops the list when PAC encounters a "DIRECT".
       // So UseNamedProxy() should work OK.
-      results->UseNamedProxy(base::UTF16ToASCII(info.lpszProxy));
+      results->UseNamedProxy(base::WideToUTF8(info.lpszProxy));
       break;
     default:
       NOTREACHED();
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc
index 119c7e7..1273e78 100644
--- a/net/quic/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc
@@ -512,7 +512,6 @@
                        PRIVACY_MODE_DISABLED, SocketTag()),
         /*require_confirmation=*/false, /*migrate_session_early_v2=*/false,
         /*migrate_session_on_network_change_v2=*/false,
-        /*go_away_on_path_degrading*/ false,
         /*default_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
         base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
@@ -520,6 +519,7 @@
         kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
+        /*go_away_on_path_degrading*/ false,
         client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0,
         quic::test::DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN",
         dns_start, dns_end, &push_promise_index_, nullptr,
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index 07c9b45..e97387d 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -682,13 +682,13 @@
     bool require_confirmation,
     bool migrate_session_early_v2,
     bool migrate_sessions_on_network_change_v2,
-    bool go_away_on_path_degrading,
     NetworkChangeNotifier::NetworkHandle default_network,
     base::TimeDelta max_time_on_non_default_network,
     int max_migrations_to_non_default_network_on_write_error,
     int max_migrations_to_non_default_network_on_path_degrading,
     int yield_after_packets,
     quic::QuicTime::Delta yield_after_duration,
+    bool go_away_on_path_degrading,
     bool headers_include_h2_stream_dependency,
     int cert_verify_flags,
     const quic::QuicConfig& config,
@@ -710,7 +710,6 @@
       migrate_session_early_v2_(migrate_session_early_v2),
       migrate_session_on_network_change_v2_(
           migrate_sessions_on_network_change_v2),
-      go_away_on_path_degrading_(go_away_on_path_degrading),
       max_time_on_non_default_network_(max_time_on_non_default_network),
       max_migrations_to_non_default_network_on_write_error_(
           max_migrations_to_non_default_network_on_write_error),
@@ -721,6 +720,7 @@
       clock_(clock),
       yield_after_packets_(yield_after_packets),
       yield_after_duration_(yield_after_duration),
+      go_away_on_path_degrading_(go_away_on_path_degrading),
       most_recent_path_degrading_timestamp_(base::TimeTicks()),
       most_recent_network_disconnected_timestamp_(base::TimeTicks()),
       most_recent_write_error_(0),
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index 65020a6..d45d7d29 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -374,13 +374,13 @@
       bool require_confirmation,
       bool migrate_sesion_early_v2,
       bool migrate_session_on_network_change_v2,
-      bool go_away_on_path_degrading,
       NetworkChangeNotifier::NetworkHandle default_network,
       base::TimeDelta max_time_on_non_default_network,
       int max_migrations_to_non_default_network_on_write_error,
       int max_migrations_to_non_default_network_on_path_degrading,
       int yield_after_packets,
       quic::QuicTime::Delta yield_after_duration,
+      bool go_away_on_path_degrading,
       bool headers_include_h2_stream_dependency,
       int cert_verify_flags,
       const quic::QuicConfig& config,
@@ -745,7 +745,6 @@
   bool require_confirmation_;
   bool migrate_session_early_v2_;
   bool migrate_session_on_network_change_v2_;
-  bool go_away_on_path_degrading_;
   base::TimeDelta max_time_on_non_default_network_;
   // Maximum allowed number of migrations to non-default network triggered by
   // packet write error per default network.
@@ -758,6 +757,7 @@
   quic::QuicClock* clock_;  // Unowned.
   int yield_after_packets_;
   quic::QuicTime::Delta yield_after_duration_;
+  bool go_away_on_path_degrading_;
 
   base::TimeTicks most_recent_path_degrading_timestamp_;
   base::TimeTicks most_recent_network_disconnected_timestamp_;
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc
index ca867a76..751ac41 100644
--- a/net/quic/quic_chromium_client_session_test.cc
+++ b/net/quic/quic_chromium_client_session_test.cc
@@ -161,7 +161,6 @@
         base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)), session_key_,
         /*require_confirmation=*/false, migrate_session_early_v2_,
         /*migrate_session_on_network_change_v2=*/false,
-        /*go_away_on_path_degrading*/ false,
         /*defaulet_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
         base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
@@ -169,7 +168,8 @@
         kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
-        /*cert_verify_flags=*/0, client_headers_include_h2_stream_dependency_,
+        /*cert_verify_flags=*/0, /*go_away_on_path_degrading*/ false,
+        client_headers_include_h2_stream_dependency_,
         quic::test::DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN",
         base::TimeTicks::Now(), base::TimeTicks::Now(), &push_promise_index_,
         &test_push_delegate_, base::ThreadTaskRunnerHandle::Get().get(),
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 5b8049b3..8a0e7f0f 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -322,7 +322,6 @@
                        PRIVACY_MODE_DISABLED, SocketTag()),
         /*require_confirmation=*/false, /*migrate_session_early_v2=*/false,
         /*migrate_session_on_network_change_v2=*/false,
-        /*go_away_on_path_degrading*/ false,
         /*default_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
         base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
@@ -330,6 +329,7 @@
         kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
+        /*go_away_on_path_degrading*/ false,
         client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0,
         quic::test::DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN",
         dns_start, dns_end, &push_promise_index_, nullptr,
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc
index 05fe846..5c6df3f 100644
--- a/net/quic/quic_proxy_client_socket_unittest.cc
+++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -210,7 +210,6 @@
                        SocketTag()),
         /*require_confirmation=*/false, /*migrate_session_early_v2=*/false,
         /*migrate_session_on_network_change_v2=*/false,
-        /*go_away_on_path_degrading*/ false,
         /*default_network=*/NetworkChangeNotifier::kInvalidNetworkHandle,
         base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
@@ -218,6 +217,7 @@
         kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
+        /*go_away_on_path_degrading*/ false,
         client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0,
         quic::test::DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN",
         dns_start, dns_end, &push_promise_index_, nullptr,
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 30c740b..7214cd9 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -995,12 +995,12 @@
     bool migrate_sessions_on_network_change_v2,
     bool migrate_sessions_early_v2,
     bool retry_on_alternate_network_before_handshake,
-    bool race_stale_dns_on_connection,
-    bool go_away_on_path_degrading,
     base::TimeDelta max_time_on_non_default_network,
     int max_migrations_to_non_default_network_on_write_error,
     int max_migrations_to_non_default_network_on_path_degrading,
     bool allow_server_migration,
+    bool race_stale_dns_on_connection,
+    bool go_away_on_path_degrading,
     bool race_cert_verification,
     bool estimate_initial_rtt,
     bool headers_include_h2_stream_dependency,
@@ -1052,8 +1052,6 @@
       retry_on_alternate_network_before_handshake_(
           retry_on_alternate_network_before_handshake &&
           migrate_sessions_on_network_change_v2_),
-      race_stale_dns_on_connection_(race_stale_dns_on_connection),
-      go_away_on_path_degrading_(go_away_on_path_degrading),
       default_network_(NetworkChangeNotifier::kInvalidNetworkHandle),
       max_time_on_non_default_network_(max_time_on_non_default_network),
       max_migrations_to_non_default_network_on_write_error_(
@@ -1061,6 +1059,8 @@
       max_migrations_to_non_default_network_on_path_degrading_(
           max_migrations_to_non_default_network_on_path_degrading),
       allow_server_migration_(allow_server_migration),
+      race_stale_dns_on_connection_(race_stale_dns_on_connection),
+      go_away_on_path_degrading_(go_away_on_path_degrading),
       race_cert_verification_(race_cert_verification),
       estimate_initial_rtt(estimate_initial_rtt),
       headers_include_h2_stream_dependency_(
@@ -1804,11 +1804,10 @@
       clock_, transport_security_state_, ssl_config_service_,
       std::move(server_info), key.session_key(), require_confirmation,
       migrate_sessions_early_v2_, migrate_sessions_on_network_change_v2_,
-      go_away_on_path_degrading_, default_network_,
-      max_time_on_non_default_network_,
+      default_network_, max_time_on_non_default_network_,
       max_migrations_to_non_default_network_on_write_error_,
       max_migrations_to_non_default_network_on_path_degrading_,
-      yield_after_packets_, yield_after_duration_,
+      yield_after_packets_, yield_after_duration_, go_away_on_path_degrading_,
       headers_include_h2_stream_dependency_, cert_verify_flags, config,
       &crypto_config_, network_connection_.connection_description(),
       dns_resolution_start_time, dns_resolution_end_time, &push_promise_index_,
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 53703e9..3086bafc 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -251,12 +251,12 @@
       bool migrate_sessions_on_network_change_v2,
       bool migrate_sessions_early_v2,
       bool retry_on_alternate_network_before_handshake,
-      bool race_stale_dns_on_connection,
-      bool go_away_on_path_degrading,
       base::TimeDelta max_time_on_non_default_network,
       int max_migrations_to_non_default_network_on_write_error,
       int max_migrations_to_non_default_network_on_path_degrading,
       bool allow_server_migration,
+      bool race_stale_dns_on_connection,
+      bool go_away_on_path_degrading,
       bool race_cert_verification,
       bool estimate_initial_rtt,
       bool headers_include_h2_stream_dependency,
@@ -546,14 +546,6 @@
   // connection fails on the default network before handshake is confirmed.
   const bool retry_on_alternate_network_before_handshake_;
 
-  // Set if stale DNS result may be speculatively used to connect and then
-  // compared with the original DNS result.
-  const bool race_stale_dns_on_connection_;
-
-  // Set if client should mark the session as GOAWAY when the connection
-  // experiences poor connectivity
-  const bool go_away_on_path_degrading_;
-
   // If |migrate_sessions_early_v2_| is true, tracks the current default
   // network, and is updated OnNetworkMadeDefault.
   // Otherwise, always set to NetworkChangeNotifier::kInvalidNetwork.
@@ -573,6 +565,14 @@
   // server address.
   const bool allow_server_migration_;
 
+  // Set if stale DNS result may be speculatively used to connect and then
+  // compared with the original DNS result.
+  const bool race_stale_dns_on_connection_;
+
+  // Set if client should mark the session as GOAWAY when the connection
+  // experiences poor connectivity
+  const bool go_away_on_path_degrading_;
+
   // Set if cert verification is to be raced with host resolution.
   bool race_cert_verification_;
 
diff --git a/net/quic/quic_stream_factory_fuzzer.cc b/net/quic/quic_stream_factory_fuzzer.cc
index 5be455ff..ff326cd 100644
--- a/net/quic/quic_stream_factory_fuzzer.cc
+++ b/net/quic/quic_stream_factory_fuzzer.cc
@@ -138,13 +138,14 @@
           quic::kMaxTimeForCryptoHandshakeSecs, quic::kInitialIdleTimeoutSecs,
           migrate_sessions_on_network_change_v2, migrate_sessions_early_v2,
           retry_on_alternate_network_before_handshake,
-          race_stale_dns_on_connection, go_away_on_path_degrading,
           base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
           kMaxMigrationsToNonDefaultNetworkOnWriteError,
           kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
-          allow_server_migration, race_cert_verification, estimate_initial_rtt,
-          headers_include_h2_stream_dependency, env->connection_options,
-          env->client_connection_options, enable_socket_recv_optimization);
+          allow_server_migration, race_stale_dns_on_connection,
+          go_away_on_path_degrading, race_cert_verification,
+          estimate_initial_rtt, headers_include_h2_stream_dependency,
+          env->connection_options, env->client_connection_options,
+          enable_socket_recv_optimization);
 
   QuicStreamRequest request(factory.get());
   TestCompletionCallback callback;
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 72ca1eb7..3dde527e 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -293,13 +293,13 @@
         max_idle_time_before_crypto_handshake_seconds_,
         migrate_sessions_on_network_change_v2_, migrate_sessions_early_v2_,
         retry_on_alternate_network_before_handshake_,
-        race_stale_dns_on_connection_, go_away_on_path_degrading_,
         base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs),
         kMaxMigrationsToNonDefaultNetworkOnWriteError,
         kMaxMigrationsToNonDefaultNetworkOnPathDegrading,
-        allow_server_migration_, race_cert_verification_, estimate_initial_rtt_,
-        client_headers_include_h2_stream_dependency_, connection_options_,
-        client_connection_options_,
+        allow_server_migration_, race_stale_dns_on_connection_,
+        go_away_on_path_degrading_, race_cert_verification_,
+        estimate_initial_rtt_, client_headers_include_h2_stream_dependency_,
+        connection_options_, client_connection_options_,
         /*enable_socket_recv_optimization*/ false));
   }
 
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
index f3d7c48..c0f628c 100644
--- a/net/socket/client_socket_pool_manager.cc
+++ b/net/socket/client_socket_pool_manager.cc
@@ -18,7 +18,7 @@
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/client_socket_pool.h"
 #include "net/socket/socks_connect_job.h"
-#include "net/socket/ssl_client_socket_pool.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/ssl/ssl_config.h"
@@ -197,7 +197,7 @@
     scoped_refptr<SSLSocketParams> ssl_params = new SSLSocketParams(
         ssl_tcp_params, socks_params, http_proxy_params, origin_host_port,
         ssl_config_for_origin, privacy_mode);
-    SSLClientSocketPool* ssl_pool = NULL;
+    TransportClientSocketPool* ssl_pool = nullptr;
     if (proxy_info.is_direct()) {
       ssl_pool = session->GetSSLSocketPool(socket_pool_type);
     } else {
@@ -206,14 +206,20 @@
     }
 
     if (num_preconnect_streams) {
-      RequestSocketsForPool(ssl_pool, connection_group, ssl_params,
-                            num_preconnect_streams, net_log);
+      RequestSocketsForPool(
+          ssl_pool, connection_group,
+          TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+              ssl_params),
+          num_preconnect_streams, net_log);
       return OK;
     }
 
-    return socket_handle->Init(connection_group, ssl_params, request_priority,
-                               socket_tag, respect_limits, std::move(callback),
-                               ssl_pool, net_log);
+    return socket_handle->Init(
+        connection_group,
+        TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+            ssl_params),
+        request_priority, socket_tag, respect_limits, std::move(callback),
+        ssl_pool, net_log);
   }
 
   // Finally, get the connection started.
diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h
index 23c9f88..b65dcaa 100644
--- a/net/socket/client_socket_pool_manager.h
+++ b/net/socket/client_socket_pool_manager.h
@@ -37,7 +37,6 @@
 class ProxyInfo;
 class ProxyServer;
 class TransportClientSocketPool;
-class SSLClientSocketPool;
 
 struct SSLConfig;
 
@@ -79,14 +78,14 @@
   virtual void FlushSocketPoolsWithError(int error) = 0;
   virtual void CloseIdleSockets() = 0;
   virtual TransportClientSocketPool* GetTransportSocketPool() = 0;
-  virtual SSLClientSocketPool* GetSSLSocketPool() = 0;
+  virtual TransportClientSocketPool* GetSSLSocketPool() = 0;
   virtual TransportClientSocketPool* GetSocketPoolForSOCKSProxy(
       const ProxyServer& socks_proxy) = 0;
   // Returns the HttpProxyClientSocketPool for a ProxyServer that uses an
   // "HTTP-like" scheme, as defined by ProxyServer::is_http_like().
   virtual HttpProxyClientSocketPool* GetSocketPoolForHTTPLikeProxy(
       const ProxyServer& http_proxy) = 0;
-  virtual SSLClientSocketPool* GetSocketPoolForSSLWithProxy(
+  virtual TransportClientSocketPool* GetSocketPoolForSSLWithProxy(
       const ProxyServer& proxy_server) = 0;
   // Creates a Value summary of the state of the socket pools.
   virtual std::unique_ptr<base::Value> SocketPoolInfoToValue() const = 0;
diff --git a/net/socket/client_socket_pool_manager_impl.cc b/net/socket/client_socket_pool_manager_impl.cc
index b8bb1a7..b9801a7 100644
--- a/net/socket/client_socket_pool_manager_impl.cc
+++ b/net/socket/client_socket_pool_manager_impl.cc
@@ -13,7 +13,7 @@
 #include "net/http/http_network_session.h"
 #include "net/http/http_proxy_client_socket_pool.h"
 #include "net/socket/socks_connect_job.h"
-#include "net/socket/ssl_client_socket_pool.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/socket/websocket_transport_client_socket_pool.h"
@@ -103,21 +103,23 @@
                                        socket_performance_watcher_factory_,
                                        network_quality_estimator,
                                        net_log)),
-      ssl_socket_pool_(new SSLClientSocketPool(max_sockets_per_pool(pool_type),
-                                               max_sockets_per_group(pool_type),
-                                               cert_verifier,
-                                               channel_id_service,
-                                               transport_security_state,
-                                               cert_transparency_verifier,
-                                               ct_policy_enforcer,
-                                               ssl_client_session_cache,
-                                               socket_factory,
-                                               transport_socket_pool_.get(),
-                                               nullptr /* no socks proxy */,
-                                               nullptr /* no http proxy */,
-                                               ssl_config_service,
-                                               network_quality_estimator,
-                                               net_log)) {
+      ssl_socket_pool_(
+          new TransportClientSocketPool(max_sockets_per_pool(pool_type),
+                                        max_sockets_per_group(pool_type),
+                                        socket_factory_,
+                                        host_resolver,
+                                        cert_verifier,
+                                        channel_id_service,
+                                        transport_security_state,
+                                        cert_transparency_verifier,
+                                        ct_policy_enforcer,
+                                        ssl_client_session_cache,
+                                        ssl_session_cache_shard_,
+                                        ssl_config_service,
+                                        socket_performance_watcher_factory_,
+                                        network_quality_estimator,
+                                        net_log,
+                                        transport_socket_pool_.get())) {
   CertDatabase::GetInstance()->AddObserver(this);
 }
 
@@ -194,7 +196,7 @@
   return transport_socket_pool_.get();
 }
 
-SSLClientSocketPool* ClientSocketPoolManagerImpl::GetSSLSocketPool() {
+TransportClientSocketPool* ClientSocketPoolManagerImpl::GetSSLSocketPool() {
   return ssl_socket_pool_.get();
 }
 
@@ -279,17 +281,18 @@
               net_log_)));
   DCHECK(tcp_https_ret.second);
 
-  std::pair<SSLSocketPoolMap::iterator, bool> ssl_https_ret =
+  std::pair<TransportSocketPoolMap::iterator, bool> ssl_https_ret =
       ssl_socket_pools_for_https_proxies_.insert(std::make_pair(
           http_proxy,
-          std::make_unique<SSLClientSocketPool>(
-              sockets_per_proxy_server, sockets_per_group, cert_verifier_,
-              channel_id_service_, transport_security_state_,
-              cert_transparency_verifier_, ct_policy_enforcer_,
-              ssl_client_session_cache_, socket_factory_,
-              tcp_https_ret.first->second.get() /* https proxy */,
-              nullptr /* no socks proxy */, nullptr /* no http proxy */,
-              ssl_config_service_, network_quality_estimator_, net_log_)));
+          new TransportClientSocketPool(
+              sockets_per_proxy_server, sockets_per_group, socket_factory_,
+              host_resolver_, cert_verifier_, channel_id_service_,
+              transport_security_state_, cert_transparency_verifier_,
+              ct_policy_enforcer_, ssl_client_session_cache_,
+              ssl_session_cache_shard_, ssl_config_service_,
+              socket_performance_watcher_factory_, network_quality_estimator_,
+              net_log_, tcp_https_ret.first->second.get() /* https proxy */,
+              nullptr /* no socks proxy */, nullptr /* no http proxy */)));
   DCHECK(tcp_https_ret.second);
 
   std::pair<HTTPProxySocketPoolMap::iterator, bool> ret =
@@ -303,9 +306,10 @@
   return ret.first->second.get();
 }
 
-SSLClientSocketPool* ClientSocketPoolManagerImpl::GetSocketPoolForSSLWithProxy(
+TransportClientSocketPool*
+ClientSocketPoolManagerImpl::GetSocketPoolForSSLWithProxy(
     const ProxyServer& proxy_server) {
-  SSLSocketPoolMap::const_iterator it =
+  TransportSocketPoolMap::const_iterator it =
       ssl_socket_pools_for_proxies_.find(proxy_server);
   if (it != ssl_socket_pools_for_proxies_.end())
     return it->second.get();
@@ -314,21 +318,22 @@
   int sockets_per_group = std::min(sockets_per_proxy_server,
                                    max_sockets_per_group(pool_type_));
 
-  std::pair<SSLSocketPoolMap::iterator, bool> ret =
+  std::pair<TransportSocketPoolMap::iterator, bool> ret =
       ssl_socket_pools_for_proxies_.insert(std::make_pair(
           proxy_server,
-          std::make_unique<SSLClientSocketPool>(
-              sockets_per_proxy_server, sockets_per_group, cert_verifier_,
-              channel_id_service_, transport_security_state_,
-              cert_transparency_verifier_, ct_policy_enforcer_,
-              ssl_client_session_cache_, socket_factory_,
-              nullptr, /* no tcp pool, we always go through a proxy */
+          std::make_unique<TransportClientSocketPool>(
+              sockets_per_proxy_server, sockets_per_group, socket_factory_,
+              host_resolver_, cert_verifier_, channel_id_service_,
+              transport_security_state_, cert_transparency_verifier_,
+              ct_policy_enforcer_, ssl_client_session_cache_,
+              ssl_session_cache_shard_, ssl_config_service_,
+              socket_performance_watcher_factory_, network_quality_estimator_,
+              net_log_, nullptr, /* no tcp pool, we always go through a proxy */
               proxy_server.is_socks() ? GetSocketPoolForSOCKSProxy(proxy_server)
                                       : nullptr,
               proxy_server.is_http_like()
                   ? GetSocketPoolForHTTPLikeProxy(proxy_server)
-                  : nullptr,
-              ssl_config_service_, network_quality_estimator_, net_log_)));
+                  : nullptr)));
 
   return ret.first->second.get();
 }
diff --git a/net/socket/client_socket_pool_manager_impl.h b/net/socket/client_socket_pool_manager_impl.h
index 66650fd..9b87884 100644
--- a/net/socket/client_socket_pool_manager_impl.h
+++ b/net/socket/client_socket_pool_manager_impl.h
@@ -39,7 +39,6 @@
 class ProxyServer;
 class SocketPerformanceWatcherFactory;
 class SSLClientSessionCache;
-class SSLClientSocketPool;
 class SSLConfigService;
 class TransportClientSocketPool;
 class TransportSecurityState;
@@ -72,7 +71,7 @@
 
   TransportClientSocketPool* GetTransportSocketPool() override;
 
-  SSLClientSocketPool* GetSSLSocketPool() override;
+  TransportClientSocketPool* GetSSLSocketPool() override;
 
   TransportClientSocketPool* GetSocketPoolForSOCKSProxy(
       const ProxyServer& proxy_server) override;
@@ -80,7 +79,7 @@
   HttpProxyClientSocketPool* GetSocketPoolForHTTPLikeProxy(
       const ProxyServer& http_proxy) override;
 
-  SSLClientSocketPool* GetSocketPoolForSSLWithProxy(
+  TransportClientSocketPool* GetSocketPoolForSSLWithProxy(
       const ProxyServer& proxy_server) override;
 
   // Creates a Value summary of the state of the socket pools.
@@ -98,8 +97,6 @@
       std::map<ProxyServer, std::unique_ptr<TransportClientSocketPool>>;
   using HTTPProxySocketPoolMap =
       std::map<ProxyServer, std::unique_ptr<HttpProxyClientSocketPool>>;
-  using SSLSocketPoolMap =
-      std::map<ProxyServer, std::unique_ptr<SSLClientSocketPool>>;
 
   NetLog* const net_log_;
   ClientSocketFactory* const socket_factory_;
@@ -120,7 +117,7 @@
   // Note: this ordering is important.
 
   std::unique_ptr<TransportClientSocketPool> transport_socket_pool_;
-  std::unique_ptr<SSLClientSocketPool> ssl_socket_pool_;
+  std::unique_ptr<TransportClientSocketPool> ssl_socket_pool_;
 
   // Currently only contains socket pools for SOCKS proxies (With SSL over SOCKS
   // connections layered on top of it, and appearing in
@@ -130,9 +127,9 @@
 
   TransportSocketPoolMap transport_socket_pools_for_http_proxies_;
   TransportSocketPoolMap transport_socket_pools_for_https_proxies_;
-  SSLSocketPoolMap ssl_socket_pools_for_https_proxies_;
+  TransportSocketPoolMap ssl_socket_pools_for_https_proxies_;
   HTTPProxySocketPoolMap http_proxy_socket_pools_;
-  SSLSocketPoolMap ssl_socket_pools_for_proxies_;
+  TransportSocketPoolMap ssl_socket_pools_for_proxies_;
 
   THREAD_CHECKER(thread_checker_);
 
diff --git a/net/socket/mock_client_socket_pool_manager.cc b/net/socket/mock_client_socket_pool_manager.cc
index b9776561..5e56681 100644
--- a/net/socket/mock_client_socket_pool_manager.cc
+++ b/net/socket/mock_client_socket_pool_manager.cc
@@ -6,7 +6,6 @@
 
 #include "base/values.h"
 #include "net/http/http_proxy_client_socket_pool.h"
-#include "net/socket/ssl_client_socket_pool.h"
 #include "net/socket/transport_client_socket_pool.h"
 
 namespace net {
@@ -20,7 +19,7 @@
 }
 
 void MockClientSocketPoolManager::SetSSLSocketPool(
-    SSLClientSocketPool* pool) {
+    TransportClientSocketPool* pool) {
   ssl_socket_pool_.reset(pool);
 }
 
@@ -39,7 +38,7 @@
 
 void MockClientSocketPoolManager::SetSocketPoolForSSLWithProxy(
     const ProxyServer& proxy_server,
-    std::unique_ptr<SSLClientSocketPool> pool) {
+    std::unique_ptr<TransportClientSocketPool> pool) {
   ssl_socket_pools_for_proxies_[proxy_server] = std::move(pool);
 }
 
@@ -56,7 +55,7 @@
   return transport_socket_pool_.get();
 }
 
-SSLClientSocketPool* MockClientSocketPoolManager::GetSSLSocketPool() {
+TransportClientSocketPool* MockClientSocketPoolManager::GetSSLSocketPool() {
   return ssl_socket_pool_.get();
 }
 
@@ -81,9 +80,10 @@
   return nullptr;
 }
 
-SSLClientSocketPool* MockClientSocketPoolManager::GetSocketPoolForSSLWithProxy(
+TransportClientSocketPool*
+MockClientSocketPoolManager::GetSocketPoolForSSLWithProxy(
     const ProxyServer& proxy_server) {
-  SSLSocketPoolMap::const_iterator it =
+  TransportClientSocketPoolMap::const_iterator it =
       ssl_socket_pools_for_proxies_.find(proxy_server);
   if (it != ssl_socket_pools_for_proxies_.end())
     return it->second.get();
diff --git a/net/socket/mock_client_socket_pool_manager.h b/net/socket/mock_client_socket_pool_manager.h
index 8e97cd6..7fd81bf 100644
--- a/net/socket/mock_client_socket_pool_manager.h
+++ b/net/socket/mock_client_socket_pool_manager.h
@@ -23,26 +23,27 @@
 
   // Sets "override" socket pools that get used instead.
   void SetTransportSocketPool(TransportClientSocketPool* pool);
-  void SetSSLSocketPool(SSLClientSocketPool* pool);
+  void SetSSLSocketPool(TransportClientSocketPool* pool);
   // Currently only works for SOCKS proxies.
   void SetSocketPoolForProxy(const ProxyServer& proxy_server,
                              std::unique_ptr<TransportClientSocketPool> pool);
   void SetSocketPoolForHTTPProxy(
       const ProxyServer& http_proxy,
       std::unique_ptr<HttpProxyClientSocketPool> pool);
-  void SetSocketPoolForSSLWithProxy(const ProxyServer& proxy_server,
-                                    std::unique_ptr<SSLClientSocketPool> pool);
+  void SetSocketPoolForSSLWithProxy(
+      const ProxyServer& proxy_server,
+      std::unique_ptr<TransportClientSocketPool> pool);
 
   // ClientSocketPoolManager methods:
   void FlushSocketPoolsWithError(int error) override;
   void CloseIdleSockets() override;
   TransportClientSocketPool* GetTransportSocketPool() override;
-  SSLClientSocketPool* GetSSLSocketPool() override;
+  TransportClientSocketPool* GetSSLSocketPool() override;
   TransportClientSocketPool* GetSocketPoolForSOCKSProxy(
       const ProxyServer& socks_proxy) override;
   HttpProxyClientSocketPool* GetSocketPoolForHTTPLikeProxy(
       const ProxyServer& http_proxy) override;
-  SSLClientSocketPool* GetSocketPoolForSSLWithProxy(
+  TransportClientSocketPool* GetSocketPoolForSSLWithProxy(
       const ProxyServer& proxy_server) override;
   std::unique_ptr<base::Value> SocketPoolInfoToValue() const override;
   void DumpMemoryStats(
@@ -54,14 +55,12 @@
       std::map<ProxyServer, std::unique_ptr<TransportClientSocketPool>>;
   using HTTPProxySocketPoolMap =
       std::map<ProxyServer, std::unique_ptr<HttpProxyClientSocketPool>>;
-  using SSLSocketPoolMap =
-      std::map<ProxyServer, std::unique_ptr<SSLClientSocketPool>>;
 
   std::unique_ptr<TransportClientSocketPool> transport_socket_pool_;
-  std::unique_ptr<SSLClientSocketPool> ssl_socket_pool_;
+  std::unique_ptr<TransportClientSocketPool> ssl_socket_pool_;
   TransportClientSocketPoolMap proxy_socket_pools_;
   HTTPProxySocketPoolMap http_proxy_socket_pools_;
-  SSLSocketPoolMap ssl_socket_pools_for_proxies_;
+  TransportClientSocketPoolMap ssl_socket_pools_for_proxies_;
 
   DISALLOW_COPY_AND_ASSIGN(MockClientSocketPoolManager);
 };
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 2cb7d900..899543c 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -41,7 +41,6 @@
 #include "net/socket/socket_performance_watcher.h"
 #include "net/socket/socket_tag.h"
 #include "net/socket/ssl_client_socket.h"
-#include "net/socket/ssl_client_socket_pool.h"
 #include "net/socket/transport_client_socket.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/ssl/ssl_config_service.h"
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 14d0048..820ac86 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -32,6 +32,7 @@
 #include "net/socket/socket_tag.h"
 #include "net/socket/socket_test_util.h"
 #include "net/socket/socks_connect_job.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/spdy/spdy_session.h"
@@ -103,15 +104,19 @@
   }
 
   void CreatePool(bool transport_pool, bool http_proxy_pool) {
-    pool_.reset(new SSLClientSocketPool(
-        kMaxSockets, kMaxSocketsPerGroup, cert_verifier_.get(),
+    pool_.reset(new TransportClientSocketPool(
+        kMaxSockets, kMaxSocketsPerGroup, &socket_factory_,
+        nullptr /* host_resolver */, cert_verifier_.get(),
         NULL /* channel_id_service */, transport_security_state_.get(),
         &ct_verifier_, &ct_policy_enforcer_,
-        nullptr /* ssl_client_session_cache */, &socket_factory_,
-        transport_pool ? &transport_socket_pool_ : nullptr, nullptr,
-        http_proxy_pool ? &http_proxy_socket_pool_ : nullptr,
+        nullptr /* ssl_client_session_cache */,
+        std::string() /* ssl_session_cache_shard */,
         nullptr /* ssl_config_service */,
-        nullptr /* network_quality_estimator */, nullptr /* net_log */));
+        nullptr /* socket_performance_watcher_factory */,
+        nullptr /* network_quality_estimator */, nullptr /* net_log */,
+        transport_pool ? &transport_socket_pool_ : nullptr,
+        nullptr /* socks_pool */,
+        http_proxy_pool ? &http_proxy_socket_pool_ : nullptr));
   }
 
   scoped_refptr<SSLSocketParams> SSLParams(ProxyServer::Scheme proxy) {
@@ -172,7 +177,7 @@
   HttpProxyClientSocketPool http_proxy_socket_pool_;
 
   SSLConfig ssl_config_;
-  std::unique_ptr<SSLClientSocketPool> pool_;
+  std::unique_ptr<TransportClientSocketPool> pool_;
 };
 
 TEST_F(SSLClientSocketPoolTest, DirectCertError) {
@@ -186,9 +191,12 @@
 
   ClientSocketHandle handle;
   TestCompletionCallback callback;
-  int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(),
-                       ClientSocketPool::RespectLimits::ENABLED,
-                       callback.callback(), pool_.get(), NetLogWithSource());
+  int rv = handle.Init(
+      kGroupName,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          params),
+      MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
+      callback.callback(), pool_.get(), NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
   EXPECT_FALSE(handle.is_initialized());
   EXPECT_FALSE(handle.socket());
@@ -221,9 +229,12 @@
 
   ClientSocketHandle handle;
   TestCompletionCallback callback;
-  int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(),
-                       ClientSocketPool::RespectLimits::ENABLED,
-                       callback.callback(), pool_.get(), NetLogWithSource());
+  int rv = handle.Init(
+      kGroupName,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          params),
+      MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
+      callback.callback(), pool_.get(), NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
   EXPECT_FALSE(handle.is_initialized());
   EXPECT_FALSE(handle.socket());
@@ -269,13 +280,17 @@
       nullptr /* socket_performance_watcher_factory */,
       nullptr /* network_quality_estimator */, nullptr /* netlog */);
   cert_verifier_->set_default_result(OK);
-  SSLClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
-                           cert_verifier_.get(), NULL /* channel_id_service */,
-                           transport_security_state_.get(), &ct_verifier_,
-                           &ct_policy_enforcer_,
-                           nullptr /* ssl_client_session_cache */,
-                           ClientSocketFactory::GetDefaultFactory(), &tcp_pool,
-                           NULL, NULL, NULL, NULL, NULL);
+  TransportClientSocketPool pool(
+      kMaxSockets, kMaxSocketsPerGroup,
+      ClientSocketFactory::GetDefaultFactory(), &host_resolver_,
+      cert_verifier_.get() /* cert_verifier */, nullptr /* channel_id_server */,
+      transport_security_state_.get(), &ct_verifier_, &ct_policy_enforcer_,
+      nullptr /* ssl_client_session_cache */,
+      std::string() /* ssl_session_cache_shard */,
+      nullptr /* ssl_config_service */,
+      nullptr /* socket_performance_watcher_factory */,
+      nullptr /* network_quality_estimator */, nullptr /* netlog */, &tcp_pool,
+      nullptr /* socks_pool */, nullptr /* http_proxy_pool */);
   TestCompletionCallback callback;
   ClientSocketHandle handle;
   int32_t tag_val1 = 0x12345678;
@@ -290,9 +305,12 @@
 
   // Test socket is tagged before connected.
   uint64_t old_traffic = GetTaggedBytes(tag_val1);
-  int rv = handle.Init(kGroupName, params, LOW, tag1,
-                       ClientSocketPool::RespectLimits::ENABLED,
-                       callback.callback(), &pool, NetLogWithSource());
+  int rv = handle.Init(
+      kGroupName,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          params),
+      LOW, tag1, ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
+      &pool, NetLogWithSource());
   EXPECT_THAT(callback.GetResult(rv), IsOk());
   EXPECT_TRUE(handle.socket());
   EXPECT_TRUE(handle.socket()->IsConnected());
@@ -303,9 +321,12 @@
   handle.Reset();
   old_traffic = GetTaggedBytes(tag_val2);
   TestCompletionCallback callback2;
-  rv = handle.Init(kGroupName, params, LOW, tag2,
-                   ClientSocketPool::RespectLimits::ENABLED,
-                   callback2.callback(), &pool, NetLogWithSource());
+  rv = handle.Init(
+      kGroupName,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          params),
+      LOW, tag2, ClientSocketPool::RespectLimits::ENABLED, callback2.callback(),
+      &pool, NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(handle.socket());
   EXPECT_TRUE(handle.socket()->IsConnected());
@@ -347,13 +368,17 @@
       nullptr /* socket_performance_watcher_factory */,
       nullptr /* network_quality_estimator */, nullptr /* netlog */);
   cert_verifier_->set_default_result(OK);
-  SSLClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
-                           cert_verifier_.get(), NULL /* channel_id_service */,
-                           transport_security_state_.get(), &ct_verifier_,
-                           &ct_policy_enforcer_,
-                           nullptr /* ssl_client_session_cache */,
-                           ClientSocketFactory::GetDefaultFactory(), &tcp_pool,
-                           NULL, NULL, NULL, NULL, NULL);
+  TransportClientSocketPool pool(
+      kMaxSockets, kMaxSocketsPerGroup,
+      ClientSocketFactory::GetDefaultFactory(), &host_resolver_,
+      cert_verifier_.get() /* cert_verifier */, nullptr /* channel_id_server */,
+      transport_security_state_.get(), &ct_verifier_, &ct_policy_enforcer_,
+      nullptr /* ssl_client_session_cache */,
+      std::string() /* ssl_session_cache_shard */,
+      nullptr /* ssl_config_service */,
+      nullptr /* socket_performance_watcher_factory */,
+      nullptr /* network_quality_estimator */, nullptr /* netlog */, &tcp_pool,
+      nullptr /* socks_pool */, nullptr /* http_proxy_pool */);
   ClientSocketHandle handle;
   int32_t tag_val1 = 0x12345678;
   SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
@@ -368,16 +393,22 @@
   // Test connect jobs that are orphaned and then adopted, appropriately apply
   // new tag. Request socket with |tag1|.
   TestCompletionCallback callback;
-  int rv = handle.Init(kGroupName, params, LOW, tag1,
-                       ClientSocketPool::RespectLimits::ENABLED,
-                       callback.callback(), &pool, NetLogWithSource());
+  int rv = handle.Init(
+      kGroupName,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          params),
+      LOW, tag1, ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
+      &pool, NetLogWithSource());
   EXPECT_TRUE(rv == OK || rv == ERR_IO_PENDING) << "Result: " << rv;
   // Abort and request socket with |tag2|.
   handle.Reset();
   TestCompletionCallback callback2;
-  rv = handle.Init(kGroupName, params, LOW, tag2,
-                   ClientSocketPool::RespectLimits::ENABLED,
-                   callback2.callback(), &pool, NetLogWithSource());
+  rv = handle.Init(
+      kGroupName,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          params),
+      LOW, tag2, ClientSocketPool::RespectLimits::ENABLED, callback2.callback(),
+      &pool, NetLogWithSource());
   EXPECT_THAT(callback2.GetResult(rv), IsOk());
   EXPECT_TRUE(handle.socket());
   EXPECT_TRUE(handle.socket()->IsConnected());
@@ -417,13 +448,17 @@
       nullptr /* socket_performance_watcher_factory */,
       nullptr /* network_quality_estimator */, nullptr /* netlog */);
   cert_verifier_->set_default_result(OK);
-  SSLClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
-                           cert_verifier_.get(), NULL /* channel_id_service */,
-                           transport_security_state_.get(), &ct_verifier_,
-                           &ct_policy_enforcer_,
-                           nullptr /* ssl_client_session_cache */,
-                           ClientSocketFactory::GetDefaultFactory(), &tcp_pool,
-                           NULL, NULL, NULL, NULL, NULL);
+  TransportClientSocketPool pool(
+      kMaxSockets, kMaxSocketsPerGroup,
+      ClientSocketFactory::GetDefaultFactory(), &host_resolver_,
+      cert_verifier_.get() /* cert_verifier */, nullptr /* channel_id_server */,
+      transport_security_state_.get(), &ct_verifier_, &ct_policy_enforcer_,
+      nullptr /* ssl_client_session_cache */,
+      std::string() /* ssl_session_cache_shard */,
+      nullptr /* ssl_config_service */,
+      nullptr /* socket_performance_watcher_factory */,
+      nullptr /* network_quality_estimator */, nullptr /* netlog */, &tcp_pool,
+      nullptr /* socks_pool */, nullptr /* http_proxy_pool */);
   TestCompletionCallback callback;
   ClientSocketHandle handle;
   int32_t tag_val1 = 0x12345678;
@@ -454,12 +489,18 @@
   // Request two SSL sockets.
   ClientSocketHandle handle_to_be_canceled;
   rv = handle_to_be_canceled.Init(
-      kGroupName, params, LOW, tag1, ClientSocketPool::RespectLimits::ENABLED,
-      callback.callback(), &pool, NetLogWithSource());
+      kGroupName,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          params),
+      LOW, tag1, ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
+      &pool, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
-  rv = handle.Init(kGroupName, params, LOW, tag2,
-                   ClientSocketPool::RespectLimits::ENABLED,
-                   callback.callback(), &pool, NetLogWithSource());
+  rv = handle.Init(
+      kGroupName,
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          params),
+      LOW, tag2, ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
+      &pool, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
   // Cancel first request.
   handle_to_be_canceled.Reset();
diff --git a/net/socket/ssl_connect_job.cc b/net/socket/ssl_connect_job.cc
index b37c478..df71b53 100644
--- a/net/socket/ssl_connect_job.cc
+++ b/net/socket/ssl_connect_job.cc
@@ -138,8 +138,10 @@
 }
 
 bool SSLConnectJob::HasEstablishedConnection() const {
+  // Return true to prevent creating any backup jobs when this is used in a
+  // TransportClientSocketPool.
   // TODO(mmenke): Implement this, as nested pools are removed.
-  return false;
+  return true;
 }
 
 void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle* handle) {
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc
index 7ca302b..12b7daf 100644
--- a/net/socket/transport_client_socket_pool.cc
+++ b/net/socket/transport_client_socket_pool.cc
@@ -12,6 +12,7 @@
 #include "base/trace_event/trace_event.h"
 #include "base/values.h"
 #include "net/base/trace_constants.h"
+#include "net/http/http_proxy_client_socket_pool.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_event_type.h"
 #include "net/log/net_log_source_type.h"
@@ -21,6 +22,7 @@
 #include "net/socket/client_socket_pool_base.h"
 #include "net/socket/socket_net_log_params.h"
 #include "net/socket/socks_connect_job.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/socket/websocket_transport_connect_job.h"
 
@@ -28,13 +30,52 @@
 
 namespace {
 
+// TODO(mmenke): Once the socket pool arguments are no longer needed, remove
+// this method and use TransportConnectJob::CreateTransportConnectJob()
+// directly.
+std::unique_ptr<ConnectJob> CreateTransportConnectJob(
+    scoped_refptr<TransportSocketParams> transport_socket_params,
+    RequestPriority priority,
+    const CommonConnectJobParams& common_connect_job_params,
+    ConnectJob::Delegate* delegate,
+    TransportClientSocketPool* transport_pool,
+    TransportClientSocketPool* socks_pool,
+    HttpProxyClientSocketPool* http_proxy_pool) {
+  DCHECK(!transport_pool);
+  DCHECK(!socks_pool);
+  DCHECK(!http_proxy_pool);
+  return TransportConnectJob::CreateTransportConnectJob(
+      std::move(transport_socket_params), priority, common_connect_job_params,
+      delegate);
+}
+
 std::unique_ptr<ConnectJob> CreateSOCKSConnectJob(
     scoped_refptr<SOCKSSocketParams> socks_socket_params,
     RequestPriority priority,
     const CommonConnectJobParams& common_connect_job_params,
-    ConnectJob::Delegate* delegate) {
+    ConnectJob::Delegate* delegate,
+    TransportClientSocketPool* transport_pool,
+    TransportClientSocketPool* socks_pool,
+    HttpProxyClientSocketPool* http_proxy_pool) {
+  DCHECK(!transport_pool);
+  DCHECK(!socks_pool);
+  DCHECK(!http_proxy_pool);
   return std::make_unique<SOCKSConnectJob>(priority, common_connect_job_params,
-                                           socks_socket_params, delegate);
+                                           std::move(socks_socket_params),
+                                           delegate);
+}
+
+std::unique_ptr<ConnectJob> CreateSSLConnectJob(
+    scoped_refptr<SSLSocketParams> ssl_socket_params,
+    RequestPriority priority,
+    const CommonConnectJobParams& common_connect_job_params,
+    ConnectJob::Delegate* delegate,
+    TransportClientSocketPool* transport_pool,
+    TransportClientSocketPool* socks_pool,
+    HttpProxyClientSocketPool* http_proxy_pool) {
+  return std::make_unique<SSLConnectJob>(
+      priority, common_connect_job_params, std::move(ssl_socket_params),
+      transport_pool, socks_pool, http_proxy_pool, delegate);
 }
 
 }  // namespace
@@ -46,9 +87,8 @@
 scoped_refptr<TransportClientSocketPool::SocketParams>
 TransportClientSocketPool::SocketParams::CreateFromTransportSocketParams(
     scoped_refptr<TransportSocketParams> transport_client_params) {
-  CreateConnectJobCallback callback =
-      base::BindRepeating(&TransportConnectJob::CreateTransportConnectJob,
-                          std::move(transport_client_params));
+  CreateConnectJobCallback callback = base::BindRepeating(
+      &CreateTransportConnectJob, std::move(transport_client_params));
   return base::MakeRefCounted<SocketParams>(callback);
 }
 
@@ -60,8 +100,40 @@
   return base::MakeRefCounted<SocketParams>(callback);
 }
 
+scoped_refptr<TransportClientSocketPool::SocketParams>
+TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+    scoped_refptr<SSLSocketParams> ssl_socket_params) {
+  CreateConnectJobCallback callback =
+      base::BindRepeating(&CreateSSLConnectJob, std::move(ssl_socket_params));
+  return base::MakeRefCounted<SocketParams>(callback);
+}
+
 TransportClientSocketPool::SocketParams::~SocketParams() = default;
 
+TransportClientSocketPool::TransportConnectJobFactory::
+    TransportConnectJobFactory(
+        ClientSocketFactory* client_socket_factory,
+        HostResolver* host_resolver,
+        const SSLClientSocketContext& ssl_client_socket_context,
+        SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
+        NetworkQualityEstimator* network_quality_estimator,
+        NetLog* net_log,
+        TransportClientSocketPool* transport_pool,
+        TransportClientSocketPool* socks_pool,
+        HttpProxyClientSocketPool* http_proxy_pool)
+    : client_socket_factory_(client_socket_factory),
+      host_resolver_(host_resolver),
+      ssl_client_socket_context_(ssl_client_socket_context),
+      socket_performance_watcher_factory_(socket_performance_watcher_factory),
+      network_quality_estimator_(network_quality_estimator),
+      net_log_(net_log),
+      transport_pool_(transport_pool),
+      socks_pool_(socks_pool),
+      http_proxy_pool_(http_proxy_pool) {}
+
+TransportClientSocketPool::TransportConnectJobFactory::
+    ~TransportConnectJobFactory() = default;
+
 std::unique_ptr<ConnectJob>
 TransportClientSocketPool::TransportConnectJobFactory::NewConnectJob(
     const std::string& group_name,
@@ -75,7 +147,7 @@
           client_socket_factory_, host_resolver_, ssl_client_socket_context_,
           socket_performance_watcher_factory_, network_quality_estimator_,
           net_log_, nullptr /* websocket_endpoint_lock_manager */),
-      delegate);
+      delegate, transport_pool_, socks_pool_, http_proxy_pool_);
 }
 
 TransportClientSocketPool::TransportClientSocketPool(
@@ -93,8 +165,11 @@
     SSLConfigService* ssl_config_service,
     SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
     NetworkQualityEstimator* network_quality_estimator,
-    NetLog* net_log)
-    : base_(nullptr,
+    NetLog* net_log,
+    TransportClientSocketPool* transport_pool,
+    TransportClientSocketPool* socks_pool,
+    HttpProxyClientSocketPool* http_proxy_pool)
+    : base_(this,
             max_sockets,
             max_sockets_per_group,
             ClientSocketPool::unused_idle_socket_timeout(),
@@ -111,12 +186,22 @@
                                        ssl_session_cache_shard),
                 socket_performance_watcher_factory,
                 network_quality_estimator,
-                net_log)),
+                net_log,
+                transport_pool,
+                socks_pool,
+                http_proxy_pool)),
       client_socket_factory_(client_socket_factory),
       ssl_config_service_(ssl_config_service) {
   base_.EnableConnectBackupJobs();
   if (ssl_config_service_)
     ssl_config_service_->AddObserver(this);
+
+  if (transport_pool)
+    base_.AddLowerLayeredPool(transport_pool);
+  if (socks_pool)
+    base_.AddLowerLayeredPool(socks_pool);
+  if (http_proxy_pool)
+    base_.AddLowerLayeredPool(http_proxy_pool);
 }
 
 TransportClientSocketPool::~TransportClientSocketPool() {
@@ -236,6 +321,18 @@
   base_.RemoveHigherLayeredPool(higher_pool);
 }
 
+bool TransportClientSocketPool::CloseOneIdleConnection() {
+  if (base_.CloseOneIdleSocket())
+    return true;
+  return base_.CloseOneIdleConnectionInHigherLayeredPool();
+}
+
+void TransportClientSocketPool::DumpMemoryStats(
+    base::trace_event::ProcessMemoryDump* pmd,
+    const std::string& parent_dump_absolute_name) const {
+  base_.DumpMemoryStats(pmd, parent_dump_absolute_name);
+}
+
 void TransportClientSocketPool::OnSSLConfigChanged() {
   // When the user changes the SSL config, flush all idle sockets so they won't
   // get re-used.
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h
index db18547..a93531d 100644
--- a/net/socket/transport_client_socket_pool.h
+++ b/net/socket/transport_client_socket_pool.h
@@ -27,16 +27,19 @@
 class CTVerifier;
 class CTPolicyEnforcer;
 class HostResolver;
+class HttpProxyClientSocketPool;
 class NetLog;
 class NetLogWithSource;
 class NetworkQualityEstimator;
 class SocketPerformanceWatcherFactory;
 class SOCKSSocketParams;
+class SSLSocketParams;
 class TransportSecurityState;
 class TransportSocketParams;
 
 class NET_EXPORT_PRIVATE TransportClientSocketPool
     : public ClientSocketPool,
+      public HigherLayeredPool,
       public SSLConfigService::Observer {
  public:
   // Callback to create a ConnectJob using the provided arguments. The lower
@@ -44,11 +47,18 @@
   // socket, proxy, etc) are all already bound to the callback.  If
   // |websocket_endpoint_lock_manager| is non-null, a ConnectJob for use by
   // WebSockets should be created.
+  //
+  // |transport_pool|, |socks_pool|, and |http_proxy_pool| are for the case of
+  // SSLConnectJobs that will be layered on top of other socket pool types.
+  // TODO(mmenke): Remove them.
   using CreateConnectJobCallback =
       base::RepeatingCallback<std::unique_ptr<ConnectJob>(
           RequestPriority priority,
           const CommonConnectJobParams& common_connect_job_params,
-          ConnectJob::Delegate* delegate)>;
+          ConnectJob::Delegate* delegate,
+          TransportClientSocketPool* transport_pool,
+          TransportClientSocketPool* socks_pool,
+          HttpProxyClientSocketPool* http_proxy_pool)>;
 
   // "Parameters" that own a single callback for creating a ConnectJob that can
   // be of any type.
@@ -71,6 +81,9 @@
     static scoped_refptr<SocketParams> CreateFromSOCKSSocketParams(
         scoped_refptr<SOCKSSocketParams> socks_socket_params);
 
+    static scoped_refptr<SocketParams> CreateFromSSLSocketParams(
+        scoped_refptr<SSLSocketParams> ssl_socket_params);
+
    private:
     friend class base::RefCounted<SocketParams>;
     ~SocketParams();
@@ -80,6 +93,11 @@
     DISALLOW_COPY_AND_ASSIGN(SocketParams);
   };
 
+  // If this is being used for an SSL socket pool, |transport_pool|,
+  // |socks_pool|, and |http_proxy_pool| socket pools beneath the SSL socket
+  // pool.
+  //
+  // TODO(mmenke): Remove those socket pools.
   TransportClientSocketPool(
       int max_sockets,
       int max_sockets_per_group,
@@ -95,7 +113,10 @@
       SSLConfigService* ssl_config_service,
       SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
       NetworkQualityEstimator* network_quality_estimator,
-      NetLog* net_log);
+      NetLog* net_log,
+      TransportClientSocketPool* transport_pool = nullptr,
+      TransportClientSocketPool* socks_pool = nullptr,
+      HttpProxyClientSocketPool* http_proxy_pool = nullptr);
 
   ~TransportClientSocketPool() override;
 
@@ -138,6 +159,12 @@
   void AddHigherLayeredPool(HigherLayeredPool* higher_pool) override;
   void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) override;
 
+  // HigherLayeredPool implementation.
+  bool CloseOneIdleConnection() override;
+
+  void DumpMemoryStats(base::trace_event::ProcessMemoryDump* pmd,
+                       const std::string& parent_dump_absolute_name) const;
+
   ClientSocketFactory* client_socket_factory() {
     return client_socket_factory_;
   }
@@ -159,16 +186,12 @@
         const SSLClientSocketContext& ssl_client_socket_context,
         SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
         NetworkQualityEstimator* network_quality_estimator,
-        NetLog* net_log)
-        : client_socket_factory_(client_socket_factory),
-          host_resolver_(host_resolver),
-          ssl_client_socket_context_(ssl_client_socket_context),
-          socket_performance_watcher_factory_(
-              socket_performance_watcher_factory),
-          network_quality_estimator_(network_quality_estimator),
-          net_log_(net_log) {}
+        NetLog* net_log,
+        TransportClientSocketPool* transport_pool = nullptr,
+        TransportClientSocketPool* socks_pool = nullptr,
+        HttpProxyClientSocketPool* http_proxy_pool = nullptr);
 
-    ~TransportConnectJobFactory() override {}
+    ~TransportConnectJobFactory() override;
 
     // ClientSocketPoolBase::ConnectJobFactory methods.
 
@@ -185,6 +208,10 @@
     NetworkQualityEstimator* const network_quality_estimator_;
     NetLog* const net_log_;
 
+    TransportClientSocketPool* const transport_pool_;
+    TransportClientSocketPool* const socks_pool_;
+    HttpProxyClientSocketPool* const http_proxy_pool_;
+
     DISALLOW_COPY_AND_ASSIGN(TransportConnectJobFactory);
   };
 
diff --git a/net/socket/transport_client_socket_unittest.cc b/net/socket/transport_client_socket_unittest.cc
index 26b3dbf..37940565 100644
--- a/net/socket/transport_client_socket_unittest.cc
+++ b/net/socket/transport_client_socket_unittest.cc
@@ -477,12 +477,8 @@
   int rv = write_callback.WaitForResult();
   EXPECT_GE(rv, 0);
 
-  // It's possible the read is blocked because it's already read all the data.
-  // Close the server socket, so there will at least be a 0-byte read.
-  CloseServerSocket();
-
   rv = callback.WaitForResult();
-  EXPECT_GE(rv, 0);
+  EXPECT_GT(rv, 0);
 }
 
 }  // namespace net
diff --git a/net/socket/websocket_transport_client_socket_pool.cc b/net/socket/websocket_transport_client_socket_pool.cc
index dc94c10..e1647eb 100644
--- a/net/socket/websocket_transport_client_socket_pool.cc
+++ b/net/socket/websocket_transport_client_socket_pool.cc
@@ -147,7 +147,7 @@
                                  nullptr /* SocketPerformanceWatcherFactory */,
                                  network_quality_estimator_, pool_net_log_,
                                  websocket_endpoint_lock_manager_),
-          connect_job_delegate.get());
+          connect_job_delegate.get(), nullptr, nullptr, nullptr);
 
   int result = connect_job_delegate->Connect(std::move(connect_job));
 
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index fb75add..951f4a4 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -27,6 +27,7 @@
 #include "net/socket/socket_tag.h"
 #include "net/socket/socks_connect_job.h"
 #include "net/socket/ssl_client_socket.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/spdy/buffered_spdy_framer.h"
@@ -496,8 +497,11 @@
       transport_params, nullptr, nullptr, key.host_port_pair(), ssl_config,
       key.privacy_mode());
   int rv = connection->Init(
-      key.host_port_pair().ToString(), ssl_params, MEDIUM, key.socket_tag(),
-      ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
+      key.host_port_pair().ToString(),
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          ssl_params),
+      MEDIUM, key.socket_tag(), ClientSocketPool::RespectLimits::ENABLED,
+      callback.callback(),
       http_session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL),
       net_log);
   rv = callback.GetResult(rv);
diff --git a/net/test/python_utils.cc b/net/test/python_utils.cc
index 9548d98..e4110c1 100644
--- a/net/test/python_utils.cc
+++ b/net/test/python_utils.cc
@@ -40,7 +40,7 @@
   std::string old_path;
   std::string dir_path;
 #if defined(OS_WIN)
-  dir_path = base::WideToUTF8(dir.value());
+  dir_path = base::UTF16ToUTF8(dir.value());
 #elif defined(OS_POSIX)
   dir_path = dir.value();
 #endif
diff --git a/net/url_request/url_request_file_dir_job_unittest.cc b/net/url_request/url_request_file_dir_job_unittest.cc
index e5afa8f..148dafc 100644
--- a/net/url_request/url_request_file_dir_job_unittest.cc
+++ b/net/url_request/url_request_file_dir_job_unittest.cc
@@ -308,7 +308,7 @@
   for (int slashes_to_test = 1; slashes_to_test < 4; ++slashes_to_test) {
     base::FilePath::StringType root_dir_string;
 #if defined(OS_WIN)
-    root_dir_string = L"C:";
+    root_dir_string = FILE_PATH_LITERAL("C:");
 #endif
     root_dir_string.append(slashes_to_test, base::FilePath::kSeparators[0]);
     base::FilePath root_dir(root_dir_string);
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index be31d12..3c91beb 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -1453,7 +1453,7 @@
   app_path = app_path.Append(kTestFilePath);
   app_path = app_path.AppendASCII("with-headers.html");
 
-  std::wstring lnk_path = app_path.value() + L".lnk";
+  base::string16 lnk_path = app_path.value() + FILE_PATH_LITERAL(".lnk");
 
   base::win::ScopedCOMInitializer com_initializer;
 
@@ -1464,9 +1464,9 @@
         CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shell))));
     Microsoft::WRL::ComPtr<IPersistFile> persist;
     ASSERT_TRUE(SUCCEEDED(shell.CopyTo(persist.GetAddressOf())));
-    EXPECT_TRUE(SUCCEEDED(shell->SetPath(app_path.value().c_str())));
+    EXPECT_TRUE(SUCCEEDED(shell->SetPath(base::wdata(app_path.value()))));
     EXPECT_TRUE(SUCCEEDED(shell->SetDescription(L"ResolveShortcutTest")));
-    EXPECT_TRUE(SUCCEEDED(persist->Save(lnk_path.c_str(), TRUE)));
+    EXPECT_TRUE(SUCCEEDED(persist->Save(base::wdata(lnk_path), TRUE)));
   }
 
   TestDelegate d;
@@ -1481,11 +1481,11 @@
     d.RunUntilComplete();
 
     WIN32_FILE_ATTRIBUTE_DATA data;
-    GetFileAttributesEx(app_path.value().c_str(),
-                        GetFileExInfoStandard, &data);
-    HANDLE file = CreateFile(app_path.value().c_str(), GENERIC_READ,
-                             FILE_SHARE_READ, NULL, OPEN_EXISTING,
-                             FILE_ATTRIBUTE_NORMAL, NULL);
+    GetFileAttributesEx(base::wdata(app_path.value()), GetFileExInfoStandard,
+                        &data);
+    HANDLE file =
+        CreateFile(base::wdata(app_path.value()), GENERIC_READ, FILE_SHARE_READ,
+                   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     EXPECT_NE(INVALID_HANDLE_VALUE, file);
     std::unique_ptr<char[]> buffer(new char[data.nFileSizeLow]);
     DWORD read_size;
@@ -1501,7 +1501,7 @@
   }
 
   // Clean the shortcut
-  DeleteFile(lnk_path.c_str());
+  DeleteFile(base::wdata(lnk_path));
 }
 #endif  // defined(OS_WIN)
 
diff --git a/net/websockets/websocket_basic_stream_adapters_test.cc b/net/websockets/websocket_basic_stream_adapters_test.cc
index 335d743..245cdaf7 100644
--- a/net/websockets/websocket_basic_stream_adapters_test.cc
+++ b/net/websockets/websocket_basic_stream_adapters_test.cc
@@ -25,7 +25,7 @@
 #include "net/socket/socket_tag.h"
 #include "net/socket/socket_test_util.h"
 #include "net/socket/socks_connect_job.h"
-#include "net/socket/ssl_client_socket_pool.h"
+#include "net/socket/ssl_connect_job.h"
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/socket/transport_connect_job.h"
 #include "net/socket/websocket_endpoint_lock_manager.h"
@@ -91,9 +91,12 @@
   bool InitClientSocketHandle(ClientSocketHandle* connection) {
     TestCompletionCallback callback;
     int rv = connection->Init(
-        kGroupName, ssl_params_, MEDIUM, SocketTag(),
-        ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
-        socket_pool_manager_->GetSSLSocketPool(), net_log_);
+        kGroupName,
+        TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+            ssl_params_),
+        MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
+        callback.callback(), socket_pool_manager_->GetSSLSocketPool(),
+        net_log_);
     rv = callback.GetResult(rv);
     return rv == OK;
   }
diff --git a/services/device/hid/test_report_descriptors.cc b/services/device/hid/test_report_descriptors.cc
index 0ba7a09..0234145 100644
--- a/services/device/hid/test_report_descriptors.cc
+++ b/services/device/hid/test_report_descriptors.cc
@@ -26,10 +26,10 @@
     0x26, 0xe0, 0x2e,  //   Logical Maximum (12000)
     0x35, 0x00,        //   Physical Minimum (0)
     0x45, 0x0c,        //   Physical Maximum (12)
-    0x65, 0x13,        //   Unit (19)
+    0x65, 0x13,        //   Unit (Inch)
     0x55, 0x00,        //   Unit Exponent (0)
     0xa4,              //   Push
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x0d,        //   Usage Page (Digitizer)
     0x09, 0x32,        //   Usage (0x32)
     0x09, 0x44,        //   Usage (0x44)
@@ -41,10 +41,10 @@
     0x75, 0x01,        //   Report Size (1)
     0x95, 0x03,        //   Report Count (3)
     0x65, 0x00,        //   Unit (0)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x01,        //   Report Count (1)
     0x75, 0x05,        //   Report Size (5)
-    0x81, 0x03,        //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x03,        //   Input (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0,              //  End Collection
     0x85, 0x02,        //  Report ID (0x2)
     0x09, 0x20,        //  Usage (0x20)
@@ -53,7 +53,7 @@
     0xa4,              //   Push
     0x09, 0x30,        //   Usage (0x30)
     0x09, 0x31,        //   Usage (0x31)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x0d,        //   Usage Page (Digitizer)
     0x09, 0x32,        //   Usage (0x32)
     0x15, 0x00,        //   Logical Minimum (0)
@@ -62,15 +62,15 @@
     0x45, 0x01,        //   Physical Maximum (1)
     0x65, 0x00,        //   Unit (0)
     0x75, 0x01,        //   Report Size (1)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x09,        //   Usage Page (Button)
     0x19, 0x00,        //   Usage Minimum (0)
     0x29, 0x10,        //   Usage Maximum (16)
     0x25, 0x10,        //   Logical Maximum (16)
     0x75, 0x05,        //   Report Size (5)
-    0x81, 0x40,        //   Input (Dat|Var|Rel|NoWrp|Lin|Prf|Null|BitF)
+    0x81, 0x40,        //   Input (Dat|Arr|Abs|NoWrp|Lin|Prf|Null|BitF)
     0x75, 0x02,        //   Report Size (2)
-    0x81, 0x01,        //   Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x01,        //   Input (Con|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0,              //  End Collection
     0x85, 0x03,        //  Report ID (0x3)
     0x05, 0x0d,        //  Usage Page (Digitizer)
@@ -79,7 +79,7 @@
     0xb4,              //   Pop
     0x09, 0x30,        //   Usage (0x30)
     0x09, 0x31,        //   Usage (0x31)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x0d,        //   Usage Page (Digitizer)
     0x09, 0x32,        //   Usage (0x32)
     0x09, 0x44,        //   Usage (0x44)
@@ -89,20 +89,20 @@
     0x35, 0x00,        //   Physical Minimum (0)
     0x45, 0x01,        //   Physical Maximum (1)
     0x65, 0x00,        //   Unit (0)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x06,        //   Report Count (6)
-    0x81, 0x03,        //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x03,        //   Input (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x30,        //   Usage (0x30)
     0x15, 0x00,        //   Logical Minimum (0)
     0x25, 0x7f,        //   Logical Maximum (127)
     0x35, 0x00,        //   Physical Minimum (0)
     0x45, 0x2d,        //   Physical Maximum (45)
-    0x67, 0x11, 0xe1,  //   Unit (57617)
+    0x67, 0x11, 0xe1,  //   Unit (Newtons)
     0x00, 0x00,        //   Default
     0x55, 0x04,        //   Unit Exponent (4)
     0x75, 0x08,        //   Report Size (8)
     0x95, 0x01,        //   Report Count (1)
-    0x81, 0x12,        //   Input (Dat|Arr|Rel|NoWrp|NoLin|Prf|NoNull|BitF)
+    0x81, 0x12,        //   Input (Dat|Var|Abs|NoWrp|NoLin|Prf|NoNull|BitF)
     0xc0,              //  End Collection
     0xc0               // End Collection
 };
@@ -121,19 +121,19 @@
     0x25, 0x01,  //  Logical Maximum (1)
     0x75, 0x01,  //  Report Size (1)
     0x95, 0x08,  //  Report Count (8)
-    0x81, 0x02,  //  Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,  //  Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x01,  //  Report Count (1)
     0x75, 0x08,  //  Report Size (8)
-    0x81, 0x03,  //  Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x03,  //  Input (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x05,  //  Report Count (5)
     0x75, 0x01,  //  Report Size (1)
     0x05, 0x08,  //  Usage Page (Led)
     0x19, 0x01,  //  Usage Minimum (1)
     0x29, 0x05,  //  Usage Maximum (5)
-    0x91, 0x02,  //  Output (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x02,  //  Output (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x01,  //  Report Count (1)
     0x75, 0x03,  //  Report Size (3)
-    0x91, 0x03,  //  Output (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x03,  //  Output (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x06,  //  Report Count (6)
     0x75, 0x08,  //  Report Size (8)
     0x15, 0x00,  //  Logical Minimum (0)
@@ -141,7 +141,7 @@
     0x05, 0x07,  //  Usage Page (Keyboard)
     0x19, 0x00,  //  Usage Minimum (0)
     0x29, 0x65,  //  Usage Maximum (101)
-    0x81, 0x00,  //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,  //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0         // End Collection
 };
 const size_t kKeyboardSize = base::size(kKeyboard);
@@ -158,11 +158,11 @@
     0x75, 0x08,        //  Report Size (8)
     0x95, 0x80,        //  Report Count (128)
     0x09, 0x02,        //  Usage (0x2)
-    0xb2, 0x02, 0x01,  //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff)
+    0xb2, 0x02, 0x01,  //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|Buff)
     0x85, 0x02,        //  Report ID (0x2)
     0x95, 0xf3,        //  Report Count (243)
     0x09, 0x03,        //  Usage (0x3)
-    0xb2, 0x02, 0x01,  //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff)
+    0xb2, 0x02, 0x01,  //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|Buff)
     0x85, 0x03,        //  Report ID (0x3)
     0x05, 0x82,        //  Usage Page (Monitor 2)
     0x67, 0xE1, 0x00,  //  Unit (System: SI, Lum. Intensity: Candela)
@@ -172,11 +172,11 @@
     0x75, 0x10,        //  Report Size (16)
     0x26, 0xc8, 0x00,  //  Logical Maximum (200)
     0x09, 0x10,        //  Usage (0x10)
-    0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0xb1, 0x02,        //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x85, 0x04,        //  Report ID (0x4)
     0x25, 0x64,        //  Logical Maximum (100)
     0x09, 0x12,        //  Usage (0x12)
-    0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0xb1, 0x02,        //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x06,        //  Report Count (6)
     0x26, 0xff, 0x00,  //  Logical Maximum (255)
     0x09, 0x16,        //  Usage (0x16)
@@ -185,7 +185,7 @@
     0x09, 0x6c,        //  Usage (0x6C)
     0x09, 0x6e,        //  Usage (0x6E)
     0x09, 0x70,        //  Usage (0x70)
-    0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0xb1, 0x02,        //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x85, 0x05,        //  Report ID (0x5)
     0x25, 0x7f,        //  Logical Maximum (127)
     0x09, 0x20,        //  Usage (0x20)
@@ -194,7 +194,7 @@
     0x09, 0x32,        //  Usage (0x32)
     0x09, 0x42,        //  Usage (0x42)
     0x09, 0x44,        //  Usage (0x44)
-    0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0xb1, 0x02,        //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0               // End Collection
 };
 const size_t kMonitorSize = base::size(kMonitor);
@@ -214,10 +214,10 @@
     0x25, 0x01,  //   Logical Maximum (1)
     0x95, 0x03,  //   Report Count (3)
     0x75, 0x01,  //   Report Size (1)
-    0x81, 0x02,  //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,  //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x01,  //   Report Count (1)
     0x75, 0x05,  //   Report Size (5)
-    0x81, 0x03,  //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x03,  //   Input (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x01,  //   Usage Page (Generic Desktop)
     0x09, 0x30,  //   Usage (0x30)
     0x09, 0x31,  //   Usage (0x31)
@@ -225,7 +225,7 @@
     0x25, 0x7f,  //   Logical Maximum (127)
     0x75, 0x08,  //   Report Size (8)
     0x95, 0x02,  //   Report Count (2)
-    0x81, 0x06,  //   Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x06,  //   Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0,        //  End Collection
     0xc0         // End Collection
 };
@@ -242,9 +242,9 @@
     0x15, 0x00,        //  Logical Minimum (0)
     0x26, 0xFF, 0x00,  //  Logical Maximum (255)
     0x09, 0x01,        //  Usage (0x1)
-    0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,        //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x01,        //  Usage (0x1)
-    0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x00,        //  Output (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xC0,              // End Collection
     0x06, 0x00, 0xFF,  // Usage Page (Vendor)
     0x09, 0x02,        // Usage (0x2)
@@ -255,9 +255,9 @@
     0x15, 0x00,        //  Logical Minimum (0)
     0x26, 0xFF, 0x00,  //  Logical Maximum (255)
     0x09, 0x02,        //  Usage (0x2)
-    0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,        //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x02,        //  Usage (0x2)
-    0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x00,        //  Output (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xC0,              // End Collection
     0x06, 0x00, 0xFF,  // Usage Page (Vendor)
     0x09, 0x04,        // Usage (0x4)
@@ -268,17 +268,17 @@
     0x15, 0x00,        //  Logical Minimum (0)
     0x26, 0xFF, 0x00,  //  Logical Maximum (255)
     0x09, 0x41,        //  Usage (0x41)
-    0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,        //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x41,        //  Usage (0x41)
-    0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x00,        //  Output (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x85, 0x21,        //  Report ID (0x21)
     0x95, 0x1F,        //  Report Count (31)
     0x15, 0x00,        //  Logical Minimum (0)
     0x26, 0xFF, 0x00,  //  Logical Maximum (255)
     0x09, 0x42,        //  Usage (0x42)
-    0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,        //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x42,        //  Usage (0x42)
-    0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x00,        //  Output (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xC0               // End Collection
 };
 const size_t kLogitechUnifyingReceiverSize =
@@ -288,8 +288,8 @@
 const uint8_t kSonyDualshock3[] = {
     0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
     0x09, 0x04,        // Usage (Joystick)
-    0xA1, 0x01,        // Collection (Physical)
-    0xA1, 0x02,        //   Collection (Application)
+    0xA1, 0x01,        // Collection (Application)
+    0xA1, 0x02,        //   Collection (Logical)
     0x85, 0x01,        //     Report ID (1)
     0x75, 0x08,        //     Report Size (8)
     0x95, 0x01,        //     Report Count (1)
@@ -318,7 +318,7 @@
     0x26, 0xFF, 0x00,  //     Logical Maximum (255)
     0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
     0x09, 0x01,        //     Usage (Pointer)
-    0xA1, 0x00,        //     Collection (Undefined)
+    0xA1, 0x00,        //     Collection (Physical)
     0x75, 0x08,        //       Report Size (8)
     0x95, 0x04,        //       Report Count (4)
     0x35, 0x00,        //       Physical Minimum (0)
@@ -347,7 +347,7 @@
     0xB1, 0x02,        //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred
                        //     State,No Null Position,Non-volatile)
     0xC0,              //   End Collection
-    0xA1, 0x02,        //   Collection (Application)
+    0xA1, 0x02,        //   Collection (Logical)
     0x85, 0x02,        //     Report ID (2)
     0x75, 0x08,        //     Report Size (8)
     0x95, 0x30,        //     Report Count (48)
@@ -355,7 +355,7 @@
     0xB1, 0x02,        //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred
                        //     State,No Null Position,Non-volatile)
     0xC0,              //   End Collection
-    0xA1, 0x02,        //   Collection (Application)
+    0xA1, 0x02,        //   Collection (Logical)
     0x85, 0xEE,        //     Report ID (238)
     0x75, 0x08,        //     Report Size (8)
     0x95, 0x30,        //     Report Count (48)
@@ -363,7 +363,7 @@
     0xB1, 0x02,        //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred
                        //     State,No Null Position,Non-volatile)
     0xC0,              //   End Collection
-    0xA1, 0x02,        //   Collection (Application)
+    0xA1, 0x02,        //   Collection (Logical)
     0x85, 0xEF,        //     Report ID (239)
     0x75, 0x08,        //     Report Size (8)
     0x95, 0x30,        //     Report Count (48)
@@ -1642,4 +1642,328 @@
 const size_t kMicrosoftXboxAdaptiveControllerSize =
     base::size(kMicrosoftXboxAdaptiveController);
 
+const uint8_t kNexusPlayerController[] = {
+    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x05,        // Usage (Game Pad)
+    0xA1, 0x01,        // Collection (Application)
+    0x85, 0x01,        //   Report ID (1)
+    0x05, 0x09,        //   Usage Page (Button)
+    0x0A, 0x01, 0x00,  //   Usage (0x01)
+    0x0A, 0x02, 0x00,  //   Usage (0x02)
+    0x0A, 0x04, 0x00,  //   Usage (0x04)
+    0x0A, 0x05, 0x00,  //   Usage (0x05)
+    0x0A, 0x07, 0x00,  //   Usage (0x07)
+    0x0A, 0x08, 0x00,  //   Usage (0x08)
+    0x0A, 0x0E, 0x00,  //   Usage (0x0E)
+    0x0A, 0x0F, 0x00,  //   Usage (0x0F)
+    0x0A, 0x0D, 0x00,  //   Usage (0x0D)
+    0x05, 0x0C,        //   Usage Page (Consumer)
+    0x0A, 0x24, 0x02,  //   Usage (AC Back)
+    0x0A, 0x23, 0x02,  //   Usage (AC Home)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x25, 0x01,        //   Logical Maximum (1)
+    0x75, 0x01,        //   Report Size (1)
+    0x95, 0x0B,        //   Report Count (11)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x75, 0x01,        //   Report Size (1)
+    0x95, 0x01,        //   Report Count (1)
+    0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
+    0x75, 0x04,        //   Report Size (4)
+    0x95, 0x01,        //   Report Count (1)
+    0x25, 0x07,        //   Logical Maximum (7)
+    0x46, 0x3B, 0x01,  //   Physical Maximum (315)
+    0x66, 0x14, 0x00,  //   Unit (System: English Rotation, Length: Centimeter)
+    0x09, 0x39,        //   Usage (Hat switch)
+    0x81, 0x42,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   Null State)
+    0x66, 0x00, 0x00,  //   Unit (None)
+    0xA1, 0x00,        //   Collection (Physical)
+    0x09, 0x30,        //     Usage (X)
+    0x09, 0x31,        //     Usage (Y)
+    0x09, 0x32,        //     Usage (Z)
+    0x09, 0x35,        //     Usage (Rz)
+    0x05, 0x02,        //     Usage Page (Sim Ctrls)
+    0x09, 0xC5,        //     Usage (Brake)
+    0x09, 0xC4,        //     Usage (Accelerator)
+    0x15, 0x00,        //     Logical Minimum (0)
+    0x26, 0xFF, 0x00,  //     Logical Maximum (255)
+    0x35, 0x00,        //     Physical Minimum (0)
+    0x46, 0xFF, 0x00,  //     Physical Maximum (255)
+    0x75, 0x08,        //     Report Size (8)
+    0x95, 0x06,        //     Report Count (6)
+    0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred
+                       //     State,No Null Position)
+    0xC0,              //   End Collection
+    0x85, 0x02,        //   Report ID (2)
+    0x05, 0x08,        //   Usage Page (LEDs)
+    0x0A, 0x01, 0x00,  //   Usage (Num Lock)
+    0x0A, 0x02, 0x00,  //   Usage (Caps Lock)
+    0x0A, 0x03, 0x00,  //   Usage (Scroll Lock)
+    0x0A, 0x04, 0x00,  //   Usage (Compose)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x25, 0x01,        //   Logical Maximum (1)
+    0x75, 0x01,        //   Report Size (1)
+    0x95, 0x04,        //   Report Count (4)
+    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position,Non-volatile)
+    0x75, 0x04,        //   Report Size (4)
+    0x95, 0x01,        //   Report Count (1)
+    0x91, 0x03,        //   Output (Const,Var,Abs,No Wrap,Linear,Preferred
+                       //   State,No Null Position,Non-volatile)
+    0xC0,              // End Collection
+    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x05,        // Usage (Game Pad)
+    0xA1, 0x01,        // Collection (Application)
+    0x85, 0x03,        //   Report ID (3)
+    0x05, 0x06,        //   Usage Page (Generic Dev Ctrls)
+    0x09, 0x20,        //   Usage (Battery Strength)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+    0x75, 0x08,        //   Report Size (8)
+    0x95, 0x01,        //   Report Count (1)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x06, 0xBC, 0xFF,  //   Usage Page (Vendor Defined 0xFFBC)
+    0x0A, 0xAD, 0xBD,  //   Usage (0xBDAD)
+    0x75, 0x08,        //   Report Size (8)
+    0x95, 0x06,        //   Report Count (6)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0xC0,              // End Collection
+    0x00,              // Unknown (bTag: 0x00, bType: 0x00)
+};
+const size_t kNexusPlayerControllerSize = base::size(kNexusPlayerController);
+
+const uint8_t kSteamControllerKeyboard[] = {
+    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x06,  // Usage (Keyboard)
+    0x95, 0x01,  // Report Count (1)
+    0xA1, 0x01,  // Collection (Application)
+    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
+    0x19, 0xE0,  //   Usage Minimum (0xE0)
+    0x29, 0xE7,  //   Usage Maximum (0xE7)
+    0x15, 0x00,  //   Logical Minimum (0)
+    0x25, 0x01,  //   Logical Maximum (1)
+    0x75, 0x01,  //   Report Size (1)
+    0x95, 0x08,  //   Report Count (8)
+    0x81, 0x02,  //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                 //   No Null Position)
+    0x95, 0x01,  //   Report Count (1)
+    0x75, 0x08,  //   Report Size (8)
+    0x81, 0x01,  //   Input (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position)
+    0x95, 0x05,  //   Report Count (5)
+    0x75, 0x01,  //   Report Size (1)
+    0x05, 0x08,  //   Usage Page (LEDs)
+    0x19, 0x01,  //   Usage Minimum (Num Lock)
+    0x29, 0x05,  //   Usage Maximum (Kana)
+    0x91, 0x02,  //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                 //   No Null Position,Non-volatile)
+    0x95, 0x01,  //   Report Count (1)
+    0x75, 0x03,  //   Report Size (3)
+    0x91, 0x01,  //   Output (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position,Non-volatile)
+    0x95, 0x06,  //   Report Count (6)
+    0x75, 0x08,  //   Report Size (8)
+    0x15, 0x00,  //   Logical Minimum (0)
+    0x25, 0x65,  //   Logical Maximum (101)
+    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
+    0x19, 0x00,  //   Usage Minimum (0x00)
+    0x29, 0x65,  //   Usage Maximum (0x65)
+    0x81, 0x00,  //   Input (Data,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position)
+    0xC0,        // End Collection
+};
+const size_t kSteamControllerKeyboardSize =
+    base::size(kSteamControllerKeyboard);
+
+const uint8_t kSteamControllerMouse[] = {
+    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x02,  // Usage (Mouse)
+    0xA1, 0x01,  // Collection (Application)
+    0x09, 0x01,  //   Usage (Pointer)
+    0xA1, 0x00,  //   Collection (Physical)
+    0x05, 0x09,  //     Usage Page (Button)
+    0x19, 0x01,  //     Usage Minimum (0x01)
+    0x29, 0x05,  //     Usage Maximum (0x05)
+    0x15, 0x00,  //     Logical Minimum (0)
+    0x25, 0x01,  //     Logical Maximum (1)
+    0x95, 0x05,  //     Report Count (5)
+    0x75, 0x01,  //     Report Size (1)
+    0x81, 0x02,  //     Input (Data,Var,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x95, 0x01,  //     Report Count (1)
+    0x75, 0x03,  //     Report Size (3)
+    0x81, 0x01,  //     Input (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x05, 0x01,  //     Usage Page (Generic Desktop Ctrls)
+    0x09, 0x30,  //     Usage (X)
+    0x09, 0x31,  //     Usage (Y)
+    0x09, 0x38,  //     Usage (Wheel)
+    0x15, 0x81,  //     Logical Minimum (-127)
+    0x25, 0x7F,  //     Logical Maximum (127)
+    0x75, 0x08,  //     Report Size (8)
+    0x95, 0x03,  //     Report Count (3)
+    0x81, 0x06,  //     Input (Data,Var,Rel,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0xC0,        //   End Collection
+    0xC0,        // End Collection
+};
+const size_t kSteamControllerMouseSize = base::size(kSteamControllerMouse);
+
+const uint8_t kSteamControllerVendor[] = {
+    0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
+    0x09, 0x01,        // Usage (0x01)
+    0xA1, 0x01,        // Collection (Application)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+    0x75, 0x08,        //   Report Size (8)
+    0x95, 0x40,        //   Report Count (64)
+    0x09, 0x01,        //   Usage (0x01)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x95, 0x40,        //   Report Count (64)
+    0x09, 0x01,        //   Usage (0x01)
+    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position,Non-volatile)
+    0x95, 0x40,        //   Report Count (64)
+    0x09, 0x01,        //   Usage (0x01)
+    0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred
+                       //   State,No Null Position,Non-volatile)
+    0xC0,              // End Collection
+};
+const size_t kSteamControllerVendorSize = base::size(kSteamControllerVendor);
+
+const uint8_t kXSkillsUsbAdapter[] = {
+    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x04,        // Usage (Joystick)
+    0xA1, 0x01,        // Collection (Application)
+    0x05, 0x09,        //   Usage Page (Button)
+    0x19, 0x01,        //   Usage Minimum (0x01)
+    0x29, 0x0C,        //   Usage Maximum (0x0C)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x25, 0x01,        //   Logical Maximum (1)
+    0x35, 0x00,        //   Physical Minimum (0)
+    0x45, 0x01,        //   Physical Maximum (1)
+    0x75, 0x01,        //   Report Size (1)
+    0x95, 0x0C,        //   Report Count (12)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x95, 0x04,        //   Report Count (4)
+    0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
+    0x09, 0x30,        //   Usage (X)
+    0x09, 0x31,        //   Usage (Y)
+    0x09, 0x35,        //   Usage (Rz)
+    0x09, 0x32,        //   Usage (Z)
+    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+    0x46, 0xFF, 0x00,  //   Physical Maximum (255)
+    0x66, 0x00, 0x00,  //   Unit (None)
+    0x75, 0x08,        //   Report Size (8)
+    0x95, 0x04,        //   Report Count (4)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x09, 0x33,        //   Usage (Rx)
+    0x09, 0x34,        //   Usage (Ry)
+    0x26, 0x0F, 0x00,  //   Logical Maximum (15)
+    0x46, 0x0F, 0x00,  //   Physical Maximum (15)
+    0x75, 0x04,        //   Report Size (4)
+    0x95, 0x02,        //   Report Count (2)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x75, 0x08,        //   Report Size (8)
+    0x06, 0x00, 0xFF,  //   Usage Page (Vendor Defined 0xFF00)
+    0x19, 0x01,        //   Usage Minimum (0x01)
+    0x29, 0x04,        //   Usage Maximum (0x04)
+    0x95, 0x04,        //   Report Count (4)
+    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position,Non-volatile)
+    0xC0,              // End Collection
+};
+const size_t kXSkillsUsbAdapterSize = base::size(kXSkillsUsbAdapter);
+
+const uint8_t kBelkinNostromoKeyboard[] = {
+    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x06,  // Usage (Keyboard)
+    0xA1, 0x01,  // Collection (Application)
+    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
+    0x19, 0xE0,  //   Usage Minimum (0xE0)
+    0x29, 0xE7,  //   Usage Maximum (0xE7)
+    0x15, 0x00,  //   Logical Minimum (0)
+    0x25, 0x01,  //   Logical Maximum (1)
+    0x75, 0x01,  //   Report Size (1)
+    0x95, 0x08,  //   Report Count (8)
+    0x81, 0x02,  //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                 //   No Null Position)
+    0x95, 0x01,  //   Report Count (1)
+    0x75, 0x08,  //   Report Size (8)
+    0x81, 0x01,  //   Input (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position)
+    0x95, 0x06,  //   Report Count (6)
+    0x75, 0x08,  //   Report Size (8)
+    0x15, 0x00,  //   Logical Minimum (0)
+    0x25, 0x65,  //   Logical Maximum (101)
+    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
+    0x19, 0x00,  //   Usage Minimum (0x00)
+    0x29, 0x65,  //   Usage Maximum (0x65)
+    0x81, 0x00,  //   Input (Data,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position)
+    0xC0,        // End Collection
+};
+const size_t kBelkinNostromoKeyboardSize = base::size(kBelkinNostromoKeyboard);
+
+const uint8_t kBelkinNostromoMouseAndExtra[] = {
+    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x02,  // Usage (Mouse)
+    0xA1, 0x01,  // Collection (Application)
+    0x09, 0x01,  //   Usage (Pointer)
+    0xA1, 0x00,  //   Collection (Physical)
+    0x05, 0x09,  //     Usage Page (Button)
+    0x19, 0x01,  //     Usage Minimum (0x01)
+    0x29, 0x03,  //     Usage Maximum (0x03)
+    0x15, 0x00,  //     Logical Minimum (0)
+    0x25, 0x01,  //     Logical Maximum (1)
+    0x95, 0x03,  //     Report Count (3)
+    0x75, 0x01,  //     Report Size (1)
+    0x81, 0x02,  //     Input (Data,Var,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x95, 0x01,  //     Report Count (1)
+    0x75, 0x05,  //     Report Size (5)
+    0x81, 0x01,  //     Input (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x05, 0x01,  //     Usage Page (Generic Desktop Ctrls)
+    0x09, 0x30,  //     Usage (X)
+    0x09, 0x31,  //     Usage (Y)
+    0x09, 0x38,  //     Usage (Wheel)
+    0x15, 0x81,  //     Logical Minimum (-127)
+    0x25, 0x7F,  //     Logical Maximum (127)
+    0x75, 0x08,  //     Report Size (8)
+    0x95, 0x03,  //     Report Count (3)
+    0x81, 0x06,  //     Input (Data,Var,Rel,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x05, 0x08,  //     Usage Page (LEDs)
+    0x19, 0x01,  //     Usage Minimum (Num Lock)
+    0x29, 0x03,  //     Usage Maximum (Scroll Lock)
+    0x15, 0x00,  //     Logical Minimum (0)
+    0x25, 0x01,  //     Logical Maximum (1)
+    0x35, 0x00,  //     Physical Minimum (0)
+    0x45, 0x01,  //     Physical Maximum (1)
+    0x75, 0x01,  //     Report Size (1)
+    0x95, 0x03,  //     Report Count (3)
+    0x91, 0x02,  //     Output (Data,Var,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position,Non-volatile)
+    0x75, 0x05,  //     Report Size (5)
+    0x95, 0x01,  //     Report Count (1)
+    0x91, 0x01,  //     Output (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position,Non-volatile)
+    0xC0,        //   End Collection
+    0xC0,        // End Collection
+};
+const size_t kBelkinNostromoMouseAndExtraSize =
+    base::size(kBelkinNostromoMouseAndExtra);
+
 }  // namespace device
diff --git a/services/device/hid/test_report_descriptors.h b/services/device/hid/test_report_descriptors.h
index 1985ce6..b116b64 100644
--- a/services/device/hid/test_report_descriptors.h
+++ b/services/device/hid/test_report_descriptors.h
@@ -54,6 +54,28 @@
 extern const uint8_t kMicrosoftXboxAdaptiveController[];
 extern const size_t kMicrosoftXboxAdaptiveControllerSize;
 
+// Nexus Player Controller descriptor
+extern const uint8_t kNexusPlayerController[];
+extern const size_t kNexusPlayerControllerSize;
+
+// Steam Controller descriptors
+extern const uint8_t kSteamControllerKeyboard[];
+extern const size_t kSteamControllerKeyboardSize;
+extern const uint8_t kSteamControllerMouse[];
+extern const size_t kSteamControllerMouseSize;
+extern const uint8_t kSteamControllerVendor[];
+extern const size_t kSteamControllerVendorSize;
+
+// XSkills Gamecube USB controller adapter descriptor
+extern const uint8_t kXSkillsUsbAdapter[];
+extern const size_t kXSkillsUsbAdapterSize;
+
+// Belkin Nostromo SpeedPad descriptors
+extern const uint8_t kBelkinNostromoKeyboard[];
+extern const size_t kBelkinNostromoKeyboardSize;
+extern const uint8_t kBelkinNostromoMouseAndExtra[];
+extern const size_t kBelkinNostromoMouseAndExtraSize;
+
 }  // namespace device
 
 #endif  // SERVICES_DEVICE_HID_TEST_REPORT_DESCRIPTORS_H_
diff --git a/services/device/public/cpp/hid/BUILD.gn b/services/device/public/cpp/hid/BUILD.gn
index 6ec1c2c..da35bf9 100644
--- a/services/device/public/cpp/hid/BUILD.gn
+++ b/services/device/public/cpp/hid/BUILD.gn
@@ -12,12 +12,18 @@
   sources = [
     "fake_input_service_linux.cc",
     "fake_input_service_linux.h",
+    "hid_collection.cc",
+    "hid_collection.h",
     "hid_device_filter.cc",
     "hid_device_filter.h",
+    "hid_item_state_table.cc",
+    "hid_item_state_table.h",
     "hid_report_descriptor.cc",
     "hid_report_descriptor.h",
     "hid_report_descriptor_item.cc",
     "hid_report_descriptor_item.h",
+    "hid_report_item.cc",
+    "hid_report_item.h",
     "hid_usage_and_page.cc",
     "hid_usage_and_page.h",
   ]
diff --git a/services/device/public/cpp/hid/fake_input_service_linux.h b/services/device/public/cpp/hid/fake_input_service_linux.h
index 0cfb825..391cf7cf 100644
--- a/services/device/public/cpp/hid/fake_input_service_linux.h
+++ b/services/device/public/cpp/hid/fake_input_service_linux.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 DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
-#define DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_FAKE_INPUT_SERVICE_LINUX_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_FAKE_INPUT_SERVICE_LINUX_H_
 
 #include <map>
 #include <string>
@@ -42,4 +42,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_FAKE_INPUT_SERVICE_LINUX_H_
diff --git a/services/device/public/cpp/hid/hid_collection.cc b/services/device/public/cpp/hid/hid_collection.cc
new file mode 100644
index 0000000..473c5cf65
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_collection.cc
@@ -0,0 +1,215 @@
+// 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/device/public/cpp/hid/hid_collection.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "services/device/public/cpp/hid/hid_item_state_table.h"
+
+namespace device {
+
+HidCollection::HidCollection(HidCollection* parent,
+                             uint32_t usage_page,
+                             uint32_t usage,
+                             uint32_t type)
+    : parent_(parent), usage_(usage, usage_page), collection_type_(type) {}
+
+HidCollection::~HidCollection() = default;
+
+// static
+std::vector<std::unique_ptr<HidCollection>> HidCollection::BuildCollections(
+    const std::vector<std::unique_ptr<HidReportDescriptorItem>>& items) {
+  std::vector<std::unique_ptr<HidCollection>> collections;
+  // This HID report descriptor parser implements a state machine described
+  // in the HID specification. See section 6.2.2 Report Descriptor.
+  HidItemStateTable state;
+  for (const auto& current_item : items) {
+    switch (current_item->tag()) {
+      case HidReportDescriptorItem::kTagCollection:
+        // Add a new collection. Collections at the top-most level describe
+        // separate components of the device and are often treated as separate
+        // devices. Nested components represent logical collections of fields
+        // within a report.
+        AddCollection(*current_item, collections, state);
+        state.local.Reset();
+        break;
+      case HidReportDescriptorItem::kTagEndCollection:
+        // Mark the end of the current collection. Subsequent items describe
+        // reports associated with the parent collection.
+        if (state.collection)
+          state.collection = state.collection->parent_;
+        state.local.Reset();
+        break;
+      case HidReportDescriptorItem::kTagInput:
+      case HidReportDescriptorItem::kTagOutput:
+      case HidReportDescriptorItem::kTagFeature:
+        // Add a report item to an input, output, or feature report within the
+        // current collection. The properties of the report item are determined
+        // by the current descriptor item and the current item state table.
+        // Changes to input, output, and feature reports are propagated to all
+        // ancestor collections.
+        if (state.collection) {
+          auto* collection = state.collection;
+          while (collection) {
+            collection->AddReportItem(current_item->tag(),
+                                      current_item->GetShortData(), state);
+            collection = collection->parent_;
+          }
+        }
+        state.local.Reset();
+        break;
+      case HidReportDescriptorItem::kTagPush:
+        // Push a copy of the current global state onto the stack. If there is
+        // no global state, the push has no effect and is ignored.
+        if (!state.global_stack.empty())
+          state.global_stack.push_back(state.global_stack.back());
+        break;
+      case HidReportDescriptorItem::kTagPop:
+        // Pop the top item of the global state stack, returning to the
+        // previously pushed state. If there is no such item, the pop has no
+        // effect and is ignored.
+        if (!state.global_stack.empty())
+          state.global_stack.pop_back();
+        break;
+      case HidReportDescriptorItem::kTagReportId:
+        // Update the current report ID. The report ID is global, but is not
+        // affected by push and pop. Changes to the report ID are propagated to
+        // all ancestor collections.
+        if (state.collection) {
+          state.report_id = current_item->GetShortData();
+          auto* collection = state.collection;
+          while (collection) {
+            collection->report_ids_.push_back(state.report_id);
+            collection = collection->parent_;
+          }
+        }
+        break;
+      case HidReportDescriptorItem::kTagUsagePage:
+      case HidReportDescriptorItem::kTagLogicalMinimum:
+      case HidReportDescriptorItem::kTagLogicalMaximum:
+      case HidReportDescriptorItem::kTagPhysicalMinimum:
+      case HidReportDescriptorItem::kTagPhysicalMaximum:
+      case HidReportDescriptorItem::kTagUnitExponent:
+      case HidReportDescriptorItem::kTagUnit:
+      case HidReportDescriptorItem::kTagReportSize:
+      case HidReportDescriptorItem::kTagReportCount:
+      case HidReportDescriptorItem::kTagUsage:
+      case HidReportDescriptorItem::kTagUsageMinimum:
+      case HidReportDescriptorItem::kTagUsageMaximum:
+      case HidReportDescriptorItem::kTagDesignatorIndex:
+      case HidReportDescriptorItem::kTagDesignatorMinimum:
+      case HidReportDescriptorItem::kTagDesignatorMaximum:
+      case HidReportDescriptorItem::kTagStringIndex:
+      case HidReportDescriptorItem::kTagStringMinimum:
+      case HidReportDescriptorItem::kTagStringMaximum:
+      case HidReportDescriptorItem::kTagDelimiter:
+        // Update the value associated with a local or global item in the item
+        // state table.
+        state.SetItemValue(current_item->tag(), current_item->GetShortData());
+        break;
+      default:
+        break;
+    }
+  }
+  return collections;
+}
+
+// static
+void HidCollection::AddCollection(
+    const HidReportDescriptorItem& item,
+    std::vector<std::unique_ptr<HidCollection>>& collections,
+    HidItemStateTable& state) {
+  // Extract |usage| and |usage_page| from the current state. The usage page may
+  // be set either by a global usage page, or in the high-order bytes of a local
+  // usage value. When both are provided, the local usage value takes
+  // precedence.
+  uint32_t usage = state.local.usages.empty() ? 0 : state.local.usages.front();
+  uint32_t usage_page = (usage >> 16) & 0xffff;
+  if (usage_page == 0 && !state.global_stack.empty())
+    usage_page = state.global_stack.back().usage_page;
+  // Create the new collection. If it is a child of another collection, append
+  // it to that collection's list of children. Otherwise, append it to the list
+  // of top-level collections in |collections|.
+  uint32_t collection_type = item.GetShortData();
+  auto collection = std::make_unique<HidCollection>(
+      state.collection, usage_page, usage, collection_type);
+  if (state.collection) {
+    state.collection->children_.push_back(std::move(collection));
+    state.collection = state.collection->children_.back().get();
+  } else {
+    collections.push_back(std::move(collection));
+    state.collection = collections.back().get();
+  }
+}
+
+void HidCollection::AddChildForTesting(
+    std::unique_ptr<HidCollection> collection) {
+  children_.push_back(std::move(collection));
+}
+
+void HidCollection::AddReportItem(HidReportDescriptorItem::Tag tag,
+                                  uint32_t report_info,
+                                  const HidItemStateTable& state) {
+  // Get the correct report map for the current report item (input, output,
+  // or feature). The new item will be appended to a report in this report map.
+  std::unordered_map<uint8_t, HidReport>* reports = nullptr;
+  if (tag == HidReportDescriptorItem::kTagInput)
+    reports = &input_reports_;
+  else if (tag == HidReportDescriptorItem::kTagOutput)
+    reports = &output_reports_;
+  else if (tag == HidReportDescriptorItem::kTagFeature)
+    reports = &feature_reports_;
+  else
+    return;
+  // Fetch the report with the |report_id| matching this item, or insert a new
+  // report into the map if it does not yet exist.
+  HidReport* report = nullptr;
+  auto find_it = reports->find(state.report_id);
+  if (find_it == reports->end()) {
+    auto emplace_result = reports->emplace(state.report_id, HidReport());
+    report = &emplace_result.first->second;
+  } else {
+    report = &find_it->second;
+  }
+  // Create the report item and append it to the report.
+  report->push_back(HidReportItem::Create(tag, report_info, state));
+}
+
+mojom::HidCollectionInfoPtr HidCollection::GetDetails(
+    size_t* max_input_report_bits,
+    size_t* max_output_report_bits,
+    size_t* max_feature_report_bits) {
+  DCHECK(max_input_report_bits);
+  DCHECK(max_output_report_bits);
+  DCHECK(max_feature_report_bits);
+  struct {
+    const std::unordered_map<uint8_t, HidReport>& reports;
+    size_t& max_report_bits;
+  } report_lists[]{
+      {input_reports_, *max_input_report_bits},
+      {output_reports_, *max_output_report_bits},
+      {feature_reports_, *max_feature_report_bits},
+  };
+  auto collection_info = mojom::HidCollectionInfo::New();
+  collection_info->usage =
+      mojom::HidUsageAndPage::New(usage_.usage, usage_.usage_page);
+  collection_info->report_ids.insert(collection_info->report_ids.end(),
+                                     report_ids_.begin(), report_ids_.end());
+  for (const auto& entry : report_lists) {
+    entry.max_report_bits = 0;
+    for (const auto& report : entry.reports) {
+      size_t report_bits = 0;
+      for (const auto& item : report.second)
+        report_bits += item->GetReportSize() * item->GetReportCount();
+      entry.max_report_bits = std::max(entry.max_report_bits, report_bits);
+    }
+  }
+  return collection_info;
+}
+
+}  // namespace device
diff --git a/services/device/public/cpp/hid/hid_collection.h b/services/device/public/cpp/hid/hid_collection.h
new file mode 100644
index 0000000..4f964a0
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_collection.h
@@ -0,0 +1,109 @@
+// 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_DEVICE_PUBLIC_CPP_HID_HID_COLLECTION_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_COLLECTION_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
+#include "services/device/public/cpp/hid/hid_report_item.h"
+#include "services/device/public/mojom/hid.mojom.h"
+
+namespace device {
+
+class HidItemStateTable;
+
+// Information about a single HID collection.
+class HidCollection {
+ public:
+  using HidReport = std::vector<std::unique_ptr<HidReportItem>>;
+
+  HidCollection(HidCollection* parent,
+                uint32_t usage_page,
+                uint32_t usage,
+                uint32_t collection_type);
+  ~HidCollection();
+
+  static std::vector<std::unique_ptr<HidCollection>> BuildCollections(
+      const std::vector<std::unique_ptr<HidReportDescriptorItem>>& items);
+
+  uint16_t GetUsagePage() const { return usage_.usage_page; }
+
+  uint16_t GetUsage() const { return usage_.usage; }
+
+  uint32_t GetCollectionType() const { return collection_type_; }
+
+  // Returns true if there are one or more report IDs associated with this
+  // collection.
+  bool HasReportId() const { return !report_ids_.empty(); }
+
+  // Returns information about the collection.
+  mojom::HidCollectionInfoPtr GetDetails(size_t* max_input_report_bits,
+                                         size_t* max_output_report_bits,
+                                         size_t* max_feature_report_bits);
+
+  const HidCollection* GetParent() const { return parent_; }
+
+  const std::vector<std::unique_ptr<HidCollection>>& GetChildren() const {
+    return children_;
+  }
+
+  const std::unordered_map<uint8_t, HidReport>& GetInputReports() const {
+    return input_reports_;
+  }
+
+  const std::unordered_map<uint8_t, HidReport>& GetOutputReports() const {
+    return output_reports_;
+  }
+
+  const std::unordered_map<uint8_t, HidReport>& GetFeatureReports() const {
+    return feature_reports_;
+  }
+
+  // Exposed for testing.
+  void AddChildForTesting(std::unique_ptr<HidCollection> child);
+  void AddReportItem(const HidReportDescriptorItem::Tag tag,
+                     uint32_t report_info,
+                     const HidItemStateTable& state);
+
+ private:
+  static void AddCollection(
+      const HidReportDescriptorItem& item,
+      std::vector<std::unique_ptr<HidCollection>>& collections,
+      HidItemStateTable& state);
+
+  // The parent collection, or nullptr if this is a top level collection.
+  HidCollection* const parent_;
+
+  // The children of this collection in the order they were encountered in the
+  // report descriptor.
+  std::vector<std::unique_ptr<HidCollection>> children_;
+
+  // The usage page and usage ID associated with this collection.
+  const mojom::HidUsageAndPage usage_;
+
+  // The type of this collection. Stored as an integer type rather than an enum
+  // to preserve reserved and vendor-defined values.
+  const uint32_t collection_type_;
+
+  // The sequence of report IDs associated with this collection in the order
+  // they were encountered in the report descriptor.
+  std::vector<uint8_t> report_ids_;
+
+  // Maps from report IDs to sequences of report items. Reports are divided by
+  // type (input, output, or feature).
+  std::unordered_map<uint8_t, HidReport> input_reports_;
+  std::unordered_map<uint8_t, HidReport> output_reports_;
+  std::unordered_map<uint8_t, HidReport> feature_reports_;
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_COLLECTION_H_
diff --git a/services/device/public/cpp/hid/hid_device_filter.h b/services/device/public/cpp/hid/hid_device_filter.h
index 431d8a47..bdb9c2e 100644
--- a/services/device/public/cpp/hid/hid_device_filter.h
+++ b/services/device/public/cpp/hid/hid_device_filter.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 DEVICE_HID_HID_DEVICE_FILTER_H_
-#define DEVICE_HID_HID_DEVICE_FILTER_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_DEVICE_FILTER_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_DEVICE_FILTER_H_
 
 #include <stdint.h>
 #include <vector>
@@ -41,4 +41,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_HID_HID_DEVICE_FILTER_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_DEVICE_FILTER_H_
diff --git a/services/device/public/cpp/hid/hid_item_state_table.cc b/services/device/public/cpp/hid/hid_item_state_table.cc
new file mode 100644
index 0000000..6acb2cb
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_item_state_table.cc
@@ -0,0 +1,153 @@
+// 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/device/public/cpp/hid/hid_item_state_table.h"
+
+#include <limits>
+
+namespace device {
+
+namespace {
+
+bool IsGlobalItem(HidReportDescriptorItem::Tag tag) {
+  switch (tag) {
+    case HidReportDescriptorItem::kTagUsagePage:
+    case HidReportDescriptorItem::kTagLogicalMinimum:
+    case HidReportDescriptorItem::kTagLogicalMaximum:
+    case HidReportDescriptorItem::kTagPhysicalMinimum:
+    case HidReportDescriptorItem::kTagPhysicalMaximum:
+    case HidReportDescriptorItem::kTagUnitExponent:
+    case HidReportDescriptorItem::kTagUnit:
+    case HidReportDescriptorItem::kTagReportSize:
+    case HidReportDescriptorItem::kTagReportId:
+    case HidReportDescriptorItem::kTagReportCount:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
+uint32_t MaybeCombineUsageAndUsagePage(
+    uint32_t usage,
+    const std::vector<HidItemStateTable::HidGlobalItemState>& global_stack) {
+  // Check if the usage value already has a usage page in the upper bytes.
+  if (usage > std::numeric_limits<uint16_t>::max())
+    return usage;
+  // No global state, just return the usage value.
+  if (global_stack.empty())
+    return usage;
+  // Combine the global usage page with the usage value.
+  return (global_stack.back().usage_page << (sizeof(uint16_t) * 8)) | usage;
+}
+
+}  // namespace
+
+HidItemStateTable::HidItemStateTable() = default;
+HidItemStateTable::~HidItemStateTable() = default;
+
+void HidItemStateTable::SetItemValue(HidReportDescriptorItem::Tag tag,
+                                     uint32_t value) {
+  if (IsGlobalItem(tag)) {
+    if (global_stack.empty())
+      global_stack.emplace_back();
+    auto& global = global_stack.back();
+    switch (tag) {
+      case HidReportDescriptorItem::kTagUsagePage:
+        global.usage_page = value;
+        break;
+      case HidReportDescriptorItem::kTagLogicalMinimum:
+        global.logical_minimum = int32_t{value};
+        break;
+      case HidReportDescriptorItem::kTagLogicalMaximum:
+        global.logical_maximum = int32_t{value};
+        break;
+      case HidReportDescriptorItem::kTagPhysicalMinimum:
+        global.physical_minimum = int32_t{value};
+        break;
+      case HidReportDescriptorItem::kTagPhysicalMaximum:
+        global.physical_maximum = int32_t{value};
+        break;
+      case HidReportDescriptorItem::kTagUnitExponent:
+        global.unit_exponent = value;
+        break;
+      case HidReportDescriptorItem::kTagUnit:
+        global.unit = value;
+        break;
+      case HidReportDescriptorItem::kTagReportSize:
+        global.report_size = value;
+        break;
+      case HidReportDescriptorItem::kTagReportCount:
+        global.report_count = value;
+        break;
+      default:
+        NOTREACHED() << "Unexpected global item in HID report descriptor";
+        break;
+    }
+  } else {
+    switch (tag) {
+      case HidReportDescriptorItem::kTagUsage:
+        local.usages.push_back(
+            MaybeCombineUsageAndUsagePage(value, global_stack));
+        break;
+      case HidReportDescriptorItem::kTagUsageMinimum:
+        local.usage_minimum =
+            MaybeCombineUsageAndUsagePage(value, global_stack);
+        break;
+      case HidReportDescriptorItem::kTagUsageMaximum:
+        local.usage_maximum =
+            MaybeCombineUsageAndUsagePage(value, global_stack);
+        break;
+      case HidReportDescriptorItem::kTagDesignatorIndex:
+        local.designator_index = value;
+        break;
+      case HidReportDescriptorItem::kTagDesignatorMinimum:
+        local.designator_minimum = value;
+        break;
+      case HidReportDescriptorItem::kTagDesignatorMaximum:
+        local.designator_maximum = value;
+        break;
+      case HidReportDescriptorItem::kTagStringIndex:
+        local.string_index = value;
+        break;
+      case HidReportDescriptorItem::kTagStringMinimum:
+        local.string_minimum = value;
+        break;
+      case HidReportDescriptorItem::kTagStringMaximum:
+        local.string_maximum = value;
+        break;
+      case HidReportDescriptorItem::kTagDelimiter:
+        local.delimiter = value;
+        break;
+      default:
+        NOTREACHED() << "Unexpected local item in HID report descriptor";
+        break;
+    }
+  }
+}
+
+HidItemStateTable::HidGlobalItemState::HidGlobalItemState() = default;
+HidItemStateTable::HidGlobalItemState::HidGlobalItemState(
+    const HidGlobalItemState&) = default;
+HidItemStateTable::HidGlobalItemState::~HidGlobalItemState() = default;
+
+HidItemStateTable::HidLocalItemState::HidLocalItemState() = default;
+HidItemStateTable::HidLocalItemState::HidLocalItemState(
+    const HidLocalItemState&) = default;
+HidItemStateTable::HidLocalItemState::~HidLocalItemState() = default;
+
+void HidItemStateTable::HidLocalItemState::Reset() {
+  usages.clear();
+  usage_minimum = 0;
+  usage_maximum = 0;
+  designator_index = 0;
+  designator_minimum = 0;
+  designator_maximum = 0;
+  string_index = 0;
+  string_minimum = 0;
+  string_maximum = 0;
+  delimiter = 0;
+}
+
+}  // namespace device
diff --git a/services/device/public/cpp/hid/hid_item_state_table.h b/services/device/public/cpp/hid/hid_item_state_table.h
new file mode 100644
index 0000000..2f6ff56
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_item_state_table.h
@@ -0,0 +1,85 @@
+// 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_DEVICE_PUBLIC_CPP_HID_HID_ITEM_STATE_TABLE_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_ITEM_STATE_TABLE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
+#include "services/device/public/mojom/hid.mojom.h"
+
+namespace device {
+
+class HidCollection;
+
+// The item state table, used when parsing the HID report descriptor.
+class HidItemStateTable {
+ public:
+  class HidGlobalItemState {
+   public:
+    HidGlobalItemState();
+    HidGlobalItemState(const HidGlobalItemState&);
+    ~HidGlobalItemState();
+
+    // Global items. See section 6.2.2.7 of the HID specifications.
+    uint32_t usage_page = mojom::kPageUndefined;
+    int32_t logical_minimum = 0;
+    int32_t logical_maximum = 0;
+    int32_t physical_minimum = 0;
+    int32_t physical_maximum = 0;
+    uint32_t unit_exponent = 0;
+    uint32_t unit = 0;
+    uint32_t report_size = 0;
+    uint32_t report_count = 0;
+  };
+
+  class HidLocalItemState {
+   public:
+    HidLocalItemState();
+    HidLocalItemState(const HidLocalItemState&);
+    ~HidLocalItemState();
+
+    void Reset();
+
+    // Local items. See section 6.2.2.6 of the HID specifications.
+    std::vector<uint32_t> usages;
+    uint32_t usage_minimum = 0;
+    uint32_t usage_maximum = 0;
+    uint32_t designator_index = 0;
+    uint32_t designator_minimum = 0;
+    uint32_t designator_maximum = 0;
+    uint32_t string_index = 0;
+    uint32_t string_minimum = 0;
+    uint32_t string_maximum = 0;
+    uint32_t delimiter = 0;
+  };
+
+  HidItemStateTable();
+  ~HidItemStateTable();
+
+  // Set the value of a local or global item.
+  void SetItemValue(HidReportDescriptorItem::Tag tag, uint32_t value);
+
+  // The collection that will be modified when main items are encountered.
+  HidCollection* collection = nullptr;
+
+  // The report ID is part of the global item state but is not affected by push
+  // or pop items.
+  uint32_t report_id = 0;
+
+  // The global item state. The global state is represented as a stack in order
+  // to handle push and pop items. The last element holds the current state.
+  std::vector<HidGlobalItemState> global_stack;
+
+  // The local item state.
+  HidLocalItemState local;
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_ITEM_STATE_TABLE_H_
diff --git a/services/device/public/cpp/hid/hid_report_descriptor.cc b/services/device/public/cpp/hid/hid_report_descriptor.cc
index ca71cdbe..22d3f06e 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor.cc
+++ b/services/device/public/cpp/hid/hid_report_descriptor.cc
@@ -4,7 +4,10 @@
 
 #include "services/device/public/cpp/hid/hid_report_descriptor.h"
 
-#include "base/memory/ptr_util.h"
+#include <algorithm>
+#include <limits>
+#include <utility>
+
 #include "base/stl_util.h"
 
 namespace device {
@@ -19,11 +22,11 @@
   size_t header_index = 0;
   HidReportDescriptorItem* item = nullptr;
   while (header_index < bytes.size()) {
-    item = new HidReportDescriptorItem(&bytes[header_index],
-                                       bytes.size() - header_index, item);
-    items_.push_back(base::WrapUnique(item));
-    header_index += item->GetSize();
+    items_.push_back(HidReportDescriptorItem::Create(
+        &bytes[header_index], bytes.size() - header_index, item));
+    header_index += items_.back()->GetSize();
   }
+  collections_ = HidCollection::BuildCollections(items_);
 }
 
 HidReportDescriptor::~HidReportDescriptor() {}
@@ -31,126 +34,37 @@
 void HidReportDescriptor::GetDetails(
     std::vector<mojom::HidCollectionInfoPtr>* top_level_collections,
     bool* has_report_id,
-    size_t* max_input_report_size,
-    size_t* max_output_report_size,
-    size_t* max_feature_report_size) {
+    size_t* max_input_report_bytes,
+    size_t* max_output_report_bytes,
+    size_t* max_feature_report_bytes) const {
   DCHECK(top_level_collections);
-  DCHECK(max_input_report_size);
-  DCHECK(max_output_report_size);
-  DCHECK(max_feature_report_size);
+  DCHECK(has_report_id);
+  DCHECK(max_input_report_bytes);
+  DCHECK(max_output_report_bytes);
+  DCHECK(max_feature_report_bytes);
   base::STLClearObject(top_level_collections);
 
+  size_t max_input_report_bits = 0;
+  size_t max_output_report_bits = 0;
+  size_t max_feature_report_bits = 0;
   *has_report_id = false;
-  *max_input_report_size = 0;
-  *max_output_report_size = 0;
-  *max_feature_report_size = 0;
-
-  // Global tags data:
-  auto current_usage_page = mojom::kPageUndefined;
-  size_t current_report_count = 0;
-  size_t cached_report_count = 0;
-  size_t current_report_size = 0;
-  size_t cached_report_size = 0;
-  size_t current_input_report_size = 0;
-  size_t current_output_report_size = 0;
-  size_t current_feature_report_size = 0;
-
-  // Local tags data:
-  uint32_t current_usage = 0;
-
-  for (const auto& current_item : items()) {
-    switch (current_item->tag()) {
-      // Main tags:
-      case HidReportDescriptorItem::kTagCollection:
-        if (!current_item->parent() &&
-            (current_usage <= std::numeric_limits<uint16_t>::max())) {
-          // This is a top-level collection.
-          auto collection = mojom::HidCollectionInfo::New();
-          collection->usage = mojom::HidUsageAndPage::New(
-              static_cast<uint16_t>(current_usage),
-              static_cast<uint16_t>(current_usage_page));
-          top_level_collections->push_back(std::move(collection));
-        }
-        break;
-      case HidReportDescriptorItem::kTagInput:
-        current_input_report_size += current_report_count * current_report_size;
-        break;
-      case HidReportDescriptorItem::kTagOutput:
-        current_output_report_size +=
-            current_report_count * current_report_size;
-        break;
-      case HidReportDescriptorItem::kTagFeature:
-        current_feature_report_size +=
-            current_report_count * current_report_size;
-        break;
-
-      // Global tags:
-      case HidReportDescriptorItem::kTagUsagePage:
-        current_usage_page = current_item->GetShortData();
-        break;
-      case HidReportDescriptorItem::kTagReportId:
-        if (top_level_collections->size() > 0) {
-          // Store report ID.
-          top_level_collections->back()->report_ids.push_back(
-              current_item->GetShortData());
-          *has_report_id = true;
-
-          // Update max report sizes.
-          *max_input_report_size =
-              std::max(*max_input_report_size, current_input_report_size);
-          *max_output_report_size =
-              std::max(*max_output_report_size, current_output_report_size);
-          *max_feature_report_size =
-              std::max(*max_feature_report_size, current_feature_report_size);
-
-          // Reset the report sizes for the next report ID.
-          current_input_report_size = 0;
-          current_output_report_size = 0;
-          current_feature_report_size = 0;
-        }
-        break;
-      case HidReportDescriptorItem::kTagReportCount:
-        current_report_count = current_item->GetShortData();
-        break;
-      case HidReportDescriptorItem::kTagReportSize:
-        current_report_size = current_item->GetShortData();
-        break;
-      case HidReportDescriptorItem::kTagPush:
-        // Cache report count and size.
-        cached_report_count = current_report_count;
-        cached_report_size = current_report_size;
-        break;
-      case HidReportDescriptorItem::kTagPop:
-        // Restore cache.
-        current_report_count = cached_report_count;
-        current_report_size = cached_report_size;
-        // Reset cache.
-        cached_report_count = 0;
-        cached_report_size = 0;
-        break;
-
-      // Local tags:
-      case HidReportDescriptorItem::kTagUsage:
-        current_usage = current_item->GetShortData();
-        break;
-
-      default:
-        break;
-    }
+  for (const auto& collection : collections_) {
+    size_t input_bits;
+    size_t output_bits;
+    size_t feature_bits;
+    top_level_collections->push_back(
+        collection->GetDetails(&input_bits, &output_bits, &feature_bits));
+    if (collection->HasReportId())
+      *has_report_id = true;
+    max_input_report_bits = std::max(max_input_report_bits, input_bits);
+    max_output_report_bits = std::max(max_output_report_bits, output_bits);
+    max_feature_report_bits = std::max(max_feature_report_bits, feature_bits);
   }
 
-  // Update max report sizes
-  *max_input_report_size =
-      std::max(*max_input_report_size, current_input_report_size);
-  *max_output_report_size =
-      std::max(*max_output_report_size, current_output_report_size);
-  *max_feature_report_size =
-      std::max(*max_feature_report_size, current_feature_report_size);
-
-  // Convert bits into bytes
-  *max_input_report_size /= kBitsPerByte;
-  *max_output_report_size /= kBitsPerByte;
-  *max_feature_report_size /= kBitsPerByte;
+  // Convert bits into bytes.
+  *max_input_report_bytes = max_input_report_bits / kBitsPerByte;
+  *max_output_report_bytes = max_output_report_bits / kBitsPerByte;
+  *max_feature_report_bytes = max_feature_report_bits / kBitsPerByte;
 }
 
 }  // namespace device
diff --git a/services/device/public/cpp/hid/hid_report_descriptor.h b/services/device/public/cpp/hid/hid_report_descriptor.h
index 337ea6a..650558d5 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor.h
+++ b/services/device/public/cpp/hid/hid_report_descriptor.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 DEVICE_HID_HID_REPORT_DESCRIPTOR_H_
-#define DEVICE_HID_HID_REPORT_DESCRIPTOR_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -11,6 +11,7 @@
 #include <memory>
 #include <vector>
 
+#include "services/device/public/cpp/hid/hid_collection.h"
 #include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
 #include "services/device/public/mojom/hid.mojom.h"
 
@@ -27,19 +28,29 @@
     return items_;
   }
 
-  // Returns top-level collections present in the descriptor,
-  // together with max report sizes
+  const std::vector<std::unique_ptr<HidCollection>>& collections() const {
+    return collections_;
+  }
+
+  // Return the top-level collections present in the descriptor,
+  // together with max report sizes.
   void GetDetails(
       std::vector<mojom::HidCollectionInfoPtr>* top_level_collections,
       bool* has_report_id,
-      size_t* max_input_report_size,
-      size_t* max_output_report_size,
-      size_t* max_feature_report_size);
+      size_t* max_input_report_bytes,
+      size_t* max_output_report_bytes,
+      size_t* max_feature_report_bytes) const;
 
  private:
+  // An ordered sequence of HidReportDescriptorItem objects representing the
+  // items that make up a HID report descriptor.
   std::vector<std::unique_ptr<HidReportDescriptorItem>> items_;
+
+  // A hierarchichal representation of the collections and reports described by
+  // the HID report descriptor.
+  std::vector<std::unique_ptr<HidCollection>> collections_;
 };
 
 }  // namespace device
 
-#endif  // DEVICE_HID_HID_REPORT_DESCRIPTOR_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_H_
diff --git a/services/device/public/cpp/hid/hid_report_descriptor_item.h b/services/device/public/cpp/hid/hid_report_descriptor_item.h
index 7f7601fae..8b1a64c7e 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor_item.h
+++ b/services/device/public/cpp/hid/hid_report_descriptor_item.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
-#define DEVICE_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
 
 #include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
+
 namespace device {
 
 // An element of a HID report descriptor.
 class HidReportDescriptorItem {
  private:
-  friend class HidReportDescriptor;
-
   enum Type {
     kTypeMain = 0,
     kTypeGlobal = 1,
@@ -100,7 +100,11 @@
   // Can be retrieved from GetShortData()
   // when item.tag() == HidReportDescriptorItem::kTagInput
   // or HidReportDescriptorItem::kTagOutput
-  // or HidReportDescriptorItem::kTagFeature
+  // or HidReportDescriptorItem::kTagFeature.
+  // The ReportInfo struct matches the layout of the bitfield defined in section
+  // 6.2.2.5 of the Device Class Definition for HID v1.11. Pad to 32-bits so it
+  // can be safely cast to and from uint32_t.
+#pragma pack(push, 1)
   struct ReportInfo {
     uint8_t data_or_constant : 1;
     uint8_t array_or_variable : 1;
@@ -109,10 +113,14 @@
     uint8_t linear : 1;
     uint8_t preferred : 1;
     uint8_t null : 1;
-    uint8_t reserved_1 : 1;
+    uint8_t is_volatile : 1;
     uint8_t bit_field_or_buffer : 1;
-    uint8_t reserved_2 : 1;
+    uint8_t reserved : 7;
+    uint8_t reserved2[2];
   };
+#pragma pack(pop)
+  static_assert(sizeof(ReportInfo) == sizeof(uint32_t),
+                "incorrect report info size");
 
   // HID collection type.
   // Can be retrieved from GetShortData()
@@ -137,6 +145,12 @@
  public:
   ~HidReportDescriptorItem() {}
 
+  static std::unique_ptr<HidReportDescriptorItem>
+  Create(const uint8_t* bytes, size_t size, HidReportDescriptorItem* previous) {
+    return std::unique_ptr<HidReportDescriptorItem>(
+        new HidReportDescriptorItem(bytes, size, previous));
+  }
+
   // Previous element in report descriptor.
   // Owned by descriptor instance.
   HidReportDescriptorItem* previous() const { return previous_; };
@@ -158,13 +172,14 @@
   // Raw data of a short item.
   // Not valid for a long item.
   uint32_t GetShortData() const;
+  // Size of this item in bytes, including the header.
+  size_t GetSize() const;
 
   static CollectionType GetCollectionTypeFromValue(uint32_t value);
 
  private:
   size_t GetHeaderSize() const;
   size_t payload_size() const { return payload_size_; }
-  size_t GetSize() const;
 
   HidReportDescriptorItem* previous_;
   HidReportDescriptorItem* next_;
@@ -176,4 +191,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
diff --git a/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc b/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
index 9fa56aa..3f63b6a 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
+++ b/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
@@ -5,43 +5,330 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <limits>
 #include <sstream>
+#include <unordered_map>
+#include <utility>
 
 #include "base/macros.h"
 #include "services/device/hid/test_report_descriptors.h"
 #include "services/device/public/cpp/hid/hid_report_descriptor.h"
+#include "services/device/public/cpp/hid/hid_usage_and_page.h"
 #include "services/device/public/mojom/hid.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace device {
 
+namespace {
+using HidReport = std::vector<std::unique_ptr<HidReportItem>>;
+using HidReportMap = std::unordered_map<uint8_t, HidReport>;
+using HidCollectionVector = std::vector<std::unique_ptr<HidCollection>>;
+
+// HID unit values.
+const uint32_t kUnitCandela = 0x010000e1;
+const uint32_t kUnitDegrees = 0x14;
+const uint32_t kUnitInch = 0x13;
+const uint32_t kUnitNewton = 0xe111;
+const uint32_t kUnitSecond = 0x1001;
+
+// Report info bitfield values. The bits are:
+//   bit 0: Data (0) | Constant (1)
+//   bit 1: Array (0) | Variable (1)
+//   bit 2: Absolute (0) | Relative (1)
+//   bit 3: No Wrap (0) | Wrap (1)
+//   bit 4: Linear (0) | Non-Linear (1)
+//   bit 5: Preferred State (0) | No Preferred State (1)
+//   bit 6: No Null Value (0) | Has Null Value (1)
+//   bit 7: Non-Volatile (0) | Volatile (1)
+//   bit 8: Bit Field (0) | Buffered Bytes (1)
+const uint16_t kNonNullableArray = 0x0000;
+const uint16_t kConstantArray = 0x0001;
+const uint16_t kAbsoluteVariable = 0x0002;
+const uint16_t kConstant = 0x0003;
+const uint16_t kRelativeVariable = 0x0006;
+const uint16_t kNonLinearVariable = 0x0012;
+const uint16_t kNullableArray = 0x0040;
+const uint16_t kNullableAbsoluteVariable = 0x0042;
+const uint16_t kVolatileConstant = 0x0083;
+const uint16_t kBufferedBytes = 0x0102;
+
+// Vendor usage pages.
+const uint16_t kPageVendor02 = mojom::kPageVendor + 0x02;
+const uint16_t kPageVendor05 = mojom::kPageVendor + 0x05;
+const uint16_t kPageVendor80 = mojom::kPageVendor + 0x80;
+
+// Bit-width and mask for the usage ID field in a 32-bit usage value.
+const size_t kUsageIdSizeBits = sizeof(uint16_t) * 8;
+const uint32_t kUsageIdMask = std::numeric_limits<uint16_t>::max();
+
+// Combined usage page and usage ID values. The usage page occupies the high 16
+// bits, the usage ID occupies the low 16 bits.
+const uint32_t kUsageButton = (mojom::kPageButton << kUsageIdSizeBits);
+const uint32_t kUsageConsumer = (mojom::kPageConsumer << kUsageIdSizeBits);
+const uint32_t kUsageConsumerACBack = kUsageConsumer | 0x0224;
+const uint32_t kUsageConsumerACHome = kUsageConsumer | 0x0223;
+const uint32_t kUsageConsumerControl = kUsageConsumer | 0x01;
+const uint32_t kUsageConsumerModeStep = kUsageConsumer | 0x82;
+const uint32_t kUsageDigitizer = (mojom::kPageDigitizer << kUsageIdSizeBits);
+const uint32_t kUsageDigitizerDigitizer = kUsageDigitizer | 0x01;
+const uint32_t kUsageDigitizerBarrelSwitch = kUsageDigitizer | 0x44;
+const uint32_t kUsageDigitizerInRange = kUsageDigitizer | 0x32;
+const uint32_t kUsageDigitizerPuck = kUsageDigitizer | 0x21;
+const uint32_t kUsageDigitizerStylus = kUsageDigitizer | 0x20;
+const uint32_t kUsageDigitizerTipPressure = kUsageDigitizer | 0x30;
+const uint32_t kUsageDigitizerTipSwitch = kUsageDigitizer | 0x42;
+const uint32_t kUsageGenericDesktop =
+    (mojom::kPageGenericDesktop << kUsageIdSizeBits);
+const uint32_t kUsageGenericDesktopDial =
+    kUsageGenericDesktop | mojom::kGenericDesktopDial;
+const uint32_t kUsageGenericDesktopGamePad =
+    kUsageGenericDesktop | mojom::kGenericDesktopGamePad;
+const uint32_t kUsageGenericDesktopHatSwitch =
+    kUsageGenericDesktop | mojom::kGenericDesktopHatSwitch;
+const uint32_t kUsageGenericDesktopJoystick =
+    kUsageGenericDesktop | mojom::kGenericDesktopJoystick;
+const uint32_t kUsageGenericDesktopKeyboard =
+    kUsageGenericDesktop | mojom::kGenericDesktopKeyboard;
+const uint32_t kUsageGenericDesktopMouse =
+    kUsageGenericDesktop | mojom::kGenericDesktopMouse;
+const uint32_t kUsageGenericDesktopPointer =
+    kUsageGenericDesktop | mojom::kGenericDesktopPointer;
+const uint32_t kUsageGenericDesktopRx =
+    kUsageGenericDesktop | mojom::kGenericDesktopRx;
+const uint32_t kUsageGenericDesktopRy =
+    kUsageGenericDesktop | mojom::kGenericDesktopRy;
+const uint32_t kUsageGenericDesktopRz =
+    kUsageGenericDesktop | mojom::kGenericDesktopRz;
+const uint32_t kUsageGenericDesktopSystemControl =
+    kUsageGenericDesktop | mojom::kGenericDesktopSystemControl;
+const uint32_t kUsageGenericDesktopSystemMainMenu =
+    kUsageGenericDesktop | mojom::kGenericDesktopSystemMainMenu;
+const uint32_t kUsageGenericDesktopVbrx =
+    kUsageGenericDesktop | mojom::kGenericDesktopVbrx;
+const uint32_t kUsageGenericDesktopVbry =
+    kUsageGenericDesktop | mojom::kGenericDesktopVbry;
+const uint32_t kUsageGenericDesktopVbrz =
+    kUsageGenericDesktop | mojom::kGenericDesktopVbrz;
+const uint32_t kUsageGenericDesktopVx =
+    kUsageGenericDesktop | mojom::kGenericDesktopVx;
+const uint32_t kUsageGenericDesktopVy =
+    kUsageGenericDesktop | mojom::kGenericDesktopVy;
+const uint32_t kUsageGenericDesktopVz =
+    kUsageGenericDesktop | mojom::kGenericDesktopVz;
+const uint32_t kUsageGenericDesktopWheel =
+    kUsageGenericDesktop | mojom::kGenericDesktopWheel;
+const uint32_t kUsageGenericDesktopX =
+    kUsageGenericDesktop | mojom::kGenericDesktopX;
+const uint32_t kUsageGenericDesktopY =
+    kUsageGenericDesktop | mojom::kGenericDesktopY;
+const uint32_t kUsageGenericDesktopZ =
+    kUsageGenericDesktop | mojom::kGenericDesktopZ;
+const uint32_t kUsageGenericDeviceBatteryStrength =
+    (mojom::kPageGenericDevice << kUsageIdSizeBits) | 0x20;
+const uint32_t kUsageKeyboard = (mojom::kPageKeyboard << kUsageIdSizeBits);
+const uint32_t kUsageKeyboardApplication = kUsageKeyboard | 0x65;
+const uint32_t kUsageKeyboardLeftControl = kUsageKeyboard | 0xe0;
+const uint32_t kUsageKeyboardRightGui = kUsageKeyboard | 0xe7;
+const uint32_t kUsageLedNumLock = (mojom::kPageLed << kUsageIdSizeBits) | 0x01;
+const uint32_t kUsageLedCapsLock = (mojom::kPageLed << kUsageIdSizeBits) | 0x02;
+const uint32_t kUsageLedScrollLock =
+    (mojom::kPageLed << kUsageIdSizeBits) | 0x03;
+const uint32_t kUsageLedCompose = (mojom::kPageLed << kUsageIdSizeBits) | 0x04;
+const uint32_t kUsageLedKana = (mojom::kPageLed << kUsageIdSizeBits) | 0x05;
+const uint32_t kUsageMonitorControl =
+    (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x01;
+const uint32_t kUsageMonitorEdidInfo =
+    (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x02;
+const uint32_t kUsageMonitorVdifInfo =
+    (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x03;
+const uint32_t kUsageMonitorBrightness =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x10;
+const uint32_t kUsageMonitorContrast =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x12;
+const uint32_t kUsageMonitorRedVideoGain =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x16;
+const uint32_t kUsageMonitorGreenVideoGain =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x18;
+const uint32_t kUsageMonitorBlueVideoGain =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x1a;
+const uint32_t kUsageMonitorHorizontalPosition =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x20;
+const uint32_t kUsageMonitorHorizontalSize =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x22;
+const uint32_t kUsageMonitorVerticalPosition =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x30;
+const uint32_t kUsageMonitorVerticalSize =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x32;
+const uint32_t kUsageMonitorTrapezoidalDistortion =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x42;
+const uint32_t kUsageMonitorTilt =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x44;
+const uint32_t kUsageMonitorRedVideoBlackLevel =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x6c;
+const uint32_t kUsageMonitorGreenVideoBlackLevel =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x6e;
+const uint32_t kUsageMonitorBlueVideoBlackLevel =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x70;
+const uint32_t kUsagePidSetEffectReport =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x21;
+const uint32_t kUsagePidDuration =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x50;
+const uint32_t kUsagePidMagnitude =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x70;
+const uint32_t kUsagePidLoopCount =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x7c;
+const uint32_t kUsagePidDCEnableActuators =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x97;
+const uint32_t kUsagePidStartDelay =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0xa7;
+const uint32_t kUsageSimulationAccelerator =
+    (mojom::kPageSimulation << kUsageIdSizeBits) | 0xc4;
+const uint32_t kUsageSimulationBrake =
+    (mojom::kPageSimulation << kUsageIdSizeBits) | 0xc5;
+const uint32_t kUsageVendor = mojom::kPageVendor << kUsageIdSizeBits;
+const uint32_t kUsageVendor02 = kPageVendor02 << kUsageIdSizeBits;
+const uint32_t kUsageVendor05 = kPageVendor05 << kUsageIdSizeBits;
+const uint32_t kUsageVendor80 = kPageVendor80 << kUsageIdSizeBits;
+
+// Report item tags.
+const HidReportDescriptorItem::Tag kInput = HidReportDescriptorItem::kTagInput;
+const HidReportDescriptorItem::Tag kOutput =
+    HidReportDescriptorItem::kTagOutput;
+const HidReportDescriptorItem::Tag kFeature =
+    HidReportDescriptorItem::kTagFeature;
+const HidReportDescriptorItem::CollectionType kCollectionTypeApplication =
+    HidReportDescriptorItem::kCollectionTypeApplication;
+const HidReportDescriptorItem::CollectionType kCollectionTypeLogical =
+    HidReportDescriptorItem::kCollectionTypeLogical;
+const HidReportDescriptorItem::CollectionType kCollectionTypePhysical =
+    kCollectionTypePhysical;
+
+}  // namespace
+
 class HidReportDescriptorTest : public testing::Test {
  protected:
   using HidUsageAndPage = mojom::HidUsageAndPage;
   using HidCollectionInfo = mojom::HidCollectionInfo;
   using HidCollectionInfoPtr = mojom::HidCollectionInfoPtr;
 
-  void SetUp() override { descriptor_ = nullptr; }
-
   void TearDown() override {
-    if (descriptor_) {
-      delete descriptor_;
-    }
+    descriptor_ = nullptr;
+    expected_collection_infos_.clear();
+    expected_collections_.clear();
+    report_id_ = 0;
+    globals_ = HidItemStateTable::HidGlobalItemState();
   }
 
  public:
+  // Add a top-level collection to |expected_collection_infos_|.
+  void AddTopCollectionInfo(HidCollectionInfoPtr collection_info) {
+    expected_collection_infos_.push_back(std::move(collection_info));
+  }
+
+  // Create a new collection and append it to |expected_collections_|.
+  HidCollection* AddTopCollection(
+      uint32_t usage,
+      HidReportDescriptorItem::CollectionType collection_type) {
+    uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
+    usage = usage & kUsageIdMask;
+    expected_collections_.push_back(std::make_unique<HidCollection>(
+        nullptr, usage_page, usage, static_cast<uint32_t>(collection_type)));
+    return expected_collections_.back().get();
+  }
+
+  // Create a new collection as a child of |parent|.
+  HidCollection* AddChild(
+      HidCollection* parent,
+      uint32_t usage,
+      HidReportDescriptorItem::CollectionType collection_type) {
+    uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
+    usage = usage & kUsageIdMask;
+    parent->AddChildForTesting(std::make_unique<HidCollection>(
+        parent, usage_page, usage, static_cast<uint32_t>(collection_type)));
+    return parent->GetChildren().back().get();
+  }
+
+  // Set the |report_id|. Subsequent report items will be appended to the report
+  // with this ID.
+  void SetReportId(uint8_t report_id) { report_id_ = report_id; }
+
+  // Set the |unit| and |unit_exponent|. Subsequent report items will inherit
+  // these values.
+  void SetUnitAndUnitExponent(uint32_t unit, uint32_t unit_exponent) {
+    globals_.unit = unit;
+    globals_.unit_exponent = unit_exponent;
+  }
+
+  // Set the logical and physical minimums and maximums. Subsequent report items
+  // will inherit these values.
+  void SetLogicalAndPhysicalBounds(uint32_t logical_minimum,
+                                   uint32_t logical_maximum,
+                                   uint32_t physical_minimum,
+                                   uint32_t physical_maximum) {
+    globals_.logical_minimum = int32_t{logical_minimum};
+    globals_.logical_maximum = int32_t{logical_maximum};
+    globals_.physical_minimum = int32_t{physical_minimum};
+    globals_.physical_maximum = int32_t{physical_maximum};
+  }
+
+  // Set the |report_size| in bits, and the |report_count|. Subsequent report
+  // items will inherit these values.
+  void SetReportSizeAndCount(uint32_t report_size, uint32_t report_count) {
+    globals_.report_size = report_size;
+    globals_.report_count = report_count;
+  }
+
+  // Add a report item with a size and count but no usage value.
+  void AddReportConstant(HidCollection* collection,
+                         HidReportDescriptorItem::Tag tag,
+                         uint32_t report_info) {
+    HidItemStateTable state;
+    state.global_stack.push_back(globals_);
+    state.report_id = report_id_;
+    for (const HidCollection* c = collection; c; c = c->GetParent())
+      const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
+  }
+
+  // Add a report item for one or more usages with the same size. The size of
+  // |usage_ids| is not required to be the same as the report count.
+  void AddReportItem(HidCollection* collection,
+                     HidReportDescriptorItem::Tag tag,
+                     uint32_t report_info,
+                     const std::vector<uint32_t>& usage_ids) {
+    HidItemStateTable state;
+    state.global_stack.push_back(globals_);
+    state.report_id = report_id_;
+    state.local.usages = usage_ids;
+    for (const HidCollection* c = collection; c; c = c->GetParent())
+      const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
+  }
+
+  // Add a report item for a range of usages. The item may be a variable or an
+  // array.
+  void AddReportItemRange(HidCollection* collection,
+                          HidReportDescriptorItem::Tag tag,
+                          uint32_t report_info,
+                          uint32_t usage_minimum,
+                          uint32_t usage_maximum) {
+    HidItemStateTable state;
+    state.global_stack.push_back(globals_);
+    state.report_id = report_id_;
+    state.local.usage_minimum = usage_minimum;
+    state.local.usage_maximum = usage_maximum;
+    for (const HidCollection* c = collection; c; c = c->GetParent())
+      const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
+  }
+
   void ValidateDetails(
-      const std::vector<HidCollectionInfoPtr>& expected_collection_infos,
       const bool expected_has_report_id,
       const size_t expected_max_input_report_size,
       const size_t expected_max_output_report_size,
       const size_t expected_max_feature_report_size,
       const uint8_t* bytes,
       size_t size) {
-    descriptor_ =
-        new HidReportDescriptor(std::vector<uint8_t>(bytes, bytes + size));
-
+    descriptor_ = std::make_unique<HidReportDescriptor>(
+        std::vector<uint8_t>(bytes, bytes + size));
     std::vector<HidCollectionInfoPtr> actual_collection_infos;
     bool actual_has_report_id;
     size_t actual_max_input_report_size;
@@ -52,199 +339,1261 @@
                             &actual_max_output_report_size,
                             &actual_max_feature_report_size);
 
-    ASSERT_EQ(expected_collection_infos.size(), actual_collection_infos.size());
-
+    ASSERT_EQ(expected_collection_infos_.size(),
+              actual_collection_infos.size());
     auto actual_info_iter = actual_collection_infos.begin();
-    auto expected_info_iter = expected_collection_infos.begin();
-
-    while (expected_info_iter != expected_collection_infos.end() &&
+    auto expected_info_iter = expected_collection_infos_.begin();
+    while (expected_info_iter != expected_collection_infos_.end() &&
            actual_info_iter != actual_collection_infos.end()) {
       const HidCollectionInfoPtr& expected_info = *expected_info_iter;
       const HidCollectionInfoPtr& actual_info = *actual_info_iter;
-
       ASSERT_EQ(expected_info->usage->usage_page,
                 actual_info->usage->usage_page);
       ASSERT_EQ(expected_info->usage->usage, actual_info->usage->usage);
       ASSERT_THAT(actual_info->report_ids,
                   testing::ContainerEq(expected_info->report_ids));
-
       ++expected_info_iter;
       ++actual_info_iter;
     }
-
     ASSERT_EQ(expected_has_report_id, actual_has_report_id);
     ASSERT_EQ(expected_max_input_report_size, actual_max_input_report_size);
     ASSERT_EQ(expected_max_output_report_size, actual_max_output_report_size);
     ASSERT_EQ(expected_max_feature_report_size, actual_max_feature_report_size);
   }
 
+  static void ValidateReportItem(const HidReportItem& expected,
+                                 const HidReportItem& actual) {
+    uint32_t expected_report_info =
+        *reinterpret_cast<const uint32_t*>(&expected.GetReportInfo());
+    uint32_t actual_report_info =
+        *reinterpret_cast<const uint32_t*>(&actual.GetReportInfo());
+    ASSERT_EQ(expected.GetTag(), actual.GetTag());
+    ASSERT_EQ(expected_report_info, actual_report_info);
+    ASSERT_EQ(expected.GetReportId(), actual.GetReportId());
+    ASSERT_THAT(actual.GetUsages(), testing::ContainerEq(expected.GetUsages()));
+    ASSERT_EQ(expected.GetUsageMinimum(), actual.GetUsageMinimum());
+    ASSERT_EQ(expected.GetUsageMaximum(), actual.GetUsageMaximum());
+    ASSERT_EQ(expected.GetDesignatorMinimum(), actual.GetDesignatorMinimum());
+    ASSERT_EQ(expected.GetDesignatorMaximum(), actual.GetDesignatorMaximum());
+    ASSERT_EQ(expected.GetStringMinimum(), actual.GetStringMinimum());
+    ASSERT_EQ(expected.GetStringMaximum(), actual.GetStringMaximum());
+    ASSERT_EQ(expected.GetLogicalMinimum(), actual.GetLogicalMinimum());
+    ASSERT_EQ(expected.GetLogicalMaximum(), actual.GetLogicalMaximum());
+    ASSERT_EQ(expected.GetPhysicalMinimum(), actual.GetPhysicalMinimum());
+    ASSERT_EQ(expected.GetPhysicalMaximum(), actual.GetPhysicalMaximum());
+    ASSERT_EQ(expected.GetUnitExponent(), actual.GetUnitExponent());
+    ASSERT_EQ(expected.GetUnit(), actual.GetUnit());
+    ASSERT_EQ(expected.GetReportSize(), actual.GetReportSize());
+    ASSERT_EQ(expected.GetReportCount(), actual.GetReportCount());
+  }
+
+  static void ValidateReportMap(const HidReportMap& expected_reports,
+                                const HidReportMap& actual_reports) {
+    for (const auto& expected_entry : expected_reports) {
+      auto find_it = actual_reports.find(expected_entry.first);
+      ASSERT_NE(find_it, actual_reports.end());
+      const auto& expected_report = expected_entry.second;
+      const auto& actual_report = find_it->second;
+      ASSERT_EQ(expected_report.size(), actual_report.size());
+      auto expected_item_iter = expected_report.begin();
+      auto actual_item_iter = actual_report.begin();
+      while (expected_item_iter != expected_report.end() &&
+             actual_item_iter != actual_report.end()) {
+        ValidateReportItem(**expected_item_iter, **actual_item_iter);
+        ++expected_item_iter;
+        ++actual_item_iter;
+      }
+    }
+    ASSERT_EQ(expected_reports.size(), actual_reports.size());
+  }
+
+  static void ValidateLinkCollection(const HidCollection* expected_collection,
+                                     const HidCollection* actual_collection) {
+    ASSERT_EQ(expected_collection->GetUsagePage(),
+              actual_collection->GetUsagePage());
+    ASSERT_EQ(expected_collection->GetUsage(), actual_collection->GetUsage());
+    ASSERT_EQ(expected_collection->GetCollectionType(),
+              actual_collection->GetCollectionType());
+    ValidateReportMap(expected_collection->GetInputReports(),
+                      actual_collection->GetInputReports());
+    ValidateReportMap(expected_collection->GetOutputReports(),
+                      actual_collection->GetOutputReports());
+    ValidateReportMap(expected_collection->GetFeatureReports(),
+                      actual_collection->GetFeatureReports());
+    const auto& expected_children = expected_collection->GetChildren();
+    const auto& actual_children = actual_collection->GetChildren();
+    auto expected_child_iter = expected_children.begin();
+    auto actual_child_iter = actual_children.begin();
+    while (expected_child_iter != expected_children.end() &&
+           actual_child_iter != actual_children.end()) {
+      const HidCollection* expected_child = expected_child_iter->get();
+      const HidCollection* actual_child = actual_child_iter->get();
+      ASSERT_EQ(actual_child->GetParent(), actual_collection);
+      ValidateLinkCollection(expected_child, actual_child);
+      ++expected_child_iter;
+      ++actual_child_iter;
+    }
+    ASSERT_EQ(expected_children.size(), actual_children.size());
+  }
+
+  void ValidateCollections(const uint8_t* bytes, size_t size) {
+    descriptor_ = std::make_unique<HidReportDescriptor>(
+        std::vector<uint8_t>(bytes, bytes + size));
+    const auto& actual_collections = descriptor_->collections();
+    auto actual_collection_iter = actual_collections.begin();
+    auto expected_collection_iter = expected_collections_.begin();
+    while (expected_collection_iter != expected_collections_.end() &&
+           actual_collection_iter != actual_collections.end()) {
+      ValidateLinkCollection(expected_collection_iter->get(),
+                             actual_collection_iter->get());
+      ++expected_collection_iter;
+      ++actual_collection_iter;
+    }
+    ASSERT_EQ(expected_collections_.size(), actual_collections.size());
+  }
+
  private:
-  HidReportDescriptor* descriptor_;
+  std::unique_ptr<HidReportDescriptor> descriptor_;
+  std::vector<HidCollectionInfoPtr> expected_collection_infos_;
+  HidCollectionVector expected_collections_;
+  uint8_t report_id_ = 0;
+  HidItemStateTable::HidGlobalItemState globals_;
 };
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_Digitizer) {
-  const uint16_t usage_page = mojom::kPageDigitizer;
-  const uint16_t usage = 0x01;  // Digitizer
-
   auto digitizer = HidCollectionInfo::New();
-  digitizer->usage = HidUsageAndPage::New(usage, usage_page);
+  digitizer->usage = HidUsageAndPage::New(0x01, mojom::kPageDigitizer);
+  ASSERT_EQ(IsProtected(*digitizer->usage), false);
   digitizer->report_ids = {0x01, 0x02, 0x03};
+  AddTopCollectionInfo(std::move(digitizer));
+  ValidateDetails(true, 6, 0, 0, kDigitizer, kDigitizerSize);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(digitizer));
-  ValidateDetails(expected_infos, true, 6, 0, 0, kDigitizer, kDigitizerSize);
+TEST_F(HidReportDescriptorTest, ValidateCollections_Digitizer) {
+  auto* top =
+      AddTopCollection(kUsageDigitizerDigitizer, kCollectionTypeApplication);
+  auto* puck = AddChild(top, kUsageDigitizerPuck, kCollectionTypePhysical);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
+  SetUnitAndUnitExponent(kUnitInch, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(puck, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 3);
+  AddReportItem(puck, kInput, kAbsoluteVariable,
+                {kUsageDigitizerInRange, kUsageDigitizerBarrelSwitch,
+                 kUsageDigitizerTipSwitch});
+  SetReportSizeAndCount(5, 1);
+  AddReportConstant(puck, kInput, kConstant);
+  SetReportId(0x02);
+  auto* stylus_up =
+      AddChild(top, kUsageDigitizerStylus, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
+  SetUnitAndUnitExponent(kUnitInch, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(stylus_up, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 2);
+  AddReportItem(stylus_up, kInput, kAbsoluteVariable, {kUsageDigitizerInRange});
+  SetLogicalAndPhysicalBounds(0, 16, 0, 1);
+  SetReportSizeAndCount(5, 2);
+  AddReportItemRange(stylus_up, kInput, kNullableArray, kUsageButton,
+                     kUsageButton + 16);
+  SetReportSizeAndCount(2, 2);
+  AddReportConstant(stylus_up, kInput, kConstantArray);
+  SetReportId(0x03);
+  auto* stylus_down =
+      AddChild(top, kUsageDigitizerStylus, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
+  SetUnitAndUnitExponent(kUnitInch, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(stylus_down, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 2);
+  AddReportItem(stylus_down, kInput, kAbsoluteVariable,
+                {kUsageDigitizerInRange, kUsageDigitizerBarrelSwitch});
+  SetReportSizeAndCount(1, 6);
+  AddReportConstant(stylus_down, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 127, 0, 45);
+  SetUnitAndUnitExponent(kUnitNewton, 4);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(stylus_down, kInput, kNonLinearVariable,
+                {kUsageDigitizerTipPressure});
+  ValidateCollections(kDigitizer, kDigitizerSize);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_Keyboard) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopKeyboard;
-
   auto keyboard = HidCollectionInfo::New();
-  keyboard->usage = HidUsageAndPage::New(usage, usage_page);
+  keyboard->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*keyboard->usage), true);
+  AddTopCollectionInfo(std::move(keyboard));
+  ValidateDetails(false, 8, 1, 0, kKeyboard, kKeyboardSize);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(keyboard));
-  ValidateDetails(expected_infos, false, 8, 1, 0, kKeyboard, kKeyboardSize);
+TEST_F(HidReportDescriptorTest, ValidateCollections_Keyboard) {
+  auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
+                               kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 8);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
+                     kUsageKeyboardRightGui);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(top, kInput, kConstant);
+  SetReportSizeAndCount(1, 5);
+  AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageLedNumLock,
+                     kUsageLedKana);
+  SetReportSizeAndCount(3, 1);
+  AddReportConstant(top, kOutput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 101, 0, 0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
+                     kUsageKeyboardApplication);
+  ValidateCollections(kKeyboard, kKeyboardSize);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_Monitor) {
-  const uint16_t usage_page = mojom::kPageMonitor0;  // USB monitor
-  const uint16_t usage = 0x01;                       // Monitor control
-
   auto monitor = HidCollectionInfo::New();
-  monitor->usage = HidUsageAndPage::New(usage, usage_page);
-  monitor->report_ids = {1, 2, 3, 4, 5};
+  monitor->usage = HidUsageAndPage::New(0x01, mojom::kPageMonitor0);
+  ASSERT_EQ(IsProtected(*monitor->usage), false);
+  monitor->report_ids = {0x01, 0x02, 0x03, 0x04, 0x05};
+  AddTopCollectionInfo(std::move(monitor));
+  ValidateDetails(true, 0, 0, 243, kMonitor, kMonitorSize);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(monitor));
-  ValidateDetails(expected_infos, true, 0, 0, 243, kMonitor, kMonitorSize);
+TEST_F(HidReportDescriptorTest, ValidateCollections_Monitor) {
+  auto* top =
+      AddTopCollection(kUsageMonitorControl, kCollectionTypeApplication);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 128);
+  AddReportItem(top, kFeature, kBufferedBytes, {kUsageMonitorEdidInfo});
+  SetReportId(0x02);
+  SetReportSizeAndCount(8, 243);
+  AddReportItem(top, kFeature, kBufferedBytes, {kUsageMonitorVdifInfo});
+  SetReportId(0x03);
+  SetUnitAndUnitExponent(kUnitCandela, 0x0e);
+  SetReportSizeAndCount(16, 1);
+  SetLogicalAndPhysicalBounds(0, 200, 0, 0);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageMonitorBrightness});
+  SetReportId(0x04);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageMonitorContrast});
+  SetReportSizeAndCount(16, 6);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(
+      top, kFeature, kAbsoluteVariable,
+      {kUsageMonitorRedVideoGain, kUsageMonitorGreenVideoGain,
+       kUsageMonitorBlueVideoGain, kUsageMonitorRedVideoBlackLevel,
+       kUsageMonitorGreenVideoBlackLevel, kUsageMonitorBlueVideoBlackLevel});
+  SetReportId(0x05);
+  SetLogicalAndPhysicalBounds(0, 127, 0, 0);
+  AddReportItem(top, kFeature, kAbsoluteVariable,
+                {kUsageMonitorHorizontalPosition, kUsageMonitorHorizontalSize,
+                 kUsageMonitorVerticalPosition, kUsageMonitorVerticalSize,
+                 kUsageMonitorTrapezoidalDistortion, kUsageMonitorTilt});
+  ValidateCollections(kMonitor, kMonitorSize);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_Mouse) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopMouse;
-
   auto mouse = HidCollectionInfo::New();
-  mouse->usage = HidUsageAndPage::New(usage, usage_page);
+  mouse->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
+                                      mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*mouse->usage), true);
+  AddTopCollectionInfo(std::move(mouse));
+  ValidateDetails(false, 3, 0, 0, kMouse, kMouseSize);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(mouse));
-  ValidateDetails(expected_infos, false, 3, 0, 0, kMouse, kMouseSize);
+TEST_F(HidReportDescriptorTest, ValidateCollections_Mouse) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
+  auto* physical =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 3);
+  AddReportItemRange(physical, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 3);
+  SetReportSizeAndCount(5, 1);
+  AddReportConstant(physical, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(physical, kInput, kRelativeVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  ValidateCollections(kMouse, kMouseSize);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_LogitechUnifyingReceiver) {
-  const uint16_t usage_page = mojom::kPageVendor;
-  const uint16_t usage_hidpp_short = 0x01;  // Vendor-defined
-  const uint16_t usage_hidpp_long = 0x02;   // Vendor-defined
-  const uint16_t usage_hidpp_dj = 0x04;     // Vendor-defined
-
   auto hidpp_short = HidCollectionInfo::New();
-  hidpp_short->usage = HidUsageAndPage::New(usage_hidpp_short, usage_page);
+  hidpp_short->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
+  ASSERT_EQ(IsProtected(*hidpp_short->usage), false);
   hidpp_short->report_ids = {0x10};
   auto hidpp_long = HidCollectionInfo::New();
-  hidpp_long->usage = HidUsageAndPage::New(usage_hidpp_long, usage_page);
+  hidpp_long->usage = HidUsageAndPage::New(0x02, mojom::kPageVendor);
+  ASSERT_EQ(IsProtected(*hidpp_long->usage), false);
   hidpp_long->report_ids = {0x11};
   auto hidpp_dj = HidCollectionInfo::New();
-  hidpp_dj->usage = HidUsageAndPage::New(usage_hidpp_dj, usage_page);
+  hidpp_dj->usage = HidUsageAndPage::New(0x04, mojom::kPageVendor);
+  ASSERT_EQ(IsProtected(*hidpp_dj->usage), false);
   hidpp_dj->report_ids = {0x20, 0x21};
-
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(hidpp_short));
-  expected_infos.push_back(std::move(hidpp_long));
-  expected_infos.push_back(std::move(hidpp_dj));
-  ValidateDetails(expected_infos, true, 31, 31, 0, kLogitechUnifyingReceiver,
+  AddTopCollectionInfo(std::move(hidpp_short));
+  AddTopCollectionInfo(std::move(hidpp_long));
+  AddTopCollectionInfo(std::move(hidpp_dj));
+  ValidateDetails(true, 31, 31, 0, kLogitechUnifyingReceiver,
                   kLogitechUnifyingReceiverSize);
 }
 
+TEST_F(HidReportDescriptorTest, ValidateCollections_LogitechUnifyingReceiver) {
+  auto* short_collection =
+      AddTopCollection(kUsageVendor + 0x01, kCollectionTypeApplication);
+  SetReportId(0x10);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(short_collection, kInput, kNonNullableArray,
+                {kUsageVendor + 0x01});
+  AddReportItem(short_collection, kOutput, kNonNullableArray,
+                {kUsageVendor + 0x01});
+  auto* long_collection =
+      AddTopCollection(kUsageVendor + 0x02, kCollectionTypeApplication);
+  SetReportId(0x11);
+  SetReportSizeAndCount(8, 19);
+  AddReportItem(long_collection, kInput, kNonNullableArray,
+                {kUsageVendor + 0x02});
+  AddReportItem(long_collection, kOutput, kNonNullableArray,
+                {kUsageVendor + 0x02});
+  auto* dj_collection =
+      AddTopCollection(kUsageVendor + 0x04, kCollectionTypeApplication);
+  SetReportId(0x20);
+  SetReportSizeAndCount(8, 14);
+  AddReportItem(dj_collection, kInput, kNonNullableArray,
+                {kUsageVendor + 0x41});
+  AddReportItem(dj_collection, kOutput, kNonNullableArray,
+                {kUsageVendor + 0x41});
+  SetReportId(0x21);
+  SetReportSizeAndCount(8, 31);
+  AddReportItem(dj_collection, kInput, kNonNullableArray,
+                {kUsageVendor + 0x42});
+  AddReportItem(dj_collection, kOutput, kNonNullableArray,
+                {kUsageVendor + 0x42});
+  ValidateCollections(kLogitechUnifyingReceiver, kLogitechUnifyingReceiverSize);
+}
+
 TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock3) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopJoystick;
-
   auto top_info = HidCollectionInfo::New();
-  top_info->usage = HidUsageAndPage::New(usage, usage_page);
+  top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*top_info->usage), false);
   top_info->report_ids = {0x01, 0x02, 0xee, 0xef};
+  AddTopCollectionInfo(std::move(top_info));
+  ValidateDetails(true, 48, 48, 48, kSonyDualshock3, kSonyDualshock3Size);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(top_info));
-  ValidateDetails(expected_infos, true, 48, 48, 48, kSonyDualshock3,
-                  kSonyDualshock3Size);
+TEST_F(HidReportDescriptorTest, ValidateCollections_SonyDualshock3) {
+  auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
+                               kCollectionTypeApplication);
+  auto* joystick = AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(joystick, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetReportSizeAndCount(1, 19);
+  AddReportItemRange(joystick, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 19);
+  SetReportSizeAndCount(1, 13);
+  AddReportConstant(joystick, kInput, kConstant);
+  auto* stick_axes =
+      AddChild(joystick, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 255);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(stick_axes, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
+  SetReportSizeAndCount(8, 39);
+  AddReportItem(joystick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  SetReportSizeAndCount(8, 48);
+  AddReportItem(joystick, kOutput, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  AddReportItem(joystick, kFeature, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  auto* report_02_collection =
+      AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
+  SetReportId(0x02);
+  AddReportItem(report_02_collection, kFeature, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  auto* report_ee_collection =
+      AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
+  SetReportId(0xee);
+  AddReportItem(report_ee_collection, kFeature, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  auto* report_ef_collection =
+      AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
+  SetReportId(0xef);
+  AddReportItem(report_ef_collection, kFeature, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  ValidateCollections(kSonyDualshock3, kSonyDualshock3Size);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock4) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopGamePad;
-
   auto top_info = HidCollectionInfo::New();
-  top_info->usage = HidUsageAndPage::New(usage, usage_page);
+  top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*top_info->usage), false);
   top_info->report_ids = {0x01, 0x05, 0x04, 0x02, 0x08, 0x10, 0x11, 0x12, 0x13,
                           0x14, 0x15, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
                           0x87, 0x88, 0x89, 0x90, 0x91, 0x92, 0x93, 0xa0, 0xa1,
                           0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xf0, 0xf1, 0xf2, 0xa7,
                           0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0};
+  AddTopCollectionInfo(std::move(top_info));
+  ValidateDetails(true, 63, 31, 63, kSonyDualshock4, kSonyDualshock4Size);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(top_info));
-  ValidateDetails(expected_infos, true, 63, 31, 63, kSonyDualshock4,
-                  kSonyDualshock4Size);
+TEST_F(HidReportDescriptorTest, ValidateCollections_SonyDualshock4) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
+  SetLogicalAndPhysicalBounds(0, 7, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(top, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 315);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 14);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 14);
+  SetLogicalAndPhysicalBounds(0, 127, 0, 315);
+  SetReportSizeAndCount(6, 1);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x20});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 315);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
+  SetReportSizeAndCount(8, 54);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x21});
+  SetReportId(0x05);
+  SetReportSizeAndCount(8, 31);
+  AddReportItem(top, kOutput, kAbsoluteVariable, {kUsageVendor + 0x22});
+  SetReportId(0x04);
+  SetReportSizeAndCount(8, 36);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x23});
+  SetReportId(0x02);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x24});
+  SetReportId(0x08);
+  SetReportSizeAndCount(8, 3);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x25});
+  SetReportId(0x10);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x26});
+  SetReportId(0x11);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x27});
+  SetReportId(0x12);
+  SetReportSizeAndCount(8, 15);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor02 + 0x21});
+  SetReportId(0x13);
+  SetReportSizeAndCount(8, 22);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor02 + 0x22});
+  SetReportId(0x14);
+  SetReportSizeAndCount(8, 16);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor05 + 0x20});
+  SetReportId(0x15);
+  SetReportSizeAndCount(8, 44);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor05 + 0x21});
+  SetReportId(0x80);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x20});
+  SetReportId(0x81);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x21});
+  SetReportId(0x82);
+  SetReportSizeAndCount(8, 5);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x22});
+  SetReportId(0x83);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x23});
+  SetReportId(0x84);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x24});
+  SetReportId(0x85);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x25});
+  SetReportId(0x86);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x26});
+  SetReportId(0x87);
+  SetReportSizeAndCount(8, 35);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x27});
+  SetReportId(0x88);
+  SetReportSizeAndCount(8, 34);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x28});
+  SetReportId(0x89);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x29});
+  SetReportId(0x90);
+  SetReportSizeAndCount(8, 5);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x30});
+  SetReportId(0x91);
+  SetReportSizeAndCount(8, 3);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x31});
+  SetReportId(0x92);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x32});
+  SetReportId(0x93);
+  SetReportSizeAndCount(8, 12);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x33});
+  SetReportId(0xa0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x40});
+  SetReportId(0xa1);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x41});
+  SetReportId(0xa2);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x42});
+  SetReportId(0xa3);
+  SetReportSizeAndCount(8, 48);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x43});
+  SetReportId(0xa4);
+  SetReportSizeAndCount(8, 13);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x44});
+  SetReportId(0xa5);
+  SetReportSizeAndCount(8, 21);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x45});
+  SetReportId(0xa6);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x46});
+  SetReportId(0xf0);
+  SetReportSizeAndCount(8, 63);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x47});
+  SetReportId(0xf1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x48});
+  SetReportId(0xf2);
+  SetReportSizeAndCount(8, 15);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x49});
+  SetReportId(0xa7);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4a});
+  SetReportId(0xa8);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4b});
+  SetReportId(0xa9);
+  SetReportSizeAndCount(8, 8);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4c});
+  SetReportId(0xaa);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4e});
+  SetReportId(0xab);
+  SetReportSizeAndCount(8, 57);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4f});
+  SetReportId(0xac);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x50});
+  SetReportId(0xad);
+  SetReportSizeAndCount(8, 11);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x51});
+  SetReportId(0xae);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x52});
+  SetReportId(0xaf);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x53});
+  SetReportId(0xb0);
+  SetReportSizeAndCount(8, 63);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x54});
+  ValidateCollections(kSonyDualshock4, kSonyDualshock4Size);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_XboxWirelessController) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopGamePad;
-
   auto top_info = HidCollectionInfo::New();
-  top_info->usage = HidUsageAndPage::New(usage, usage_page);
+  top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*top_info->usage), false);
   top_info->report_ids = {0x01, 0x02, 0x03, 0x04};
-
-  std::vector<HidCollectionInfoPtr> expected_info;
-  expected_info.push_back(std::move(top_info));
-  ValidateDetails(expected_info, true, 15, 8, 0,
-                  kMicrosoftXboxWirelessController,
+  AddTopCollectionInfo(std::move(top_info));
+  ValidateDetails(true, 15, 8, 0, kMicrosoftXboxWirelessController,
                   kMicrosoftXboxWirelessControllerSize);
 }
 
+TEST_F(HidReportDescriptorTest, ValidateCollections_XboxWirelessController) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetReportId(0x01);
+  auto* left_stick =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(left_stick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  auto* right_stick =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  AddReportItem(right_stick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageGenericDesktopZ});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(top, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageGenericDesktopRz});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(top, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(1, 8, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(top, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetUnitAndUnitExponent(0, 0);
+  AddReportConstant(top, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 10);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 10);
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(top, kInput, kConstant);
+  SetReportId(0x02);
+  auto* mode_collection =
+      AddChild(top, kUsageGenericDesktopSystemControl, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 1);
+  AddReportItem(mode_collection, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopSystemMainMenu});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(7, 1);
+  AddReportConstant(mode_collection, kInput, kConstant);
+  SetReportId(0x03);
+  auto* pid_collection =
+      AddChild(top, kUsagePidSetEffectReport, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidDCEnableActuators});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(pid_collection, kOutput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidMagnitude});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetUnitAndUnitExponent(kUnitSecond, 0x0e);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidDuration});
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidStartDelay});
+  SetUnitAndUnitExponent(0, 0);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidLoopCount});
+  SetReportId(0x04);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDeviceBatteryStrength});
+  ValidateCollections(kMicrosoftXboxWirelessController,
+                      kMicrosoftXboxWirelessControllerSize);
+}
+
 TEST_F(HidReportDescriptorTest, ValidateDetails_NintendoSwitchProController) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopJoystick;
-
   auto top_info = HidCollectionInfo::New();
-  top_info->usage = HidUsageAndPage::New(usage, usage_page);
+  top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*top_info->usage), false);
   top_info->report_ids = {0x30, 0x21, 0x81, 0x01, 0x10, 0x80, 0x82};
-
-  std::vector<HidCollectionInfoPtr> expected_info;
-  expected_info.push_back(std::move(top_info));
-  ValidateDetails(expected_info, true, 63, 63, 0, kNintendoSwitchProController,
+  AddTopCollectionInfo(std::move(top_info));
+  ValidateDetails(true, 63, 63, 0, kNintendoSwitchProController,
                   kNintendoSwitchProControllerSize);
 }
 
+TEST_F(HidReportDescriptorTest,
+       ValidateCollections_NintendoSwitchProController) {
+  auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
+                               kCollectionTypeApplication);
+  SetReportId(0x30);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 10);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 10);
+  SetReportSizeAndCount(1, 4);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 11,
+                     kUsageButton + 14);
+  SetReportSizeAndCount(1, 2);
+  AddReportConstant(top, kInput, kConstant);
+  auto* stick_axes =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  SetReportSizeAndCount(16, 4);
+  AddReportItem(stick_axes, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
+  SetLogicalAndPhysicalBounds(0, 7, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 315);
+  SetReportSizeAndCount(1, 4);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 15,
+                     kUsageButton + 18);
+  SetReportSizeAndCount(8, 52);
+  AddReportConstant(top, kInput, kConstant);
+  SetReportId(0x21);
+  SetReportSizeAndCount(8, 63);
+  AddReportItem(top, kInput, kConstant, {kUsageVendor + 0x01});
+  SetReportId(0x81);
+  AddReportItem(top, kInput, kConstant, {kUsageVendor + 0x02});
+  SetReportId(0x01);
+  AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x03});
+  SetReportId(0x10);
+  AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x04});
+  SetReportId(0x80);
+  AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x05});
+  SetReportId(0x82);
+  AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x06});
+  ValidateCollections(kNintendoSwitchProController,
+                      kNintendoSwitchProControllerSize);
+}
+
 TEST_F(HidReportDescriptorTest, ValidateDetails_XboxAdaptiveController) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage_gamepad = mojom::kGenericDesktopGamePad;
-  const uint16_t usage_keyboard = mojom::kGenericDesktopKeyboard;
-  const uint8_t report_ids_gamepad[] = {0x01, 0x02, 0x03, 0x04, 0x06,
-                                        0x07, 0x08, 0x09, 0x0a, 0x0b};
-  const size_t report_ids_gamepad_size = base::size(report_ids_gamepad);
-  const uint8_t report_ids_keyboard[] = {0x05};
-  const size_t report_ids_keyboard_size = base::size(report_ids_keyboard);
-
   auto gamepad_info = HidCollectionInfo::New();
-  gamepad_info->usage = HidUsageAndPage::New(usage_gamepad, usage_page);
-  gamepad_info->report_ids.insert(gamepad_info->report_ids.begin(),
-                                  report_ids_gamepad,
-                                  report_ids_gamepad + report_ids_gamepad_size);
-
+  gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                             mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
+  gamepad_info->report_ids = {0x01, 0x02, 0x03, 0x04, 0x06,
+                              0x07, 0x08, 0x09, 0x0a, 0x0b};
   auto keyboard_info = HidCollectionInfo::New();
-  keyboard_info->usage = HidUsageAndPage::New(usage_keyboard, usage_page);
-  keyboard_info->report_ids.insert(
-      keyboard_info->report_ids.begin(), report_ids_keyboard,
-      report_ids_keyboard + report_ids_keyboard_size);
-
-  std::vector<HidCollectionInfoPtr> expected_info;
-  expected_info.push_back(std::move(gamepad_info));
-  expected_info.push_back(std::move(keyboard_info));
-  ValidateDetails(expected_info, true, 54, 8, 64,
-                  kMicrosoftXboxAdaptiveController,
+  keyboard_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
+                                              mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*keyboard_info->usage), true);
+  keyboard_info->report_ids = {0x05};
+  AddTopCollectionInfo(std::move(gamepad_info));
+  AddTopCollectionInfo(std::move(keyboard_info));
+  ValidateDetails(true, 54, 8, 64, kMicrosoftXboxAdaptiveController,
                   kMicrosoftXboxAdaptiveControllerSize);
 }
 
+TEST_F(HidReportDescriptorTest, ValidateCollections_XboxAdaptiveController) {
+  auto* gamepad =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetReportId(0x01);
+  auto* left_stick =
+      AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(left_stick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  auto* right_stick =
+      AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  AddReportItem(right_stick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopZ, kUsageGenericDesktopRz});
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageSimulationBrake});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable,
+                {kUsageSimulationAccelerator});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(1, 8, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetUnitAndUnitExponent(0, 0);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 15);
+  AddReportItemRange(gamepad, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 15);
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(1, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageConsumerACBack});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(7, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  auto* left_stick2 =
+      AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(left_stick2, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopVx, kUsageGenericDesktopVy});
+  auto* right_stick2 =
+      AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  AddReportItem(right_stick2, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopVbrx, kUsageGenericDesktopVbry});
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageGenericDesktopVz});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageGenericDesktopVbrz});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(1, 8, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopDial});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetUnitAndUnitExponent(0, 0);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 15);
+  AddReportItemRange(gamepad, kInput, kAbsoluteVariable, kUsageButton + 16,
+                     kUsageButton + 30);
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(1, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageConsumerModeStep});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(7, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  auto* consumer_collection =
+      AddChild(gamepad, kUsageConsumerControl, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x81});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(consumer_collection, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x84});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(consumer_collection, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x85});
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x99});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(consumer_collection, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x9e});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xa1});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xa2});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xa3});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xa4});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xb9});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xba});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xbb});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xbe});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc0});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc1});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc2});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc3});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc4});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc5});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc6});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc7});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc8});
+  SetReportId(0x02);
+  auto* mode_collection =
+      AddChild(gamepad, kUsageConsumerControl, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 1);
+  AddReportItem(mode_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumerACHome});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(7, 1);
+  AddReportConstant(mode_collection, kInput, kConstant);
+  SetReportId(0x03);
+  auto* pid_collection =
+      AddChild(gamepad, kUsagePidSetEffectReport, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidDCEnableActuators});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(pid_collection, kOutput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidMagnitude});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetUnitAndUnitExponent(kUnitSecond, 0x0e);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidDuration});
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidStartDelay});
+  SetUnitAndUnitExponent(0, 0);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidLoopCount});
+  SetReportId(0x04);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable,
+                {kUsageGenericDeviceBatteryStrength});
+  SetReportId(0x06);
+  auto* report_06_collection =
+      AddChild(gamepad, kUsageVendor + 0x01, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x01});
+  AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x02});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x03});
+  SetReportSizeAndCount(8, 60);
+  AddReportItem(report_06_collection, kFeature, kBufferedBytes,
+                {kUsageVendor + 0x04});
+  SetReportId(0x07);
+  auto* report_07_collection =
+      AddChild(gamepad, kUsageVendor + 0x02, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x05});
+  AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x06});
+  AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x07});
+  SetReportId(0x08);
+  auto* report_08_collection =
+      AddChild(gamepad, kUsageVendor + 0x03, kCollectionTypeLogical);
+  AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x08});
+  AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x09});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0a});
+  SetReportId(0x09);
+  auto* report_09_collection =
+      AddChild(gamepad, kUsageVendor + 0x04, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0b});
+  AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0c});
+  AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0d});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0e});
+  SetReportSizeAndCount(8, 60);
+  AddReportItem(report_09_collection, kFeature, kBufferedBytes,
+                {kUsageVendor + 0x0f});
+  SetReportId(0x0a);
+  auto* report_0a_collection =
+      AddChild(gamepad, kUsageVendor + 0x05, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 0x7fffffff, 0, 0);
+  SetReportSizeAndCount(32, 1);
+  AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
+                {kUsageVendor + 0x10});
+  AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
+                {kUsageVendor + 0x11});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
+                {kUsageVendor + 0x12});
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
+                {kUsageVendor + 0x13});
+  SetReportId(0x0b);
+  auto* report_0b_collection =
+      AddChild(gamepad, kUsageVendor + 0x06, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+
+  AddReportItem(report_0b_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x14});
+  SetReportId(0x05);
+  auto* keyboard = AddTopCollection(kUsageGenericDesktopKeyboard,
+                                    kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 8);
+  AddReportItemRange(keyboard, kInput, kAbsoluteVariable,
+                     kUsageKeyboardLeftControl, kUsageKeyboardRightGui);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(keyboard, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 101, 0, 0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItemRange(keyboard, kInput, kNonNullableArray, kUsageKeyboard,
+                     kUsageKeyboardApplication);
+  ValidateCollections(kMicrosoftXboxAdaptiveController,
+                      kMicrosoftXboxAdaptiveControllerSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_NexusPlayerController) {
+  auto gamepad_info = HidCollectionInfo::New();
+  gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                             mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
+  gamepad_info->report_ids = {0x01, 0x02};
+  auto status_info = HidCollectionInfo::New();
+  status_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                            mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*status_info->usage), false);
+  status_info->report_ids = {0x03};
+  AddTopCollectionInfo(std::move(gamepad_info));
+  AddTopCollectionInfo(std::move(status_info));
+  ValidateDetails(true, 8, 1, 0, kNexusPlayerController,
+                  kNexusPlayerControllerSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_NexusPlayerController) {
+  auto* gamepad =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 11);
+  AddReportItem(
+      gamepad, kInput, kAbsoluteVariable,
+      {kUsageButton + 1, kUsageButton + 2, kUsageButton + 4, kUsageButton + 5,
+       kUsageButton + 7, kUsageButton + 8, kUsageButton + 14, kUsageButton + 15,
+       kUsageButton + 13, kUsageConsumerACBack, kUsageConsumerACHome});
+  SetReportSizeAndCount(1, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 7, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetUnitAndUnitExponent(0, 0);
+  auto* axes_collection =
+      AddChild(gamepad, kUsageGenericDesktop, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 255);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(axes_collection, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopZ, kUsageGenericDesktopRz,
+                 kUsageSimulationBrake, kUsageSimulationAccelerator});
+  SetReportId(0x02);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 255);
+  SetReportSizeAndCount(1, 4);
+  AddReportItem(gamepad, kOutput, kAbsoluteVariable,
+                {kUsageLedNumLock, kUsageLedCapsLock, kUsageLedScrollLock,
+                 kUsageLedCompose});
+  SetReportSizeAndCount(4, 1);
+  AddReportConstant(gamepad, kOutput, kConstant);
+  SetReportId(0x03);
+  auto* status =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 255);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(status, kInput, kAbsoluteVariable,
+                {kUsageGenericDeviceBatteryStrength});
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(status, kInput, kAbsoluteVariable, {0xffbcbdad});
+  ValidateCollections(kNexusPlayerController, kNexusPlayerControllerSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerKeyboard) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), true);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 8, 1, 0, kSteamControllerKeyboard,
+                  kSteamControllerKeyboardSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerKeyboard) {
+  auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
+                               kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 8);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
+                     kUsageKeyboardRightGui);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(top, kInput, kConstantArray);
+  SetReportSizeAndCount(1, 5);
+  AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageLedNumLock,
+                     kUsageLedKana);
+  SetReportSizeAndCount(3, 1);
+  AddReportConstant(top, kOutput, kConstantArray);
+  SetReportSizeAndCount(8, 6);
+  SetLogicalAndPhysicalBounds(0, 101, 0, 0);
+  AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
+                     kUsageKeyboardApplication);
+  ValidateCollections(kSteamControllerKeyboard, kSteamControllerKeyboardSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerMouse) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), true);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 4, 0, 0, kSteamControllerMouse,
+                  kSteamControllerMouseSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerMouse) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
+  auto* pointer =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 5);
+  AddReportItemRange(pointer, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 5);
+  SetReportSizeAndCount(3, 1);
+  AddReportConstant(pointer, kInput, kConstantArray);
+  SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
+  SetReportSizeAndCount(8, 3);
+  AddReportItem(pointer, kInput, kRelativeVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopWheel});
+  ValidateCollections(kSteamControllerMouse, kSteamControllerMouseSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerVendor) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
+  ASSERT_EQ(IsProtected(*info->usage), false);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 64, 64, 64, kSteamControllerVendor,
+                  kSteamControllerVendorSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerVendor) {
+  auto* top = AddTopCollection(kUsageVendor + 0x01, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 64);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x01});
+  AddReportItem(top, kOutput, kAbsoluteVariable, {kUsageVendor + 0x01});
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x01});
+  ValidateCollections(kSteamControllerVendor, kSteamControllerVendorSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_XSkillsUsbAdapter) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), false);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 7, 4, 0, kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_XSkillsUsbAdapter) {
+  auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
+                               kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetReportSizeAndCount(1, 12);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 12);
+  SetReportSizeAndCount(1, 4);
+  AddReportConstant(top, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 255);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopRz, kUsageGenericDesktopZ});
+  SetLogicalAndPhysicalBounds(0, 15, 0, 15);
+  SetReportSizeAndCount(4, 2);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
+  SetReportSizeAndCount(8, 4);
+  AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageVendor + 0x01,
+                     kUsageVendor + 0x04);
+  ValidateCollections(kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoKeyboard) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), true);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 8, 0, 0, kBelkinNostromoKeyboard,
+                  kBelkinNostromoKeyboardSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_BelkinNostromoKeyboard) {
+  auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
+                               kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 8);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
+                     kUsageKeyboardRightGui);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(top, kInput, kConstantArray);
+  SetLogicalAndPhysicalBounds(0, 101, 0, 0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
+                     kUsageKeyboardApplication);
+  ValidateCollections(kBelkinNostromoKeyboard, kBelkinNostromoKeyboardSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoMouseAndExtra) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), true);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 4, 1, 0, kBelkinNostromoMouseAndExtra,
+                  kBelkinNostromoMouseAndExtraSize);
+}
+
+TEST_F(HidReportDescriptorTest,
+       ValidateCollections_BelkinNostromoMouseAndExtra) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
+  auto* pointer =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 3);
+  AddReportItemRange(pointer, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 3);
+  SetReportSizeAndCount(5, 1);
+  AddReportConstant(pointer, kInput, kConstantArray);
+  SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
+  SetReportSizeAndCount(8, 3);
+  AddReportItem(pointer, kInput, kRelativeVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopWheel});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetReportSizeAndCount(1, 3);
+  AddReportItemRange(pointer, kOutput, kAbsoluteVariable, kUsageLedNumLock,
+                     kUsageLedScrollLock);
+  SetReportSizeAndCount(5, 1);
+  AddReportConstant(pointer, kOutput, kConstantArray);
+  ValidateCollections(kBelkinNostromoMouseAndExtra,
+                      kBelkinNostromoMouseAndExtraSize);
+}
+
 }  // namespace device
diff --git a/services/device/public/cpp/hid/hid_report_item.cc b/services/device/public/cpp/hid/hid_report_item.cc
new file mode 100644
index 0000000..eeab22a
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_report_item.cc
@@ -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.
+
+#include "services/device/public/cpp/hid/hid_report_item.h"
+
+#include "services/device/public/mojom/hid.mojom.h"
+
+namespace device {
+
+HidReportItem::HidReportItem(HidReportDescriptorItem::Tag tag,
+                             uint32_t short_data,
+                             const HidItemStateTable& state)
+    : tag_(tag),
+      report_info_(
+          *reinterpret_cast<HidReportDescriptorItem::ReportInfo*>(&short_data)),
+      report_id_(state.report_id),
+      local_(state.local),
+      global_(state.global_stack.empty()
+                  ? HidItemStateTable::HidGlobalItemState()
+                  : state.global_stack.back()),
+      is_range_(state.local.usage_minimum != state.local.usage_maximum),
+      has_strings_(state.local.string_index ||
+                   (state.local.string_minimum != state.local.string_maximum)),
+      has_designators_(
+          state.local.designator_index ||
+          (state.local.designator_minimum != state.local.designator_maximum)) {
+  global_.usage_page = mojom::kPageUndefined;
+  if (state.local.string_index) {
+    local_.string_minimum = state.local.string_index;
+    local_.string_maximum = state.local.string_index;
+  }
+  if (state.local.designator_index) {
+    local_.designator_minimum = state.local.designator_index;
+    local_.designator_maximum = state.local.designator_index;
+  }
+}
+
+HidReportItem::~HidReportItem() = default;
+
+}  // namespace device
diff --git a/services/device/public/cpp/hid/hid_report_item.h b/services/device/public/cpp/hid/hid_report_item.h
new file mode 100644
index 0000000..eae86f8
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_report_item.h
@@ -0,0 +1,135 @@
+// 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_DEVICE_PUBLIC_CPP_HID_HID_REPORT_ITEM_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_ITEM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "services/device/public/cpp/hid/hid_item_state_table.h"
+#include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
+
+namespace device {
+
+class HidReportItem {
+ public:
+  HidReportItem(HidReportDescriptorItem::Tag,
+                uint32_t,
+                const HidItemStateTable&);
+  ~HidReportItem();
+
+  static std::unique_ptr<HidReportItem> Create(HidReportDescriptorItem::Tag tag,
+                                               uint32_t short_data,
+                                               const HidItemStateTable& state) {
+    return std::make_unique<HidReportItem>(tag, short_data, state);
+  }
+
+  HidReportDescriptorItem::Tag GetTag() const { return tag_; }
+
+  const HidReportDescriptorItem::ReportInfo& GetReportInfo() const {
+    return report_info_;
+  }
+
+  // Returns the report ID of the report this item is part of.
+  uint8_t GetReportId() const { return report_id_; }
+
+  // Returns true if this item defines a usage range (minimum and maximum), or
+  // false if it defines a list of usages.
+  bool IsRange() const { return is_range_; }
+
+  // Returns true if the usage or usage range has one or more strings.
+  bool HasStrings() const { return has_strings_; }
+
+  // Returns true if the usage or usage range has one or more designators.
+  bool HasDesignators() const { return has_designators_; }
+
+  // Returns true if the report item is an absolute type, or false if it is a
+  // relative type.
+  bool IsAbsolute() const { return !report_info_.absolute_or_relative; }
+
+  // Returns true if the report item is an array type. (e.g., keyboard scan
+  // codes)
+  bool IsArray() const { return !report_info_.array_or_variable; }
+
+  // If |is_range| is false, Usages returns the list of usages associated with
+  // this item.
+  const std::vector<uint32_t>& GetUsages() const { return local_.usages; }
+
+  // If |is_range| is true, UsageMinimum and UsageMaximum return the minimum and
+  // maximum for the range of usages associated with this item.
+  uint16_t GetUsageMinimum() const { return local_.usage_minimum; }
+  uint16_t GetUsageMaximum() const { return local_.usage_maximum; }
+
+  // If |has_strings| is true, StringMinimum and StringMaximum return the
+  // minimum and maximum string indices associated with this item.
+  uint16_t GetStringMinimum() const { return local_.string_minimum; }
+  uint16_t GetStringMaximum() const { return local_.string_maximum; }
+
+  // If |has_designators| is true, DesignatorMinimum and DesignatorMaximum
+  // return the minimum and maximum designator indices associated with this
+  // item.
+  uint16_t GetDesignatorMinimum() const { return local_.designator_minimum; }
+  uint16_t GetDesignatorMaximum() const { return local_.designator_maximum; }
+
+  // Returns true if the item supports reporting a value outside the logical
+  // range as a null value.
+  bool HasNull() const { return report_info_.null; }
+
+  // Returns the width of each field defined by this item, in bits.
+  uint16_t GetReportSize() const { return global_.report_size; }
+
+  // Returns the number of fields defined by this item.
+  uint16_t GetReportCount() const { return global_.report_count; }
+
+  // Returns a 32-bit value representing a unit definition for the current item,
+  // or 0 if the item is not assigned a unit.
+  uint32_t GetUnit() const { return global_.unit; }
+
+  // Returns a value representing the exponent applied to the assigned unit.
+  uint32_t GetUnitExponent() const { return global_.unit_exponent; }
+
+  // Returns signed values representing the minimum and maximum values for this
+  // item.
+  int32_t GetLogicalMinimum() const { return global_.logical_minimum; }
+  int32_t GetLogicalMaximum() const { return global_.logical_maximum; }
+
+  // Returns signed values representing the minimum and maximum values for this
+  // item in the declared units, for scaling purposes.
+  int32_t GetPhysicalMinimum() const { return global_.physical_minimum; }
+  int32_t GetPhysicalMaximum() const { return global_.physical_maximum; }
+
+ private:
+  // The tag of the main item that generated this report item. Must be
+  // kItemInput, kItemOutput, or kItemFeature.
+  HidReportDescriptorItem::Tag tag_;
+
+  // Data associated with the main item that generated this report item.
+  HidReportDescriptorItem::ReportInfo report_info_;
+
+  // The report ID associated with this report, or 0 if none.
+  uint8_t report_id_;
+
+  // A copy of the local and global item state when this report item was
+  // encountered.
+  HidItemStateTable::HidLocalItemState local_;
+  HidItemStateTable::HidGlobalItemState global_;
+
+  // If true, the usages for this item are defined by |local.usage_minimum| and
+  // |local.usage_maximum|. If false, the usages are defomed by |local.usages|.
+  bool is_range_;
+
+  // If true, one or more strings are associated with this item.
+  bool has_strings_;
+
+  // If true, one or more designators are associated with this item.
+  bool has_designators_;
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_ITEM_H_
diff --git a/services/device/public/cpp/hid/hid_usage_and_page.h b/services/device/public/cpp/hid/hid_usage_and_page.h
index 4c82d88..b080797 100644
--- a/services/device/public/cpp/hid/hid_usage_and_page.h
+++ b/services/device/public/cpp/hid/hid_usage_and_page.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 DEVICE_HID_PUBLIC_CPP_HID_USAGE_AND_PAGE_H_
-#define DEVICE_HID_PUBLIC_CPP_HID_USAGE_AND_PAGE_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_USAGE_AND_PAGE_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_USAGE_AND_PAGE_H_
 
 #include "services/device/public/mojom/hid.mojom.h"
 
@@ -14,4 +14,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_HID_PUBLIC_CPP_HID_USAGE_AND_PAGE_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_USAGE_AND_PAGE_H_
diff --git a/services/device/public/mojom/hid.mojom b/services/device/public/mojom/hid.mojom
index 1de8f6f2..208a511 100644
--- a/services/device/public/mojom/hid.mojom
+++ b/services/device/public/mojom/hid.mojom
@@ -16,6 +16,7 @@
 const uint16 kPageVirtualReality = 0x03;
 const uint16 kPageSport = 0x04;
 const uint16 kPageGame = 0x05;
+const uint16 kPageGenericDevice = 0x06;
 const uint16 kPageKeyboard = 0x07;
 const uint16 kPageLed = 0x08;
 const uint16 kPageButton = 0x09;
diff --git a/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc b/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
index c2b81743..1b966d2 100644
--- a/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
+++ b/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
@@ -58,6 +58,8 @@
     case __NR_sched_getaffinity:
     case __NR_sched_setaffinity:
       return sandbox::RestrictSchedTarget(GetPolicyPid(), sysno);
+    case __NR_prlimit64:
+      return sandbox::RestrictPrlimit64(GetPolicyPid());
     default:
       if (SyscallSets::IsEventFd(sysno))
         return Allow();
diff --git a/services/tracing/public/cpp/perfetto/task_runner.cc b/services/tracing/public/cpp/perfetto/task_runner.cc
index 5392d641..f245c54 100644
--- a/services/tracing/public/cpp/perfetto/task_runner.cc
+++ b/services/tracing/public/cpp/perfetto/task_runner.cc
@@ -32,6 +32,10 @@
       base::TimeDelta::FromMilliseconds(delay_ms));
 }
 
+bool PerfettoTaskRunner::RunsTasksOnCurrentThread() const {
+  return task_runner_->RunsTasksInCurrentSequence();
+}
+
 void PerfettoTaskRunner::AddFileDescriptorWatch(int fd, std::function<void()>) {
   NOTREACHED();
 }
diff --git a/services/tracing/public/cpp/perfetto/task_runner.h b/services/tracing/public/cpp/perfetto/task_runner.h
index 373f337..15a0ca3 100644
--- a/services/tracing/public/cpp/perfetto/task_runner.h
+++ b/services/tracing/public/cpp/perfetto/task_runner.h
@@ -26,6 +26,11 @@
   // the Perfetto implementation itself.
   void PostTask(std::function<void()> task) override;
   void PostDelayedTask(std::function<void()> task, uint32_t delay_ms) override;
+  // This in Chrome would more correctly be called "RunsTasksInCurrentSequence".
+  // Perfetto calls this to determine wheather CommitData requests should be
+  // flushed synchronously. RunsTasksInCurrentSequence is sufficient for that
+  // use case.
+  bool RunsTasksOnCurrentThread() const override;
 
   // Not used in Chrome.
   void AddFileDescriptorWatch(int fd, std::function<void()>) override;
diff --git a/sql/database.cc b/sql/database.cc
index adf3b2c..e820382 100644
--- a/sql/database.cc
+++ b/sql/database.cc
@@ -158,7 +158,7 @@
 
 std::string AsUTF8ForSQL(const base::FilePath& path) {
 #if defined(OS_WIN)
-  return base::WideToUTF8(path.value());
+  return base::UTF16ToUTF8(path.value());
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   return path.value();
 #endif
@@ -540,7 +540,7 @@
   const char* path = sqlite3_db_filename(db_, "main");
   const base::StringPiece db_path(path);
 #if defined(OS_WIN)
-  return base::FilePath(base::UTF8ToWide(db_path));
+  return base::FilePath(base::UTF8ToUTF16(db_path));
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   return base::FilePath(db_path);
 #else
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6e6cf504..e919cd9a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4273,6 +4273,26 @@
             ]
         }
     ],
+    "SequenceManagerRollout": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "BlinkMainThreadUsesSequenceManager"
+                    ]
+                }
+            ]
+        }
+    ],
     "ServiceWorkerServicification": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/feature_policy/feature_policy.mojom b/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
index 33fc45b2..d5b45bf 100644
--- a/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
+++ b/third_party/blink/public/mojom/feature_policy/feature_policy.mojom
@@ -103,6 +103,8 @@
   kWakeLock = 31,
   // Controls access to font-display attribute in @font-face CSS rule
   kFontDisplay = 32,
+  // Sample Origin Trial enabled feature. This is used only for testing.
+  kFrobulate = 41,
 
   // These are the defined sandbox features implemented as policy-controlled
   // features.
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 6c73011..c1b7212 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -94,6 +94,7 @@
 
 namespace webrtc {
 struct RtpCapabilities;
+class AsyncResolverFactory;
 }
 
 namespace blink {
@@ -635,6 +636,10 @@
   virtual std::unique_ptr<cricket::PortAllocator> CreateWebRtcPortAllocator(
       WebLocalFrame* frame);
 
+  // May return null if WebRTC functionality is not implemented.
+  virtual std::unique_ptr<webrtc::AsyncResolverFactory>
+  CreateWebRtcAsyncResolverFactory();
+
   // Creates a WebCanvasCaptureHandler to capture Canvas output.
   virtual std::unique_ptr<WebCanvasCaptureHandler>
   CreateCanvasCaptureHandler(const WebSize&, double, WebMediaStreamTrack*);
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 07b4bcd2..7bb5f050 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -2213,6 +2213,7 @@
   kPerMethodCanMakePaymentQuota = 2773,
   kCSSValueAppearanceButtonForNonButtonRendered = 2774,
   kCSSValueAppearanceButtonForOthersRendered = 2775,
+  kCustomCursorIntersectsViewport = 2776,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index a63a29d..7b077dfa 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -6324,7 +6324,7 @@
     UseCounter::Count(*this, WebFeature::kFeaturePolicyHeader);
   Vector<String> messages;
   const ParsedFeaturePolicy& declared_policy = ParseFeaturePolicyHeader(
-      feature_policy_header, GetSecurityOrigin(), &messages);
+      feature_policy_header, GetSecurityOrigin(), &messages, this);
   for (auto& message : messages) {
     AddConsoleMessage(
         ConsoleMessage::Create(kSecurityMessageSource, kErrorMessageLevel,
@@ -6388,7 +6388,7 @@
   UseCounter::Count(*this, WebFeature::kFeaturePolicyReportOnlyHeader);
   Vector<String> messages;
   const ParsedFeaturePolicy& report_only_policy = ParseFeaturePolicyHeader(
-      feature_policy_report_only_header, GetSecurityOrigin(), &messages);
+      feature_policy_report_only_header, GetSecurityOrigin(), &messages, this);
   for (auto& message : messages) {
     AddConsoleMessage(ConsoleMessage::Create(
         kSecurityMessageSource, kErrorMessageLevel,
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy.cc b/third_party/blink/renderer/core/feature_policy/feature_policy.cc
index 7e527fe..0fb344f 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy.cc
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy.cc
@@ -7,6 +7,8 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
 #include "third_party/blink/renderer/platform/json/json_values.h"
 #include "third_party/blink/renderer/platform/network/http_parsers.h"
@@ -18,12 +20,39 @@
 
 namespace blink {
 
+namespace {
+
+// Returns true if this feature is currently disabled by an origin trial (it is
+// origin trial controlled, and the origin trial is not enabled).
+bool IsOriginTrialDisabled(const String& feature_name,
+                           const ExecutionContext* execution_context) {
+  bool (*origin_trial_enabled)(const blink::ExecutionContext*);
+
+  // All origin trial controlled features should be listed here.
+  if (feature_name == "frobulate") {
+    origin_trial_enabled = origin_trials::OriginTrialsSampleAPIEnabled;
+  } else {
+    return false;
+  }
+
+  // Impossible to know without an ExecutionContext, so block.
+  if (!execution_context)
+    return true;
+
+  // Check whether this feature's origin trial is enabled, and block otherwise.
+  DCHECK(origin_trial_enabled);
+  return !origin_trial_enabled(execution_context);
+}
+
+}  // namespace
+
 ParsedFeaturePolicy ParseFeaturePolicyHeader(
     const String& policy,
     scoped_refptr<const SecurityOrigin> origin,
-    Vector<String>* messages) {
+    Vector<String>* messages,
+    ExecutionContext* execution_context) {
   return ParseFeaturePolicy(policy, origin, nullptr, messages,
-                            GetDefaultFeatureNameMap());
+                            GetDefaultFeatureNameMap(), execution_context);
 }
 
 ParsedFeaturePolicy ParseFeaturePolicyAttribute(
@@ -42,7 +71,7 @@
     scoped_refptr<const SecurityOrigin> src_origin,
     Vector<String>* messages,
     const FeatureNameMap& feature_names,
-    Document* document) {
+    ExecutionContext* execution_context) {
   ParsedFeaturePolicy allowlists;
   BitVector features_specified(
       static_cast<int>(mojom::FeaturePolicyFeature::kMaxValue) + 1);
@@ -65,6 +94,7 @@
       // Empty policy. Skip.
       if (tokens.IsEmpty())
         continue;
+
       String feature_name = tokens[0];
       if (!feature_names.Contains(feature_name)) {
         if (messages) {
@@ -73,6 +103,14 @@
         continue;
       }
 
+      if (IsOriginTrialDisabled(feature_name, execution_context)) {
+        if (messages) {
+          messages->push_back("Origin trial controlled feature not enabled: '" +
+                              tokens[0] + "'.");
+        }
+        continue;
+      }
+
       mojom::FeaturePolicyFeature feature = feature_names.at(feature_name);
       // If a policy has already been specified for the current feature, drop
       // the new policy.
@@ -81,6 +119,7 @@
 
       // Count the use of this feature policy.
       if (src_origin) {
+        Document* document = DynamicTo<Document>(execution_context);
         if (!document || !document->IsParsedFeaturePolicy(feature)) {
           UMA_HISTOGRAM_ENUMERATION("Blink.UseCounter.FeaturePolicy.Allow",
                                     feature);
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy.h b/third_party/blink/renderer/core/feature_policy/feature_policy.h
index ce47d15..9cf3ee59 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy.h
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy.h
@@ -19,6 +19,7 @@
 namespace blink {
 
 class Document;
+class ExecutionContext;
 
 // Returns a map between feature name (string) and mojom::FeaturePolicyFeature
 // (enum).
@@ -26,15 +27,17 @@
 CORE_EXPORT const FeatureNameMap& GetDefaultFeatureNameMap();
 
 // Converts a header policy string into a vector of allowlists, one for each
-// feature specified. Unrecognized features are filtered out. If |messages|
-// is not null, then any message in the input will cause a warning message to be
-// appended to it.
+// feature specified. Unrecognized features are filtered out. If |messages| is
+// not null, then any message in the input will cause a warning message to be
+// appended to it. The optional ExecutionContext is used to determine if any
+// origin trials affect the parsing.
 // Example of a feature policy string:
 //     "vibrate a.com b.com; fullscreen 'none'; payment 'self', payment *".
 CORE_EXPORT ParsedFeaturePolicy
 ParseFeaturePolicyHeader(const String& policy,
                          scoped_refptr<const SecurityOrigin>,
-                         Vector<String>* messages);
+                         Vector<String>* messages,
+                         ExecutionContext* execution_context = nullptr);
 
 // Converts a container policy string into a vector of allowlists, given self
 // and src origins provided, one for each feature specified. Unrecognized
@@ -52,14 +55,16 @@
 // Converts a feature policy string into a vector of allowlists (see comments
 // above), with an explicit FeatureNameMap. This algorithm is called by both
 // header policy parsing and container policy parsing. |self_origin|,
-// |src_origin|, and |document| are nullable.
+// |src_origin|, and |execution_context| are nullable. The optional
+// ExecutionContext is used to determine if any origin trials affect the
+// parsing.
 CORE_EXPORT ParsedFeaturePolicy
 ParseFeaturePolicy(const String& policy,
                    scoped_refptr<const SecurityOrigin> self_origin,
                    scoped_refptr<const SecurityOrigin> src_origin,
                    Vector<String>* messages,
                    const FeatureNameMap& feature_names,
-                   Document* document = nullptr);
+                   ExecutionContext* execution_context = nullptr);
 
 // Returns true iff any declaration in the policy is for the given feature.
 CORE_EXPORT bool IsFeatureDeclared(mojom::FeaturePolicyFeature,
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index ee097e4..96d3a7a 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -594,6 +594,14 @@
                   "more details.",
                   MilestoneString(kM75))};
 
+    case WebFeature::kCustomCursorIntersectsViewport:
+      return {
+          "CustomCursorIntersectsViewport", kM75,
+          WillBeRemoved(
+              "Custom cursors with size greater than 32x32 DIP intersecting "
+              "native UI",
+              kM75, "5825971391299584")};
+
     // Features that aren't deprecated don't have a deprecation message.
     default:
       return {"NotDeprecated", kUnknown, ""};
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc
index 00cf6690..e62ac9f1 100644
--- a/third_party/blink/renderer/core/input/event_handler.cc
+++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -33,6 +33,7 @@
 
 #include "build/build_config.h"
 #include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/platform/web_feature.mojom-blink.h"
 #include "third_party/blink/public/platform/web_input_event.h"
 #include "third_party/blink/public/platform/web_mouse_wheel_event.h"
 #include "third_party/blink/renderer/core/clipboard/data_transfer.h"
@@ -129,6 +130,10 @@
 
 static const int kMaximumCursorSize = 128;
 
+// The maximum size a cursor can be without falling back to the default cursor
+// when intersecting browser native UI.
+static const int kMaximumCursorSizeWithoutFallback = 32;
+
 // It's pretty unlikely that a scale of less than one would ever be used. But
 // all we really need to ensure here is that the scale isn't so small that
 // integer overflow can occur when dividing cursor sizes (limited above) by the
@@ -473,9 +478,7 @@
         continue;
       float scale = style_image->ImageScaleFactor();
       bool hot_spot_specified = (*cursors)[i].HotSpotSpecified();
-      // Get hotspot and convert from logical pixels to physical pixels.
       IntPoint hot_spot = (*cursors)[i].HotSpot();
-      hot_spot.Scale(scale, scale);
       IntSize size = cached_image->GetImage()->Size();
       if (cached_image->ErrorOccurred())
         continue;
@@ -486,10 +489,27 @@
           size.Height() > kMaximumCursorSize)
         continue;
 
+      // For large cursors below the max size, limit their ability to cover UI
+      // elements by removing them when they intersect with the visual viewport.
+      // TODO(csharrison): Consider sending a fallback cursor in the IPC to the
+      // browser process so we can do that calculation there instead.
+      if (size.Width() > kMaximumCursorSizeWithoutFallback ||
+          size.Height() > kMaximumCursorSizeWithoutFallback) {
+        IntRect cursor_rect(IntPoint(location.RoundedPoint() - hot_spot), size);
+        IntRect visible_rect = page->GetVisualViewport().VisibleContentRect();
+        if (!visible_rect.Contains(cursor_rect)) {
+          Deprecation::CountDeprecation(
+              frame_, WebFeature::kCustomCursorIntersectsViewport);
+        }
+      }
+
       Image* image = cached_image->GetImage();
       // Ensure no overflow possible in calculations above.
       if (scale < kMinimumCursorScale)
         continue;
+
+      // Convert from logical pixels to physical pixels.
+      hot_spot.Scale(scale, scale);
       return Cursor(image, hot_spot_specified, hot_spot, scale);
     }
   }
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc b/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
index 97b2df1..6928a57 100644
--- a/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
+++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
@@ -9,10 +9,12 @@
 #include "third_party/blink/public/common/origin_trials/trial_token.h"
 #include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/feature_policy/feature_policy.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/html/html_head_element.h"
 #include "third_party/blink/renderer/core/html/html_meta_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
 #include "third_party/blink/renderer/core/testing/null_execution_context.h"
 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
@@ -222,4 +224,32 @@
   EXPECT_FALSE(OriginTrialContext::ParseHeaderValue("\"foo\" bar"));
 }
 
+TEST_F(OriginTrialContextTest, FeaturePolicy) {
+  // Create a dummy document with an OriginTrialContext.
+  std::unique_ptr<DummyPageHolder> dummy = DummyPageHolder::Create();
+  Document* document = &dummy->GetDocument();
+  OriginTrialContext* context = OriginTrialContext::FromOrCreate(document);
+
+  // Enable the sample origin trial API ("Frobulate").
+  context->AddFeature(origin_trials::kOriginTrialsSampleAPITrialName);
+  EXPECT_TRUE(
+      context->IsTrialEnabled(origin_trials::kOriginTrialsSampleAPITrialName));
+
+  // Make a mock feature name map with "frobulate".
+  FeatureNameMap feature_map;
+  feature_map.Set("frobulate", mojom::FeaturePolicyFeature::kFrobulate);
+
+  // Attempt to parse the "frobulate" feature policy. This will only work if the
+  // feature policy is successfully enabled via the origin trial.
+  scoped_refptr<const SecurityOrigin> security_origin =
+      SecurityOrigin::CreateFromString(kFrobulateEnabledOrigin);
+  Vector<String> messages;
+  ParsedFeaturePolicy result;
+  result = ParseFeaturePolicy("frobulate", security_origin, nullptr, &messages,
+                              feature_map, document);
+  EXPECT_TRUE(messages.IsEmpty());
+  ASSERT_EQ(1u, result.size());
+  EXPECT_EQ(mojom::FeaturePolicyFeature::kFrobulate, result[0].feature);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js b/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
index 6cf4926..035dde1 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
+++ b/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
@@ -563,7 +563,6 @@
       return;
 
     element.select();
-    event.consume(true);
   }
 
   /**
diff --git a/third_party/blink/renderer/devtools/front_end/resources/ClearStorageView.js b/third_party/blink/renderer/devtools/front_end/resources/ClearStorageView.js
index 89ff44d6..b164d80 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/ClearStorageView.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/ClearStorageView.js
@@ -117,7 +117,14 @@
    * @param {string} url
    */
   _updateOrigin(url) {
-    this._securityOrigin = new Common.ParsedURL(url).securityOrigin();
+    const parsedURL = new Common.ParsedURL(url);
+    if (!parsedURL.isValid) {
+      this._clearButton.disabled = true;
+      this._securityOrigin = '';
+    } else {
+      this._clearButton.disabled = false;
+      this._securityOrigin = parsedURL.securityOrigin();
+    }
     this._reportView.setSubtitle(this._securityOrigin);
     this.doUpdate();
   }
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
index f14f11e8..1bed259 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
@@ -11,8 +11,11 @@
 IceTransportAdapterImpl::IceTransportAdapterImpl(
     Delegate* delegate,
     std::unique_ptr<cricket::PortAllocator> port_allocator,
+    std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory,
     rtc::Thread* thread)
-    : delegate_(delegate), port_allocator_(std::move(port_allocator)) {
+    : delegate_(delegate),
+      port_allocator_(std::move(port_allocator)),
+      async_resolver_factory_(std::move(async_resolver_factory)) {
   // TODO(bugs.webrtc.org/9419): Remove once WebRTC can be built as a component.
   if (!rtc::ThreadManager::Instance()->CurrentThread()) {
     rtc::ThreadManager::Instance()->SetCurrentThread(thread);
@@ -28,7 +31,7 @@
   port_allocator_->Initialize();
 
   p2p_transport_channel_ = std::make_unique<cricket::P2PTransportChannel>(
-      "", 0, port_allocator_.get());
+      "", 0, port_allocator_.get(), async_resolver_factory.get());
   p2p_transport_channel_->SignalGatheringState.connect(
       this, &IceTransportAdapterImpl::OnGatheringStateChanged);
   p2p_transport_channel_->SignalCandidateGathered.connect(
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
index fd620d9..5293bd23 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
@@ -21,6 +21,7 @@
   IceTransportAdapterImpl(
       Delegate* delegate,
       std::unique_ptr<cricket::PortAllocator> port_allocator,
+      std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory,
       rtc::Thread* thread);
   ~IceTransportAdapterImpl() override;
 
@@ -51,6 +52,7 @@
 
   Delegate* const delegate_;
   std::unique_ptr<cricket::PortAllocator> port_allocator_;
+  std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_;
   std::unique_ptr<cricket::IceTransportInternal> p2p_transport_channel_;
   std::unique_ptr<P2PQuicPacketTransport> quic_packet_transport_adapter_;
 };
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
index b3384e21..65a727db 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
@@ -58,8 +58,11 @@
   void InitializeOnMainThread(LocalFrame& frame) override {
     DCHECK(!port_allocator_);
     DCHECK(!worker_thread_rtc_thread_);
+    DCHECK(!async_resolver_factory_);
     port_allocator_ = Platform::Current()->CreateWebRtcPortAllocator(
         frame.Client()->GetWebFrame());
+    async_resolver_factory_ =
+        Platform::Current()->CreateWebRtcAsyncResolverFactory();
     worker_thread_rtc_thread_ =
         Platform::Current()->GetWebRtcWorkerThreadRtcThread();
   }
@@ -68,12 +71,15 @@
       IceTransportAdapter::Delegate* delegate) override {
     DCHECK(port_allocator_);
     DCHECK(worker_thread_rtc_thread_);
+    DCHECK(async_resolver_factory_);
     return std::make_unique<IceTransportAdapterImpl>(
-        delegate, std::move(port_allocator_), worker_thread_rtc_thread_);
+        delegate, std::move(port_allocator_),
+        std::move(async_resolver_factory_), worker_thread_rtc_thread_);
   }
 
  private:
   std::unique_ptr<cricket::PortAllocator> port_allocator_;
+  std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_;
   rtc::Thread* worker_thread_rtc_thread_ = nullptr;
 };
 
diff --git a/third_party/blink/renderer/platform/exported/platform.cc b/third_party/blink/renderer/platform/exported/platform.cc
index 20b35af..fcea591 100644
--- a/third_party/blink/renderer/platform/exported/platform.cc
+++ b/third_party/blink/renderer/platform/exported/platform.cc
@@ -67,6 +67,7 @@
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/webrtc/api/async_resolver_factory.h"
 #include "third_party/webrtc/api/rtp_parameters.h"
 #include "third_party/webrtc/p2p/base/port_allocator.h"
 
@@ -315,6 +316,11 @@
   return nullptr;
 }
 
+std::unique_ptr<webrtc::AsyncResolverFactory>
+Platform::CreateWebRtcAsyncResolverFactory() {
+  return nullptr;
+}
+
 std::unique_ptr<WebMediaRecorderHandler> Platform::CreateMediaRecorderHandler(
     scoped_refptr<base::SingleThreadTaskRunner>) {
   return nullptr;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_color_params.h b/third_party/blink/renderer/platform/graphics/canvas_color_params.h
index e068a435..71e73d2 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_color_params.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_color_params.h
@@ -13,6 +13,7 @@
 #include "ui/gfx/buffer_types.h"
 
 class SkCanvas;
+class SkSurfaceProps;
 
 namespace cc {
 class PaintCanvas;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 4f7edc8b..3913580 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5975,6 +5975,8 @@
 crbug.com/922951 virtual/video-surface-layer/media/controls/overflow-menu-hide-on-click-panel.html [ Skip ]
 crbug.com/922951 virtual/video-surface-layer/media/controls/overflow-menu-toggle-class-for-animation.html [ Skip ]
 
+crbug.com/927866 external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Pass Failure ]
+
 # Race: The RTCIceConnectionState can become "connected" before getStats()
 # returns candidate-pair whose state is "succeeded", this sounds like a
 # contradiction.
@@ -6031,3 +6033,6 @@
 crbug.com/927296 virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js [ Pass Failure ]
 
 crbug.com/927334 [ Win ] fast/dom/document-contentType-data-uri.html [ Pass Failure ]
+
+# Sheriff 2019-02-01
+crbug.com/927862 [ Win10 ] virtual/user-activation-v2/fast/events/mousemove-to-scrollbar-changes-cursor.html [ Skip ]
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-fill-mode.https.html b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-fill-mode.https.html
index 49fead8..b910ab2 100644
--- a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-fill-mode.https.html
+++ b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-with-fill-mode.https.html
@@ -14,83 +14,146 @@
 }
 </style>
 
-<script>
-function CreateTest(target, effect, verify, test_name) {
-  promise_test(async function() {
-    await registerConstantLocalTimeAnimator(2000);
-    const animation = new WorkletAnimation('constant_time', effect);
-    animation.play();
+<div id="target" class='target'></div>
 
-    await waitForAsyncAnimationFrames(1);
-    // waitTwoAnimationFrames guarantees a compositor frame that could update
-    // the opacity value in the worklet. Meanwhile, getComputedStyle needs an
-    // extra frame to fetch the updated value.
-    await waitForNextFrame();
-    verify();
-    animation.cancel();
-  }, test_name);
+<script>
+setup(setupAndRegisterTests, {explicit_done: true});
+
+function setupAndRegisterTests() {
+  registerConstantLocalTimeAnimator(2000).then(() => {
+    promise_test(
+        effect_with_fill_mode_forwards,
+        "Effect with fill mode forwards in after phase produces output that is equivalent to effect's end value.");
+
+    promise_test(
+        effect_without_fill_mode_forwards,
+        'Effect without fill mode forwards in after phase (local time beyond end) should deactivate the animation.');
+
+    promise_test(
+        effect_without_fill_forwards_at_end,
+        'Effect without fill mode in after phase (local time at end) should deactivate the animation.');
+
+    promise_test(
+        effect_with_fill_backwards,
+        "Effect with fill mode backwards in before phase produces output that is equivalent to effect's start value.");
+
+    promise_test(
+        effect_without_fill_backwards,
+        'Effect without fill mode backwards in before phase (local time before start) should deactivate the animation.');
+
+    promise_test(
+        effect_without_fill_backwards_at_start,
+        'Effect with local time at start point is in active phase.');
+
+    done();
+  });
 }
-</script>
 
-<div id="target1" class='target'></div>
-<div id="target2" class='target'></div>
-<div id="target3" class='target'></div>
-<div id="target4" class='target'></div>
-<div id="target5" class='target'></div>
-<div id="target6" class='target'></div>
+async function effect_with_fill_mode_forwards(t) {
+      const effect_with_fill_forwards = new KeyframeEffect(
+          target,
+          { opacity: [0.5, 0] },
+          { duration: 1000, fill: 'forwards' });
+      const animation = new WorkletAnimation(
+          'constant_time',
+          effect_with_fill_forwards);
+      animation.play();
 
-<script>
-  const effect_with_fill_forwards = new KeyframeEffect(
-      target1,
-      { opacity: [0.5, 0] },
-      { duration: 1000, fill: 'forwards' });
-  CreateTest(target1,
-      effect_with_fill_forwards,
-      function() { assert_equals(getComputedStyle(target1).opacity, '0'); },
-      "Effect with fill mode forwards in after phase produces output that is equivalent to effect's end value.");
+      await waitForAsyncAnimationFrames(1);
+      await waitForNextFrame();
 
-  const effect_without_fill_forwards = new KeyframeEffect(
-      target2,
-      { opacity: [0.5, 0] },
-      { duration: 1000 });
-  CreateTest(target2,
-      effect_without_fill_forwards,
-      function() { assert_equals(getComputedStyle(target2).opacity, '1'); },
-      'Effect without fill mode forwards in after phase (local time beyond end) should deactivate the animation.');
+      assert_equals(getComputedStyle(target).opacity, '0');
 
-  const effect_without_fill_forwards_at_end = new KeyframeEffect(
-      target3,
-      { opacity: [0.5, 0] },
-      { duration: 2000 });
-  CreateTest(target3,
-      effect_without_fill_forwards_at_end,
-      function() { assert_equals(getComputedStyle(target3).opacity, '1'); },
-      'Effect without fill mode in after phase (local time at end) should deactivate the animation.');
+      animation.cancel();
+}
 
-  const effect_with_fill_backwards = new KeyframeEffect(
-      target4,
-      { opacity: [0.5, 0] },
-      { duration: 1000, delay: 2001, fill: 'backwards' });
-  CreateTest(target4,
-      effect_with_fill_backwards,
-      function() { assert_equals(getComputedStyle(target4).opacity, '0.5'); },
-      "Effect with fill mode backwards in before phase produces output that is equivalent to effect's start value.");
+async function effect_without_fill_mode_forwards(t) {
+      const effect_without_fill_forwards = new KeyframeEffect(
+          target,
+          { opacity: [0.5, 0] },
+          { duration: 1000 });
+      const animation = new WorkletAnimation(
+          'constant_time',
+          effect_without_fill_forwards);
+      animation.play();
 
-  const effect_without_fill_backwards = new KeyframeEffect(
-      target5,
-      { opacity: [0.5, 0] },
-      { duration: 1000, delay: 2001 });
-  CreateTest(target5,
-      effect_without_fill_backwards,
-      function() { assert_equals(getComputedStyle(target5).opacity, '1'); },
-      'Effect without fill mode backwards in before phase (local time before start) should deactivate the animation.');
+      await waitForAsyncAnimationFrames(1);
+      await waitForNextFrame();
 
-  const effect_without_fill_backwards_at_start = new KeyframeEffect(
-      target6,
-      { opacity: [0.5, 0] },
-      { duration: 1000, delay: 2000 });
-  CreateTest(target6,
-      effect_without_fill_backwards_at_start,
-      function() { assert_equals(getComputedStyle(target6).opacity, '0.5'); },
-      'Effect with local time at start point is in active phase.');
+      assert_equals(getComputedStyle(target).opacity, '1');
+
+      animation.cancel();
+}
+
+async function effect_without_fill_forwards_at_end(t) {
+      const effect_without_fill_forwards_at_end = new KeyframeEffect(
+          target,
+          { opacity: [0.5, 0] },
+          { duration: 2000 });
+      const animation = new WorkletAnimation(
+          'constant_time',
+          effect_without_fill_forwards_at_end);
+      animation.play();
+
+      await waitForAsyncAnimationFrames(1);
+      await waitForNextFrame();
+
+      assert_equals(getComputedStyle(target).opacity, '1');
+
+      animation.cancel();
+}
+
+async function effect_with_fill_backwards(t) {
+      const effect_with_fill_backwards = new KeyframeEffect(
+          target,
+          { opacity: [0.5, 0] },
+          { duration: 1000, delay: 2001, fill: 'backwards' });
+      const animation = new WorkletAnimation(
+          'constant_time',
+          effect_with_fill_backwards);
+      animation.play();
+
+      await waitForAsyncAnimationFrames(1);
+      await waitForNextFrame();
+
+      assert_equals(getComputedStyle(target).opacity, '0.5');
+
+      animation.cancel();
+}
+
+async function effect_without_fill_backwards(t) {
+      const effect_without_fill_backwards = new KeyframeEffect(
+          target,
+          { opacity: [0.5, 0] },
+          { duration: 1000, delay: 2001 });
+      const animation = new WorkletAnimation(
+          'constant_time',
+          effect_without_fill_backwards);
+      animation.play();
+
+      await waitForAsyncAnimationFrames(1);
+      await waitForNextFrame();
+
+      assert_equals(getComputedStyle(target).opacity, '1');
+
+      animation.cancel();
+}
+
+async function effect_without_fill_backwards_at_start(t) {
+      const effect_without_fill_backwards_at_start = new KeyframeEffect(
+          target,
+          { opacity: [0.5, 0] },
+          { duration: 1000, delay: 2000 });
+      const animation = new WorkletAnimation(
+          'constant_time',
+          effect_without_fill_backwards_at_start);
+      animation.play();
+
+      await waitForAsyncAnimationFrames(1);
+      await waitForNextFrame();
+
+      assert_equals(getComputedStyle(target).opacity, '0.5');
+
+      animation.cancel();
+}
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-no-browsing-context.html b/third_party/blink/web_tests/external/wpt/portals/portals-activate-no-browsing-context.html
index 9a822e92..6eebca9 100644
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-no-browsing-context.html
+++ b/third_party/blink/web_tests/external/wpt/portals/portals-activate-no-browsing-context.html
@@ -2,11 +2,8 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
-promise_test(async () => {
+promise_test(async t => {
   let activatePromise = document.createElement('portal').activate();
-  await activatePromise.then(() => assert_unreached(), e => {
-    assert_true(e instanceof DOMException);
-    assert_equals(e.name, 'InvalidStateError');
-  });
+  await promise_rejects(t, 'InvalidStateError', activatePromise);
 }, "A portal with nothing in it cannot be activated");
 </script>
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.png
index 7beac27..8036f09 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/backgrounds/background-leakage-transforms-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png
index 265da8e..699bdd9e 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-cell-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-cell-collapsed-border-expected.png
index d3f7721..365db25 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-cell-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-cell-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-cell-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-cell-expected.png
index 578e81f..fdd9477 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-cell-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-cell-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-collapsed-border-expected.png
index b97ddd85..92fe6840 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-collapsed-border-expected.png
index 4366b323..e3de8e06 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-expected.png
index bbe08be..e30c2f5 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-group-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
index 47b0223..2e16351 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-group-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-group-expected.png
index 87c043b..2b4eabbb 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-group-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-column-group-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-expected.png
index 662f3b4..0ed704a 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
index c2ac289..3cd06ad 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-expected.png
index 5182b3c..d323e585 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-collapsed-border-expected.png
index 01b0ca9..2e80339 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-expected.png
index 3d58398a..aa62dde 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-group-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-group-collapsed-border-expected.png
index 2533a49..920e70c7 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-group-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-group-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-group-expected.png
index ae6f1336..efac8482 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-group-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-row-group-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-hide-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-hide-collapsed-border-expected.png
index 0c62cd7..ab78701 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-hide-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-hide-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-hide-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-hide-expected.png
index b743b695..d67b21f 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-hide-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-hide-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-cell-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-cell-collapsed-border-expected.png
index c0c2cf4..aacd479 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-cell-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-cell-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-cell-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-cell-expected.png
index d88e1d7e..6cd5af3 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-cell-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-cell-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-collapsed-border-expected.png
index 88e0ff6..50a424c 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-collapsed-border-expected.png
index 3e58af85..1ed967c 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-expected.png
index 8ef7538..c1130edc 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-group-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-group-collapsed-border-expected.png
index 002523f5b..408d804 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-group-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-group-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-group-expected.png
index 8d79c10a..a2b57e4f 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-group-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-column-group-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-expected.png
index 7236c686..cf640f9 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-collapsed-border-expected.png
index 8dab848..03ac644 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-expected.png
index de21a28..c7747e5 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-group-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-group-collapsed-border-expected.png
index 9456c1ce2..3ddabe2 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-group-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-group-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-group-expected.png
index b1b9f52..de88571 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-group-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_position-table-row-group-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-cell-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-cell-collapsed-border-expected.png
index 34e7f00a..5148c22 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-cell-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-cell-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-cell-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-cell-expected.png
index d6e21a1..00c2bd1 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-cell-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-cell-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-collapsed-border-expected.png
index 6ad2717..51e47b0 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-collapsed-border-expected.png
index dd98cb6..1a7e6c9a 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-expected.png
index e6fc266..9113991d 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-group-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-group-collapsed-border-expected.png
index c07615146..133ab8f 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-group-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-group-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-group-expected.png
index 07e3fc0..611cbc2 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-group-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-column-group-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-expected.png
index d296924..539ef9cfc 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-collapsed-border-expected.png
index f4b956c..c07e33a 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-expected.png
index b95a1a3..8ea6ea76 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-group-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-group-collapsed-border-expected.png
index 48c13d49..1d0c6106 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-group-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-group-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-group-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-group-expected.png
index 866dc99b..18241b6 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-group-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_simple-table-row-group-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/border-collapsing/002-vertical-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/border-collapsing/002-vertical-expected.png
index d283f262..79ab5e58 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/border-collapsing/002-vertical-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/border-collapsing/002-vertical-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/inline-spelling-markers-hidpi-composited-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/inline-spelling-markers-hidpi-composited-expected.png
index 1add152..00a8126 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/inline-spelling-markers-hidpi-composited-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/inline-spelling-markers-hidpi-composited-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/inline-spelling-markers-hidpi-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/inline-spelling-markers-hidpi-expected.png
index 1add152..00a8126 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/inline-spelling-markers-hidpi-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/inline-spelling-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/markers-zoomed-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/markers-zoomed-expected.png
index a5a82aa..f543e00 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/markers-zoomed-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/markers-zoomed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/svg/custom/clone-element-with-animated-svg-properties-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/svg/custom/clone-element-with-animated-svg-properties-expected.png
index ae5fa19..b073059 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/svg/custom/clone-element-with-animated-svg-properties-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/svg/custom/clone-element-with-animated-svg-properties-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index 3cd4ef1..0c01241 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance-expected.png
index 46734dc4..7a557d5 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance-expected.png
index 46734dc4..7a557d5 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/parsed-url-expected.txt b/third_party/blink/web_tests/http/tests/devtools/components/parsed-url-expected.txt
index d31cb6b..7d221e91 100644
--- a/third_party/blink/web_tests/http/tests/devtools/components/parsed-url-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/components/parsed-url-expected.txt
@@ -44,6 +44,28 @@
   fragment: fragmentWith/Many//Slashes
   folderPathComponents: /foo/bar
   lastPathComponent: baz.html
+Parsing url: ://
+  isValid: false
+  scheme: 
+  user: 
+  host: 
+  port: 
+  path: ://
+  queryParams: 
+  fragment: 
+  folderPathComponents: :/
+  lastPathComponent: 
+Parsing url: 
+  isValid: false
+  scheme: 
+  user: 
+  host: 
+  port: 
+  path: 
+  queryParams: 
+  fragment: 
+  folderPathComponents: 
+  lastPathComponent: 
 Parsing url: http://[::]/?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes
   isValid: true
   scheme: http
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/parsed-url.js b/third_party/blink/web_tests/http/tests/devtools/components/parsed-url.js
index e3e41a8..baea7bd 100644
--- a/third_party/blink/web_tests/http/tests/devtools/components/parsed-url.js
+++ b/third_party/blink/web_tests/http/tests/devtools/components/parsed-url.js
@@ -11,6 +11,8 @@
       'http://user42:Alina-!$&@example.com/foo/bar.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes');
   parseAndDumpURL(
       'http://foo@example.com/foo/bar/baz.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes');
+  parseAndDumpURL('://');
+  parseAndDumpURL('');
 
   // support IPv6 localhost
   parseAndDumpURL('http://[::]/?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes');
diff --git a/third_party/boringssl/BUILD.generated.gni b/third_party/boringssl/BUILD.generated.gni
index fc9ee9b..4453b14 100644
--- a/third_party/boringssl/BUILD.generated.gni
+++ b/third_party/boringssl/BUILD.generated.gni
@@ -462,6 +462,7 @@
   "linux-x86/crypto/fipsmodule/sha512-586.S",
   "linux-x86/crypto/fipsmodule/vpaes-x86.S",
   "linux-x86/crypto/fipsmodule/x86-mont.S",
+  "linux-x86/crypto/test/trampoline-x86.S",
 ]
 
 crypto_sources_linux_x86_64 = [
@@ -502,6 +503,7 @@
   "mac-x86/crypto/fipsmodule/sha512-586.S",
   "mac-x86/crypto/fipsmodule/vpaes-x86.S",
   "mac-x86/crypto/fipsmodule/x86-mont.S",
+  "mac-x86/crypto/test/trampoline-x86.S",
 ]
 
 crypto_sources_mac_x86_64 = [
@@ -541,6 +543,7 @@
   "win-x86/crypto/fipsmodule/sha512-586.asm",
   "win-x86/crypto/fipsmodule/vpaes-x86.asm",
   "win-x86/crypto/fipsmodule/x86-mont.asm",
+  "win-x86/crypto/test/trampoline-x86.asm",
 ]
 
 crypto_sources_win_x86_64 = [
diff --git a/third_party/boringssl/linux-x86/crypto/test/trampoline-x86.S b/third_party/boringssl/linux-x86/crypto/test/trampoline-x86.S
new file mode 100644
index 0000000..2222347a
--- /dev/null
+++ b/third_party/boringssl/linux-x86/crypto/test/trampoline-x86.S
@@ -0,0 +1,205 @@
+# This file is generated from a similarly-named Perl script in the BoringSSL
+# source tree. Do not edit by hand.
+
+#if defined(__i386__)
+#if defined(BORINGSSL_PREFIX)
+#include <boringssl_prefix_symbols_asm.h>
+#endif
+.text
+.globl	abi_test_trampoline
+.hidden	abi_test_trampoline
+.type	abi_test_trampoline,@function
+.align	16
+abi_test_trampoline:
+.L_abi_test_trampoline_begin:
+	pushl	%ebp
+	pushl	%ebx
+	pushl	%esi
+	pushl	%edi
+	movl	24(%esp),%ecx
+	movl	(%ecx),%esi
+	movl	4(%ecx),%edi
+	movl	8(%ecx),%ebx
+	movl	12(%ecx),%ebp
+	subl	$44,%esp
+	movl	72(%esp),%eax
+	xorl	%ecx,%ecx
+.L000loop:
+	cmpl	76(%esp),%ecx
+	jae	.L001loop_done
+	movl	(%eax,%ecx,4),%edx
+	movl	%edx,(%esp,%ecx,4)
+	addl	$1,%ecx
+	jmp	.L000loop
+.L001loop_done:
+	call	*64(%esp)
+	addl	$44,%esp
+	movl	24(%esp),%ecx
+	movl	%esi,(%ecx)
+	movl	%edi,4(%ecx)
+	movl	%ebx,8(%ecx)
+	movl	%ebp,12(%ecx)
+	popl	%edi
+	popl	%esi
+	popl	%ebx
+	popl	%ebp
+	ret
+.size	abi_test_trampoline,.-.L_abi_test_trampoline_begin
+.globl	abi_test_get_and_clear_direction_flag
+.hidden	abi_test_get_and_clear_direction_flag
+.type	abi_test_get_and_clear_direction_flag,@function
+.align	16
+abi_test_get_and_clear_direction_flag:
+.L_abi_test_get_and_clear_direction_flag_begin:
+	pushfl
+	popl	%eax
+	andl	$1024,%eax
+	shrl	$10,%eax
+	cld
+	ret
+.size	abi_test_get_and_clear_direction_flag,.-.L_abi_test_get_and_clear_direction_flag_begin
+.globl	abi_test_set_direction_flag
+.hidden	abi_test_set_direction_flag
+.type	abi_test_set_direction_flag,@function
+.align	16
+abi_test_set_direction_flag:
+.L_abi_test_set_direction_flag_begin:
+	std
+	ret
+.size	abi_test_set_direction_flag,.-.L_abi_test_set_direction_flag_begin
+.globl	abi_test_clobber_eax
+.hidden	abi_test_clobber_eax
+.type	abi_test_clobber_eax,@function
+.align	16
+abi_test_clobber_eax:
+.L_abi_test_clobber_eax_begin:
+	xorl	%eax,%eax
+	ret
+.size	abi_test_clobber_eax,.-.L_abi_test_clobber_eax_begin
+.globl	abi_test_clobber_ebx
+.hidden	abi_test_clobber_ebx
+.type	abi_test_clobber_ebx,@function
+.align	16
+abi_test_clobber_ebx:
+.L_abi_test_clobber_ebx_begin:
+	xorl	%ebx,%ebx
+	ret
+.size	abi_test_clobber_ebx,.-.L_abi_test_clobber_ebx_begin
+.globl	abi_test_clobber_ecx
+.hidden	abi_test_clobber_ecx
+.type	abi_test_clobber_ecx,@function
+.align	16
+abi_test_clobber_ecx:
+.L_abi_test_clobber_ecx_begin:
+	xorl	%ecx,%ecx
+	ret
+.size	abi_test_clobber_ecx,.-.L_abi_test_clobber_ecx_begin
+.globl	abi_test_clobber_edx
+.hidden	abi_test_clobber_edx
+.type	abi_test_clobber_edx,@function
+.align	16
+abi_test_clobber_edx:
+.L_abi_test_clobber_edx_begin:
+	xorl	%edx,%edx
+	ret
+.size	abi_test_clobber_edx,.-.L_abi_test_clobber_edx_begin
+.globl	abi_test_clobber_edi
+.hidden	abi_test_clobber_edi
+.type	abi_test_clobber_edi,@function
+.align	16
+abi_test_clobber_edi:
+.L_abi_test_clobber_edi_begin:
+	xorl	%edi,%edi
+	ret
+.size	abi_test_clobber_edi,.-.L_abi_test_clobber_edi_begin
+.globl	abi_test_clobber_esi
+.hidden	abi_test_clobber_esi
+.type	abi_test_clobber_esi,@function
+.align	16
+abi_test_clobber_esi:
+.L_abi_test_clobber_esi_begin:
+	xorl	%esi,%esi
+	ret
+.size	abi_test_clobber_esi,.-.L_abi_test_clobber_esi_begin
+.globl	abi_test_clobber_ebp
+.hidden	abi_test_clobber_ebp
+.type	abi_test_clobber_ebp,@function
+.align	16
+abi_test_clobber_ebp:
+.L_abi_test_clobber_ebp_begin:
+	xorl	%ebp,%ebp
+	ret
+.size	abi_test_clobber_ebp,.-.L_abi_test_clobber_ebp_begin
+.globl	abi_test_clobber_xmm0
+.hidden	abi_test_clobber_xmm0
+.type	abi_test_clobber_xmm0,@function
+.align	16
+abi_test_clobber_xmm0:
+.L_abi_test_clobber_xmm0_begin:
+	pxor	%xmm0,%xmm0
+	ret
+.size	abi_test_clobber_xmm0,.-.L_abi_test_clobber_xmm0_begin
+.globl	abi_test_clobber_xmm1
+.hidden	abi_test_clobber_xmm1
+.type	abi_test_clobber_xmm1,@function
+.align	16
+abi_test_clobber_xmm1:
+.L_abi_test_clobber_xmm1_begin:
+	pxor	%xmm1,%xmm1
+	ret
+.size	abi_test_clobber_xmm1,.-.L_abi_test_clobber_xmm1_begin
+.globl	abi_test_clobber_xmm2
+.hidden	abi_test_clobber_xmm2
+.type	abi_test_clobber_xmm2,@function
+.align	16
+abi_test_clobber_xmm2:
+.L_abi_test_clobber_xmm2_begin:
+	pxor	%xmm2,%xmm2
+	ret
+.size	abi_test_clobber_xmm2,.-.L_abi_test_clobber_xmm2_begin
+.globl	abi_test_clobber_xmm3
+.hidden	abi_test_clobber_xmm3
+.type	abi_test_clobber_xmm3,@function
+.align	16
+abi_test_clobber_xmm3:
+.L_abi_test_clobber_xmm3_begin:
+	pxor	%xmm3,%xmm3
+	ret
+.size	abi_test_clobber_xmm3,.-.L_abi_test_clobber_xmm3_begin
+.globl	abi_test_clobber_xmm4
+.hidden	abi_test_clobber_xmm4
+.type	abi_test_clobber_xmm4,@function
+.align	16
+abi_test_clobber_xmm4:
+.L_abi_test_clobber_xmm4_begin:
+	pxor	%xmm4,%xmm4
+	ret
+.size	abi_test_clobber_xmm4,.-.L_abi_test_clobber_xmm4_begin
+.globl	abi_test_clobber_xmm5
+.hidden	abi_test_clobber_xmm5
+.type	abi_test_clobber_xmm5,@function
+.align	16
+abi_test_clobber_xmm5:
+.L_abi_test_clobber_xmm5_begin:
+	pxor	%xmm5,%xmm5
+	ret
+.size	abi_test_clobber_xmm5,.-.L_abi_test_clobber_xmm5_begin
+.globl	abi_test_clobber_xmm6
+.hidden	abi_test_clobber_xmm6
+.type	abi_test_clobber_xmm6,@function
+.align	16
+abi_test_clobber_xmm6:
+.L_abi_test_clobber_xmm6_begin:
+	pxor	%xmm6,%xmm6
+	ret
+.size	abi_test_clobber_xmm6,.-.L_abi_test_clobber_xmm6_begin
+.globl	abi_test_clobber_xmm7
+.hidden	abi_test_clobber_xmm7
+.type	abi_test_clobber_xmm7,@function
+.align	16
+abi_test_clobber_xmm7:
+.L_abi_test_clobber_xmm7_begin:
+	pxor	%xmm7,%xmm7
+	ret
+.size	abi_test_clobber_xmm7,.-.L_abi_test_clobber_xmm7_begin
+#endif
diff --git a/third_party/boringssl/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S b/third_party/boringssl/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S
index 8811c00..bfdc965f 100644
--- a/third_party/boringssl/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S
+++ b/third_party/boringssl/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S
@@ -1228,6 +1228,7 @@
 .type	rsaz_1024_red2norm_avx2,@function
 .align	32
 rsaz_1024_red2norm_avx2:
+.cfi_startproc	
 	subq	$-128,%rsi
 	xorq	%rax,%rax
 	movq	-128(%rsi),%r8
@@ -1419,6 +1420,7 @@
 	movq	%rax,120(%rdi)
 	movq	%r11,%rax
 	.byte	0xf3,0xc3
+.cfi_endproc	
 .size	rsaz_1024_red2norm_avx2,.-rsaz_1024_red2norm_avx2
 
 .globl	rsaz_1024_norm2red_avx2
@@ -1426,6 +1428,7 @@
 .type	rsaz_1024_norm2red_avx2,@function
 .align	32
 rsaz_1024_norm2red_avx2:
+.cfi_startproc	
 	subq	$-128,%rdi
 	movq	(%rsi),%r8
 	movl	$0x1fffffff,%eax
@@ -1578,12 +1581,14 @@
 	movq	%r8,176(%rdi)
 	movq	%r8,184(%rdi)
 	.byte	0xf3,0xc3
+.cfi_endproc	
 .size	rsaz_1024_norm2red_avx2,.-rsaz_1024_norm2red_avx2
 .globl	rsaz_1024_scatter5_avx2
 .hidden rsaz_1024_scatter5_avx2
 .type	rsaz_1024_scatter5_avx2,@function
 .align	32
 rsaz_1024_scatter5_avx2:
+.cfi_startproc	
 	vzeroupper
 	vmovdqu	.Lscatter_permd(%rip),%ymm5
 	shll	$4,%edx
@@ -1603,6 +1608,7 @@
 
 	vzeroupper
 	.byte	0xf3,0xc3
+.cfi_endproc	
 .size	rsaz_1024_scatter5_avx2,.-rsaz_1024_scatter5_avx2
 
 .globl	rsaz_1024_gather5_avx2
@@ -1727,25 +1733,6 @@
 .cfi_endproc	
 .LSEH_end_rsaz_1024_gather5:
 .size	rsaz_1024_gather5_avx2,.-rsaz_1024_gather5_avx2
-.extern	OPENSSL_ia32cap_P
-.hidden OPENSSL_ia32cap_P
-.globl	rsaz_avx2_eligible
-.hidden rsaz_avx2_eligible
-.type	rsaz_avx2_eligible,@function
-.align	32
-rsaz_avx2_eligible:
-	leaq	OPENSSL_ia32cap_P(%rip),%rax
-	movl	8(%rax),%eax
-	movl	$524544,%ecx
-	movl	$0,%edx
-	andl	%eax,%ecx
-	cmpl	$524544,%ecx
-	cmovel	%edx,%eax
-	andl	$32,%eax
-	shrl	$5,%eax
-	.byte	0xf3,0xc3
-.size	rsaz_avx2_eligible,.-rsaz_avx2_eligible
-
 .align	64
 .Land_mask:
 .quad	0x1fffffff,0x1fffffff,0x1fffffff,0x1fffffff
diff --git a/third_party/boringssl/linux-x86_64/crypto/test/trampoline-x86_64.S b/third_party/boringssl/linux-x86_64/crypto/test/trampoline-x86_64.S
index f2af98c..666ac40 100644
--- a/third_party/boringssl/linux-x86_64/crypto/test/trampoline-x86_64.S
+++ b/third_party/boringssl/linux-x86_64/crypto/test/trampoline-x86_64.S
@@ -489,7 +489,7 @@
 	pushfq
 	popq	%rax
 	andq	$0x400,%rax
-	shlq	$10,%rax
+	shrq	$10,%rax
 	cld
 	.byte	0xf3,0xc3
 .size	abi_test_get_and_clear_direction_flag,.-abi_test_get_and_clear_direction_flag
diff --git a/third_party/boringssl/mac-x86/crypto/test/trampoline-x86.S b/third_party/boringssl/mac-x86/crypto/test/trampoline-x86.S
new file mode 100644
index 0000000..601f2f0
--- /dev/null
+++ b/third_party/boringssl/mac-x86/crypto/test/trampoline-x86.S
@@ -0,0 +1,169 @@
+# This file is generated from a similarly-named Perl script in the BoringSSL
+# source tree. Do not edit by hand.
+
+#if defined(__i386__)
+#if defined(BORINGSSL_PREFIX)
+#include <boringssl_prefix_symbols_asm.h>
+#endif
+.text
+.globl	_abi_test_trampoline
+.private_extern	_abi_test_trampoline
+.align	4
+_abi_test_trampoline:
+L_abi_test_trampoline_begin:
+	pushl	%ebp
+	pushl	%ebx
+	pushl	%esi
+	pushl	%edi
+	movl	24(%esp),%ecx
+	movl	(%ecx),%esi
+	movl	4(%ecx),%edi
+	movl	8(%ecx),%ebx
+	movl	12(%ecx),%ebp
+	subl	$44,%esp
+	movl	72(%esp),%eax
+	xorl	%ecx,%ecx
+L000loop:
+	cmpl	76(%esp),%ecx
+	jae	L001loop_done
+	movl	(%eax,%ecx,4),%edx
+	movl	%edx,(%esp,%ecx,4)
+	addl	$1,%ecx
+	jmp	L000loop
+L001loop_done:
+	call	*64(%esp)
+	addl	$44,%esp
+	movl	24(%esp),%ecx
+	movl	%esi,(%ecx)
+	movl	%edi,4(%ecx)
+	movl	%ebx,8(%ecx)
+	movl	%ebp,12(%ecx)
+	popl	%edi
+	popl	%esi
+	popl	%ebx
+	popl	%ebp
+	ret
+.globl	_abi_test_get_and_clear_direction_flag
+.private_extern	_abi_test_get_and_clear_direction_flag
+.align	4
+_abi_test_get_and_clear_direction_flag:
+L_abi_test_get_and_clear_direction_flag_begin:
+	pushfl
+	popl	%eax
+	andl	$1024,%eax
+	shrl	$10,%eax
+	cld
+	ret
+.globl	_abi_test_set_direction_flag
+.private_extern	_abi_test_set_direction_flag
+.align	4
+_abi_test_set_direction_flag:
+L_abi_test_set_direction_flag_begin:
+	std
+	ret
+.globl	_abi_test_clobber_eax
+.private_extern	_abi_test_clobber_eax
+.align	4
+_abi_test_clobber_eax:
+L_abi_test_clobber_eax_begin:
+	xorl	%eax,%eax
+	ret
+.globl	_abi_test_clobber_ebx
+.private_extern	_abi_test_clobber_ebx
+.align	4
+_abi_test_clobber_ebx:
+L_abi_test_clobber_ebx_begin:
+	xorl	%ebx,%ebx
+	ret
+.globl	_abi_test_clobber_ecx
+.private_extern	_abi_test_clobber_ecx
+.align	4
+_abi_test_clobber_ecx:
+L_abi_test_clobber_ecx_begin:
+	xorl	%ecx,%ecx
+	ret
+.globl	_abi_test_clobber_edx
+.private_extern	_abi_test_clobber_edx
+.align	4
+_abi_test_clobber_edx:
+L_abi_test_clobber_edx_begin:
+	xorl	%edx,%edx
+	ret
+.globl	_abi_test_clobber_edi
+.private_extern	_abi_test_clobber_edi
+.align	4
+_abi_test_clobber_edi:
+L_abi_test_clobber_edi_begin:
+	xorl	%edi,%edi
+	ret
+.globl	_abi_test_clobber_esi
+.private_extern	_abi_test_clobber_esi
+.align	4
+_abi_test_clobber_esi:
+L_abi_test_clobber_esi_begin:
+	xorl	%esi,%esi
+	ret
+.globl	_abi_test_clobber_ebp
+.private_extern	_abi_test_clobber_ebp
+.align	4
+_abi_test_clobber_ebp:
+L_abi_test_clobber_ebp_begin:
+	xorl	%ebp,%ebp
+	ret
+.globl	_abi_test_clobber_xmm0
+.private_extern	_abi_test_clobber_xmm0
+.align	4
+_abi_test_clobber_xmm0:
+L_abi_test_clobber_xmm0_begin:
+	pxor	%xmm0,%xmm0
+	ret
+.globl	_abi_test_clobber_xmm1
+.private_extern	_abi_test_clobber_xmm1
+.align	4
+_abi_test_clobber_xmm1:
+L_abi_test_clobber_xmm1_begin:
+	pxor	%xmm1,%xmm1
+	ret
+.globl	_abi_test_clobber_xmm2
+.private_extern	_abi_test_clobber_xmm2
+.align	4
+_abi_test_clobber_xmm2:
+L_abi_test_clobber_xmm2_begin:
+	pxor	%xmm2,%xmm2
+	ret
+.globl	_abi_test_clobber_xmm3
+.private_extern	_abi_test_clobber_xmm3
+.align	4
+_abi_test_clobber_xmm3:
+L_abi_test_clobber_xmm3_begin:
+	pxor	%xmm3,%xmm3
+	ret
+.globl	_abi_test_clobber_xmm4
+.private_extern	_abi_test_clobber_xmm4
+.align	4
+_abi_test_clobber_xmm4:
+L_abi_test_clobber_xmm4_begin:
+	pxor	%xmm4,%xmm4
+	ret
+.globl	_abi_test_clobber_xmm5
+.private_extern	_abi_test_clobber_xmm5
+.align	4
+_abi_test_clobber_xmm5:
+L_abi_test_clobber_xmm5_begin:
+	pxor	%xmm5,%xmm5
+	ret
+.globl	_abi_test_clobber_xmm6
+.private_extern	_abi_test_clobber_xmm6
+.align	4
+_abi_test_clobber_xmm6:
+L_abi_test_clobber_xmm6_begin:
+	pxor	%xmm6,%xmm6
+	ret
+.globl	_abi_test_clobber_xmm7
+.private_extern	_abi_test_clobber_xmm7
+.align	4
+_abi_test_clobber_xmm7:
+L_abi_test_clobber_xmm7_begin:
+	pxor	%xmm7,%xmm7
+	ret
+#endif
diff --git a/third_party/boringssl/mac-x86_64/crypto/fipsmodule/rsaz-avx2.S b/third_party/boringssl/mac-x86_64/crypto/fipsmodule/rsaz-avx2.S
index 9a3051d..b703ae91 100644
--- a/third_party/boringssl/mac-x86_64/crypto/fipsmodule/rsaz-avx2.S
+++ b/third_party/boringssl/mac-x86_64/crypto/fipsmodule/rsaz-avx2.S
@@ -1228,6 +1228,7 @@
 
 .p2align	5
 _rsaz_1024_red2norm_avx2:
+
 	subq	$-128,%rsi
 	xorq	%rax,%rax
 	movq	-128(%rsi),%r8
@@ -1421,11 +1422,13 @@
 	.byte	0xf3,0xc3
 
 
+
 .globl	_rsaz_1024_norm2red_avx2
 .private_extern _rsaz_1024_norm2red_avx2
 
 .p2align	5
 _rsaz_1024_norm2red_avx2:
+
 	subq	$-128,%rdi
 	movq	(%rsi),%r8
 	movl	$0x1fffffff,%eax
@@ -1579,11 +1582,13 @@
 	movq	%r8,184(%rdi)
 	.byte	0xf3,0xc3
 
+
 .globl	_rsaz_1024_scatter5_avx2
 .private_extern _rsaz_1024_scatter5_avx2
 
 .p2align	5
 _rsaz_1024_scatter5_avx2:
+
 	vzeroupper
 	vmovdqu	L$scatter_permd(%rip),%ymm5
 	shll	$4,%edx
@@ -1605,6 +1610,7 @@
 	.byte	0xf3,0xc3
 
 
+
 .globl	_rsaz_1024_gather5_avx2
 .private_extern _rsaz_1024_gather5_avx2
 
@@ -1727,24 +1733,6 @@
 
 L$SEH_end_rsaz_1024_gather5:
 
-
-.globl	_rsaz_avx2_eligible
-.private_extern _rsaz_avx2_eligible
-
-.p2align	5
-_rsaz_avx2_eligible:
-	leaq	_OPENSSL_ia32cap_P(%rip),%rax
-	movl	8(%rax),%eax
-	movl	$524544,%ecx
-	movl	$0,%edx
-	andl	%eax,%ecx
-	cmpl	$524544,%ecx
-	cmovel	%edx,%eax
-	andl	$32,%eax
-	shrl	$5,%eax
-	.byte	0xf3,0xc3
-
-
 .p2align	6
 L$and_mask:
 .quad	0x1fffffff,0x1fffffff,0x1fffffff,0x1fffffff
diff --git a/third_party/boringssl/mac-x86_64/crypto/test/trampoline-x86_64.S b/third_party/boringssl/mac-x86_64/crypto/test/trampoline-x86_64.S
index 0245eab..707460f 100644
--- a/third_party/boringssl/mac-x86_64/crypto/test/trampoline-x86_64.S
+++ b/third_party/boringssl/mac-x86_64/crypto/test/trampoline-x86_64.S
@@ -485,7 +485,7 @@
 	pushfq
 	popq	%rax
 	andq	$0x400,%rax
-	shlq	$10,%rax
+	shrq	$10,%rax
 	cld
 	.byte	0xf3,0xc3
 
diff --git a/third_party/boringssl/win-x86/crypto/test/trampoline-x86.asm b/third_party/boringssl/win-x86/crypto/test/trampoline-x86.asm
new file mode 100644
index 0000000..e5c7d3f
--- /dev/null
+++ b/third_party/boringssl/win-x86/crypto/test/trampoline-x86.asm
@@ -0,0 +1,164 @@
+; This file is generated from a similarly-named Perl script in the BoringSSL
+; source tree. Do not edit by hand.
+
+%ifdef BORINGSSL_PREFIX
+%include "boringssl_prefix_symbols_nasm.inc"
+%endif
+%ifidn __OUTPUT_FORMAT__,obj
+section	code	use32 class=code align=64
+%elifidn __OUTPUT_FORMAT__,win32
+%ifdef __YASM_VERSION_ID__
+%if __YASM_VERSION_ID__ < 01010000h
+%error yasm version 1.1.0 or later needed.
+%endif
+; Yasm automatically includes .00 and complains about redefining it.
+; https://www.tortall.net/projects/yasm/manual/html/objfmt-win32-safeseh.html
+%else
+$@feat.00 equ 1
+%endif
+section	.text	code align=64
+%else
+section	.text	code
+%endif
+global	_abi_test_trampoline
+align	16
+_abi_test_trampoline:
+L$_abi_test_trampoline_begin:
+	push	ebp
+	push	ebx
+	push	esi
+	push	edi
+	mov	ecx,DWORD [24+esp]
+	mov	esi,DWORD [ecx]
+	mov	edi,DWORD [4+ecx]
+	mov	ebx,DWORD [8+ecx]
+	mov	ebp,DWORD [12+ecx]
+	sub	esp,44
+	mov	eax,DWORD [72+esp]
+	xor	ecx,ecx
+L$000loop:
+	cmp	ecx,DWORD [76+esp]
+	jae	NEAR L$001loop_done
+	mov	edx,DWORD [ecx*4+eax]
+	mov	DWORD [ecx*4+esp],edx
+	add	ecx,1
+	jmp	NEAR L$000loop
+L$001loop_done:
+	call	DWORD [64+esp]
+	add	esp,44
+	mov	ecx,DWORD [24+esp]
+	mov	DWORD [ecx],esi
+	mov	DWORD [4+ecx],edi
+	mov	DWORD [8+ecx],ebx
+	mov	DWORD [12+ecx],ebp
+	pop	edi
+	pop	esi
+	pop	ebx
+	pop	ebp
+	ret
+global	_abi_test_get_and_clear_direction_flag
+align	16
+_abi_test_get_and_clear_direction_flag:
+L$_abi_test_get_and_clear_direction_flag_begin:
+	pushfd
+	pop	eax
+	and	eax,1024
+	shr	eax,10
+	cld
+	ret
+global	_abi_test_set_direction_flag
+align	16
+_abi_test_set_direction_flag:
+L$_abi_test_set_direction_flag_begin:
+	std
+	ret
+global	_abi_test_clobber_eax
+align	16
+_abi_test_clobber_eax:
+L$_abi_test_clobber_eax_begin:
+	xor	eax,eax
+	ret
+global	_abi_test_clobber_ebx
+align	16
+_abi_test_clobber_ebx:
+L$_abi_test_clobber_ebx_begin:
+	xor	ebx,ebx
+	ret
+global	_abi_test_clobber_ecx
+align	16
+_abi_test_clobber_ecx:
+L$_abi_test_clobber_ecx_begin:
+	xor	ecx,ecx
+	ret
+global	_abi_test_clobber_edx
+align	16
+_abi_test_clobber_edx:
+L$_abi_test_clobber_edx_begin:
+	xor	edx,edx
+	ret
+global	_abi_test_clobber_edi
+align	16
+_abi_test_clobber_edi:
+L$_abi_test_clobber_edi_begin:
+	xor	edi,edi
+	ret
+global	_abi_test_clobber_esi
+align	16
+_abi_test_clobber_esi:
+L$_abi_test_clobber_esi_begin:
+	xor	esi,esi
+	ret
+global	_abi_test_clobber_ebp
+align	16
+_abi_test_clobber_ebp:
+L$_abi_test_clobber_ebp_begin:
+	xor	ebp,ebp
+	ret
+global	_abi_test_clobber_xmm0
+align	16
+_abi_test_clobber_xmm0:
+L$_abi_test_clobber_xmm0_begin:
+	pxor	xmm0,xmm0
+	ret
+global	_abi_test_clobber_xmm1
+align	16
+_abi_test_clobber_xmm1:
+L$_abi_test_clobber_xmm1_begin:
+	pxor	xmm1,xmm1
+	ret
+global	_abi_test_clobber_xmm2
+align	16
+_abi_test_clobber_xmm2:
+L$_abi_test_clobber_xmm2_begin:
+	pxor	xmm2,xmm2
+	ret
+global	_abi_test_clobber_xmm3
+align	16
+_abi_test_clobber_xmm3:
+L$_abi_test_clobber_xmm3_begin:
+	pxor	xmm3,xmm3
+	ret
+global	_abi_test_clobber_xmm4
+align	16
+_abi_test_clobber_xmm4:
+L$_abi_test_clobber_xmm4_begin:
+	pxor	xmm4,xmm4
+	ret
+global	_abi_test_clobber_xmm5
+align	16
+_abi_test_clobber_xmm5:
+L$_abi_test_clobber_xmm5_begin:
+	pxor	xmm5,xmm5
+	ret
+global	_abi_test_clobber_xmm6
+align	16
+_abi_test_clobber_xmm6:
+L$_abi_test_clobber_xmm6_begin:
+	pxor	xmm6,xmm6
+	ret
+global	_abi_test_clobber_xmm7
+align	16
+_abi_test_clobber_xmm7:
+L$_abi_test_clobber_xmm7_begin:
+	pxor	xmm7,xmm7
+	ret
diff --git a/third_party/boringssl/win-x86_64/crypto/fipsmodule/rsaz-avx2.asm b/third_party/boringssl/win-x86_64/crypto/fipsmodule/rsaz-avx2.asm
index 5165c58..74e2705 100644
--- a/third_party/boringssl/win-x86_64/crypto/fipsmodule/rsaz-avx2.asm
+++ b/third_party/boringssl/win-x86_64/crypto/fipsmodule/rsaz-avx2.asm
@@ -1297,6 +1297,7 @@
 
 ALIGN	32
 rsaz_1024_red2norm_avx2:
+
 	sub	rdx,-128
 	xor	rax,rax
 	mov	r8,QWORD[((-128))+rdx]
@@ -1490,10 +1491,12 @@
 	DB	0F3h,0C3h		;repret
 
 
+
 global	rsaz_1024_norm2red_avx2
 
 ALIGN	32
 rsaz_1024_norm2red_avx2:
+
 	sub	rcx,-128
 	mov	r8,QWORD[rdx]
 	mov	eax,0x1fffffff
@@ -1647,10 +1650,12 @@
 	mov	QWORD[184+rcx],r8
 	DB	0F3h,0C3h		;repret
 
+
 global	rsaz_1024_scatter5_avx2
 
 ALIGN	32
 rsaz_1024_scatter5_avx2:
+
 	vzeroupper
 	vmovdqu	ymm5,YMMWORD[$L$scatter_permd]
 	shl	r8d,4
@@ -1672,6 +1677,7 @@
 	DB	0F3h,0C3h		;repret
 
 
+
 global	rsaz_1024_gather5_avx2
 
 ALIGN	32
@@ -1817,23 +1823,6 @@
 
 $L$SEH_end_rsaz_1024_gather5:
 
-EXTERN	OPENSSL_ia32cap_P
-global	rsaz_avx2_eligible
-
-ALIGN	32
-rsaz_avx2_eligible:
-	lea	rax,[OPENSSL_ia32cap_P]
-	mov	eax,DWORD[8+rax]
-	mov	ecx,524544
-	mov	edx,0
-	and	ecx,eax
-	cmp	ecx,524544
-	cmove	eax,edx
-	and	eax,32
-	shr	eax,5
-	DB	0F3h,0C3h		;repret
-
-
 ALIGN	64
 $L$and_mask:
 	DQ	0x1fffffff,0x1fffffff,0x1fffffff,0x1fffffff
diff --git a/third_party/boringssl/win-x86_64/crypto/test/trampoline-x86_64.asm b/third_party/boringssl/win-x86_64/crypto/test/trampoline-x86_64.asm
index ba08a25..25b1af13 100644
--- a/third_party/boringssl/win-x86_64/crypto/test/trampoline-x86_64.asm
+++ b/third_party/boringssl/win-x86_64/crypto/test/trampoline-x86_64.asm
@@ -521,7 +521,7 @@
 	pushfq
 	pop	rax
 	and	rax,0x400
-	shl	rax,10
+	shr	rax,10
 	cld
 	DB	0F3h,0C3h		;repret
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 03dbfb3b..b60abaa 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -10962,6 +10962,7 @@
   <int value="6" label="Star"/>
   <int value="7" label="New Tab"/>
   <int value="8" label="Credit Card Autofill"/>
+  <int value="9" label="Text Suggestion"/>
 </enum>
 
 <enum name="DefaultWebClientState">
@@ -21496,6 +21497,7 @@
   <int value="2773" label="PerMethodCanMakePaymentQuota"/>
   <int value="2774" label="CSSValueAppearanceButtonForNonButtonRendered"/>
   <int value="2775" label="CSSValueAppearanceButtonForOthersRendered"/>
+  <int value="2776" label="CustomCursorIntersectsViewport"/>
 </enum>
 
 <enum name="FeaturePolicyFeature">
@@ -21542,6 +21544,7 @@
   <int value="38" label="Modals"/>
   <int value="39" label="OrientationLock"/>
   <int value="40" label="Presentation"/>
+  <int value="41" label="Frobulate"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -31386,6 +31389,8 @@
   <int value="-741806604" label="DownloadsUi:disabled"/>
   <int value="-738957187" label="OmniboxUIExperimentSwapTitleAndUrl:disabled"/>
   <int value="-735084806" label="NewTabLoadingAnimation:enabled"/>
+  <int value="-734301625"
+      label="AutofillImportNonFocusableCreditCardForms:disabled"/>
   <int value="-731133967" label="AutofillSettingsCardTypeSplit:disabled"/>
   <int value="-727860269" label="WebAuthenticationBle:disabled"/>
   <int value="-726892130" label="AndroidMessagesIntegration:disabled"/>
@@ -31948,6 +31953,8 @@
   <int value="304901781" label="NewUsbBackend:enabled"/>
   <int value="306641800" label="AndroidSiteSettingsUIRefresh:disabled"/>
   <int value="307543404" label="disable-team-drives"/>
+  <int value="310143091"
+      label="AutofillImportNonFocusableCreditCardForms:enabled"/>
   <int value="313253630" label="AutofillRefreshStyleAndroid:enabled"/>
   <int value="313303258" label="WebPaymentsModifiers:disabled"/>
   <int value="316182183" label="MediaDocumentDownloadButton:disabled"/>
diff --git a/ui/OWNERS b/ui/OWNERS
index 4f49426..96fc547 100644
--- a/ui/OWNERS
+++ b/ui/OWNERS
@@ -11,3 +11,7 @@
 
 # Translation artifacts:
 per-file *.xtb=file://tools/translation/TRANSLATION_OWNERS
+
+# For Fuchsia-specific changes:
+per-file *fuchsia*=file://build/fuchsia/OWNERS
+per-file *scenic*=file://build/fuchsia/OWNERS
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index d385261..37e49d7 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -193,6 +193,7 @@
     "//ui/base",
     "//ui/base/clipboard",
     "//ui/base/ime",
+    "//ui/base/user_activity",
     "//ui/display",
     "//ui/events",
     "//ui/events:dom_keyboard_layout",
@@ -429,6 +430,7 @@
     "//ui/aura_extra:tests",
     "//ui/base:test_support",
     "//ui/base/clipboard:clipboard_types",
+    "//ui/base/user_activity",
     "//ui/compositor:test_support",
     "//ui/compositor_extra",
     "//ui/display:test_support",
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index f913d76..cc59e98 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -249,9 +249,6 @@
     "ui_base_switches_util.h",
     "ui_base_types.cc",
     "ui_base_types.h",
-    "user_activity/user_activity_detector.cc",
-    "user_activity/user_activity_detector.h",
-    "user_activity/user_activity_observer.h",
     "view_prop.cc",
     "view_prop.h",
     "webui/i18n_source_stream.cc",
@@ -870,9 +867,7 @@
       sources += [ "ime/composition_text_util_pango_unittest.cc" ]
     }
     if (is_chromeos || use_ozone) {
-      sources += [
-        "ime/character_composer_unittest.cc",
-      ]
+      sources += [ "ime/character_composer_unittest.cc" ]
     }
   }
 
@@ -893,6 +888,7 @@
     "//ui/base:ui_data_pack",
     "//ui/base/clipboard:clipboard_test",
     "//ui/base/clipboard:clipboard_types",
+    "//ui/base/user_activity",
     "//ui/display",
     "//ui/events:events_base",
     "//ui/events:test_support",
diff --git a/ui/base/idle/BUILD.gn b/ui/base/idle/BUILD.gn
index bfa6e5d..5311a54a 100644
--- a/ui/base/idle/BUILD.gn
+++ b/ui/base/idle/BUILD.gn
@@ -52,6 +52,7 @@
     deps += [
       "//chromeos",
       "//chromeos/dbus",
+      "//ui/base/user_activity",
     ]
     sources -= [ "idle_linux.cc" ]
   }
diff --git a/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc b/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc
index 3793822..a2abea8 100644
--- a/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc
+++ b/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc
@@ -20,13 +20,8 @@
               ->ConnectToService<fuchsia::ui::input::ImeVisibilityService>()) {
   DCHECK(ime_service_);
 
-  ime_visibility_.set_error_handler([this](zx_status_t status) {
-    ZX_LOG(WARNING, status) << "ImeVisibilityService connection lost.";
-
-    // We can't observe visibility events anymore, so dismiss the keyboard and
-    // assume that it's closed for good.
-    DismissVirtualKeyboard();
-    keyboard_visible_ = false;
+  ime_visibility_.set_error_handler([](zx_status_t status) {
+    ZX_LOG(FATAL, status) << " ImeVisibilityService lost.";
   });
 
   ime_visibility_.events().OnKeyboardVisibilityChanged = [this](bool visible) {
diff --git a/ui/base/user_activity/BUILD.gn b/ui/base/user_activity/BUILD.gn
new file mode 100644
index 0000000..b4a768b
--- /dev/null
+++ b/ui/base/user_activity/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/jumbo.gni")
+import("//build/config/ui.gni")
+import("//testing/test.gni")
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+} else if (is_mac) {
+  import("//build/config/mac/rules.gni")
+}
+
+jumbo_source_set("user_activity") {
+  sources = [
+    "user_activity_detector.cc",
+    "user_activity_detector.h",
+    "user_activity_observer.h",
+  ]
+
+  deps = [
+    "//ui/events:events",
+  ]
+}
diff --git a/ui/base/user_activity/user_activity_detector.h b/ui/base/user_activity/user_activity_detector.h
index 0f2a9a9e..a3689168 100644
--- a/ui/base/user_activity/user_activity_detector.h
+++ b/ui/base/user_activity/user_activity_detector.h
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
-#include "ui/base/ui_base_export.h"
 #include "ui/events/event.h"
 #include "ui/events/platform/platform_event_observer.h"
 
@@ -18,7 +17,7 @@
 class UserActivityObserver;
 
 // Watches for input events and notifies observers that the user is active.
-class UI_BASE_EXPORT UserActivityDetector : public PlatformEventObserver {
+class UserActivityDetector : public PlatformEventObserver {
  public:
   // Minimum amount of time between notifications to observers.
   static const int kNotifyIntervalMs;
diff --git a/ui/base/user_activity/user_activity_observer.h b/ui/base/user_activity/user_activity_observer.h
index f6b98d21..18e30dd 100644
--- a/ui/base/user_activity/user_activity_observer.h
+++ b/ui/base/user_activity/user_activity_observer.h
@@ -6,7 +6,6 @@
 #define UI_BASE_USER_ACTIVITY_USER_ACTIVITY_OBSERVER_H_
 
 #include "base/macros.h"
-#include "ui/base/ui_base_export.h"
 
 namespace ui {
 class Event;
@@ -16,7 +15,7 @@
 
 // Interface for classes that want to be notified about user activity.
 // Implementations should register themselves with UserActivityDetector.
-class UI_BASE_EXPORT UserActivityObserver {
+class UserActivityObserver {
  public:
   // Invoked periodically while the user is active (i.e. generating input
   // events). |event| is the event that triggered the notification; it may
diff --git a/ui/chromeos/BUILD.gn b/ui/chromeos/BUILD.gn
index d1075fc..d3c1128 100644
--- a/ui/chromeos/BUILD.gn
+++ b/ui/chromeos/BUILD.gn
@@ -43,6 +43,7 @@
     "//ui/aura",
     "//ui/base",
     "//ui/base/ime",
+    "//ui/base/user_activity",
     "//ui/chromeos/resources",
     "//ui/chromeos/strings",
     "//ui/display",
diff --git a/ui/display/manager/BUILD.gn b/ui/display/manager/BUILD.gn
index fda805f..201de69 100644
--- a/ui/display/manager/BUILD.gn
+++ b/ui/display/manager/BUILD.gn
@@ -62,6 +62,7 @@
     "//base",
     "//third_party/re2",
     "//ui/base",
+    "//ui/base/user_activity",
     "//ui/display/mojo:interfaces",
     "//ui/display/util",
     "//ui/events:platform_event",
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
index d8185a02..4507e9d 100644
--- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
+++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
@@ -837,12 +837,14 @@
     }
   }
 
+#if defined(OS_CHROMEOS)
   // Update num lock mask.
   num_lock_mod_mask_ = 0;
   xkb_mod_index_t num_mod_index =
       xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM);
   if (num_mod_index != XKB_MOD_INVALID)
     num_lock_mod_mask_ = static_cast<xkb_mod_mask_t>(1) << num_mod_index;
+#endif
 }
 
 xkb_mod_mask_t XkbKeyboardLayoutEngine::EventFlagsToXkbFlags(
@@ -852,8 +854,10 @@
     if (ui_flags & entry.ui_flag)
       xkb_flags |= entry.xkb_flag;
   }
-  // NumLock is always on.
+#if defined(OS_CHROMEOS)
+  // In ChromeOS NumLock is always on.
   xkb_flags |= num_lock_mod_mask_;
+#endif
   return xkb_flags;
 }
 
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
index 50f0912..df8a45f 100644
--- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
+++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h
@@ -57,8 +57,10 @@
   };
   std::vector<XkbFlagMapEntry> xkb_flag_map_;
 
-  // Flag mask for num lock, which is always considered enabled.
+#if defined(OS_CHROMEOS)
+  // Flag mask for num lock, which is always considered enabled in ChromeOS.
   xkb_mod_mask_t num_lock_mod_mask_ = 0;
+#endif
 
   // Determines the Windows-based KeyboardCode (VKEY) for a character key,
   // accounting for non-US layouts. May return VKEY_UNKNOWN, in which case the
diff --git a/ui/gfx/platform_font_skia.cc b/ui/gfx/platform_font_skia.cc
index b8910fe..a7118f0 100644
--- a/ui/gfx/platform_font_skia.cc
+++ b/ui/gfx/platform_font_skia.cc
@@ -14,6 +14,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "third_party/skia/include/core/SkFont.h"
+#include "third_party/skia/include/core/SkFontMetrics.h"
 #include "third_party/skia/include/core/SkFontStyle.h"
 #include "third_party/skia/include/core/SkString.h"
 #include "ui/gfx/canvas.h"
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc
index 2035ad0..af8acbff 100644
--- a/ui/gl/gl_context.cc
+++ b/ui/gl/gl_context.cc
@@ -63,6 +63,7 @@
   share_group_->RemoveContext(this);
   if (GetCurrent() == this) {
     SetCurrent(nullptr);
+    SetCurrentGL(nullptr);
   }
   base::subtle::Atomic32 after_value =
       base::subtle::NoBarrier_AtomicIncrement(&total_gl_contexts_, -1);
@@ -191,22 +192,6 @@
   current_virtual_context_ = nullptr;
 }
 
-void GLContext::AddVirtualOwner(GLContext* owner) {
-  DCHECK(virtual_owners_.find(owner) == virtual_owners_.end());
-  virtual_owners_.insert(owner);
-}
-
-void GLContext::RemoveVirtualOwner(GLContext* owner) {
-  auto found = virtual_owners_.find(owner);
-  DCHECK(found != virtual_owners_.end());
-  virtual_owners_.erase(found);
-
-  // Also remove the owner from |current_virtual_context_|, to avoid leaving a
-  // bad pointer.
-  if (current_virtual_context_ == owner)
-    current_virtual_context_ = nullptr;
-}
-
 #if defined(OS_MACOSX)
 uint64_t GLContext::BackpressureFenceCreate() {
   return 0;
@@ -263,11 +248,6 @@
   return current_real_context_.Pointer()->Get();
 }
 
-bool GLContext::IsLastVirtualOwner(GLContext* context) {
-  DCHECK(virtual_owners_.find(context) != virtual_owners_.end());
-  return virtual_owners_.size() == 1;
-}
-
 std::unique_ptr<gl::GLVersionInfo> GLContext::GenerateGLVersionInfo() {
   return std::make_unique<GLVersionInfo>(
       GetGLVersion().c_str(), GetGLRenderer().c_str(), GetExtensions());
@@ -328,7 +308,6 @@
 
 bool GLContext::MakeVirtuallyCurrent(
     GLContext* virtual_context, GLSurface* surface) {
-  DCHECK(virtual_owners_.find(virtual_context) != virtual_owners_.end());
   if (!ForceGpuSwitchIfNeeded())
     return false;
   bool switched_real_contexts = GLContext::GetRealCurrent() != this;
@@ -386,15 +365,8 @@
 }
 
 void GLContext::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
-  DCHECK(virtual_owners_.find(virtual_context) != virtual_owners_.end());
   if (current_virtual_context_ == virtual_context)
     current_virtual_context_ = nullptr;
-
-  if (GetCurrent() == virtual_context) {
-    // The virtual context is being released, and should no longer be current.
-    // Transfer ownership to the real context (this).
-    current_context_.Pointer()->Set(this);
-  }
 }
 
 void GLContext::BindGLApi() {
diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h
index 6c046bd5..e166824 100644
--- a/ui/gl/gl_context.h
+++ b/ui/gl/gl_context.h
@@ -199,11 +199,6 @@
   // context is made current.
   void DirtyVirtualContextState();
 
-  // Notifies this class of a new virtual GLContext owner.
-  void AddVirtualOwner(GLContext* owner);
-  // Removes a virtual GLContext owner.
-  void RemoveVirtualOwner(GLContext* owner);
-
 #if defined(OS_MACOSX)
   // Create a fence for all work submitted to this context so far, and return a
   // monotonically increasing handle to it. This returned handle never needs to
@@ -252,10 +247,6 @@
 
   GLApi* gl_api() { return gl_api_.get(); }
 
-  // Returns true if the provided |context| is the only remaining virtual owner
-  // of this context.
-  bool IsLastVirtualOwner(GLContext* context);
-
  private:
   friend class base::RefCounted<GLContext>;
 
@@ -290,8 +281,6 @@
   std::unique_ptr<GLStateRestorer> state_restorer_;
   std::unique_ptr<GLVersionInfo> version_info_;
 
-  base::flat_set<GLContext*> virtual_owners_;
-
   DISALLOW_COPY_AND_ASSIGN(GLContext);
 };
 
diff --git a/ui/gl/gl_context_stub.cc b/ui/gl/gl_context_stub.cc
index 22981c3e..d4646ca 100644
--- a/ui/gl/gl_context_stub.cc
+++ b/ui/gl/gl_context_stub.cc
@@ -30,9 +30,6 @@
 }
 
 void GLContextStub::ReleaseCurrent(GLSurface* surface) {
-  if (!IsCurrent(surface))
-    return;
-
   SetCurrent(nullptr);
 }
 
diff --git a/ui/ozone/platform/scenic/OWNERS b/ui/ozone/platform/scenic/OWNERS
deleted file mode 100644
index e7034ea..0000000
--- a/ui/ozone/platform/scenic/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://build/fuchsia/OWNERS
diff --git a/ui/ozone/platform/scenic/scenic_window_manager.cc b/ui/ozone/platform/scenic/scenic_window_manager.cc
index cbb3ba4..82b0e01f 100644
--- a/ui/ozone/platform/scenic/scenic_window_manager.cc
+++ b/ui/ozone/platform/scenic/scenic_window_manager.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/scenic/scenic_window_manager.h"
 
 #include "base/fuchsia/component_context.h"
+#include "base/fuchsia/fuchsia_logging.h"
 #include "ui/ozone/platform/scenic/ozone_platform_scenic.h"
 
 namespace ui {
@@ -24,9 +25,7 @@
     view_manager_ = base::fuchsia::ComponentContext::GetDefault()
                         ->ConnectToService<fuchsia::ui::viewsv1::ViewManager>();
     view_manager_.set_error_handler([](zx_status_t status) {
-      LOG(ERROR)
-          << "The ViewManager channel was unexpectedly terminated with status "
-          << status << ".";
+      ZX_LOG(FATAL, status) << " ViewManager lost.";
     });
   }
 
@@ -37,9 +36,8 @@
   if (!scenic_) {
     scenic_ = base::fuchsia::ComponentContext::GetDefault()
                   ->ConnectToService<fuchsia::ui::scenic::Scenic>();
-    scenic_.set_error_handler([](zx_status_t status) {
-      LOG(ERROR) << "The Scenic channel was unexpectedly terminated.";
-    });
+    scenic_.set_error_handler(
+        [](zx_status_t status) { ZX_LOG(FATAL, status) << " Scenic lost."; });
   }
   return scenic_.get();
 }
diff --git a/ui/platform_window/fuchsia/OWNERS b/ui/platform_window/fuchsia/OWNERS
deleted file mode 100644
index e7034ea..0000000
--- a/ui/platform_window/fuchsia/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://build/fuchsia/OWNERS
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 5d3a78a..feb6113 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -416,8 +416,7 @@
                          const gfx::Rect& bounds,
                          MenuAnchorPosition position,
                          bool context_menu,
-                         bool is_nested_drag,
-                         base::flat_set<int> alerted_commands) {
+                         bool is_nested_drag) {
   exit_type_ = EXIT_NONE;
   possible_drag_ = false;
   drag_in_progress_ = false;
@@ -456,7 +455,6 @@
     DCHECK_EQ(owner_, parent);
   } else {
     showing_ = true;
-    alerted_commands_ = alerted_commands;
 
     if (owner_)
       owner_->RemoveObserver(this);
@@ -1944,17 +1942,6 @@
   bool do_capture = (!did_capture_ && !for_drop_);
   showing_submenu_ = true;
   if (show) {
-    // Menus are the only place using kGroupingPropertyKey, so any value (other
-    // than 0) is fine.
-    const int kGroupingId = 1001;
-
-    // Show alerts on the requested MenuItemViews.
-    for (int i = 0; i < item->GetSubmenu()->GetMenuItemCount(); ++i) {
-      MenuItemView* subitem = item->GetSubmenu()->GetMenuItemAt(i);
-      if (alerted_commands_.contains(subitem->GetCommand()))
-        subitem->SetAlerted(true);
-    }
-
     item->GetSubmenu()->ShowAt(owner_, bounds, do_capture);
 
     // Figure out if the mouse is under the menu; if so, remember the mouse
@@ -1971,6 +1958,9 @@
         menu_open_mouse_loc_ = mouse_pos;
     }
 
+    // Menus are the only place using kGroupingPropertyKey, so any value (other
+    // than 0) is fine.
+    constexpr int kGroupingId = 1001;
     item->GetSubmenu()->GetWidget()->SetNativeWindowProperty(
         TooltipManager::kGroupingPropertyKey,
         reinterpret_cast<void*>(kGroupingId));
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h
index 5407ce2d..525b9c67 100644
--- a/ui/views/controls/menu/menu_controller.h
+++ b/ui/views/controls/menu/menu_controller.h
@@ -85,16 +85,14 @@
   // If a menu is currently active, this returns the controller for it.
   static MenuController* GetActiveInstance();
 
-  // Runs the menu at the specified location. Menu items with commands in
-  // |alerted_commands| will be rendered differently to draw attention to them.
+  // Runs the menu at the specified location.
   void Run(Widget* parent,
            MenuButton* button,
            MenuItemView* root,
            const gfx::Rect& bounds,
            MenuAnchorPosition position,
            bool context_menu,
-           bool is_nested_drag,
-           base::flat_set<int> alerted_commands = base::flat_set<int>());
+           bool is_nested_drag);
 
   bool for_drop() const { return for_drop_; }
 
@@ -741,9 +739,6 @@
 
   std::unique_ptr<MenuPreTargetHandler> menu_pre_target_handler_;
 
-  // Set of menu commands that should be displayed with an alert.
-  base::flat_set<int> alerted_commands_;
-
   DISALLOW_COPY_AND_ASSIGN(MenuController);
 };
 
diff --git a/ui/views/controls/menu/menu_item_view.h b/ui/views/controls/menu/menu_item_view.h
index 98214a30..576b70e 100644
--- a/ui/views/controls/menu/menu_item_view.h
+++ b/ui/views/controls/menu/menu_item_view.h
@@ -367,10 +367,9 @@
   // border radius, if they are both the same value.
   void SetCornerRadius(int radius);
 
-  // Show an alert on this menu item. An alerted menu item is rendered
+  // Shows an alert on this menu item. An alerted menu item is rendered
   // differently to draw attention to it.
   void SetAlerted(bool alerted);
-  bool Alerted() const { return alerted_; }
 
  protected:
   // Creates a MenuItemView. This is used by the various AddXXX methods.
diff --git a/ui/views/controls/menu/menu_runner.cc b/ui/views/controls/menu/menu_runner.cc
index 1c4ffea5..bd16bfc 100644
--- a/ui/views/controls/menu/menu_runner.cc
+++ b/ui/views/controls/menu/menu_runner.cc
@@ -32,8 +32,7 @@
                            MenuButton* button,
                            const gfx::Rect& bounds,
                            MenuAnchorPosition anchor,
-                           ui::MenuSourceType source_type,
-                           base::flat_set<int> alerted_commands) {
+                           ui::MenuSourceType source_type) {
   // If we are shown on mouse press, we will eat the subsequent mouse down and
   // the parent widget will not be able to reset its state (it might have mouse
   // capture from the mouse down). So we clear its state here.
@@ -70,8 +69,7 @@
     }
   }
 
-  impl_->RunMenuAt(parent, button, bounds, anchor, run_types_,
-                   alerted_commands);
+  impl_->RunMenuAt(parent, button, bounds, anchor, run_types_);
 }
 
 bool MenuRunner::IsRunning() const {
diff --git a/ui/views/controls/menu/menu_runner.h b/ui/views/controls/menu/menu_runner.h
index dfa8bcf..b3c5b82 100644
--- a/ui/views/controls/menu/menu_runner.h
+++ b/ui/views/controls/menu/menu_runner.h
@@ -116,15 +116,12 @@
 
   // Runs the menu. MenuDelegate::OnMenuClosed will be notified of the results.
   // If |anchor| uses a |BUBBLE_..| type, the bounds will get determined by
-  // using |bounds| as the thing to point at in screen coordinates. Menu items
-  // with commands in |alerted_commands| will be rendered differently to draw
-  // attention to them.
+  // using |bounds| as the thing to point at in screen coordinates.
   void RunMenuAt(Widget* parent,
                  MenuButton* button,
                  const gfx::Rect& bounds,
                  MenuAnchorPosition anchor,
-                 ui::MenuSourceType source_type,
-                 base::flat_set<int> alerted_commands = base::flat_set<int>());
+                 ui::MenuSourceType source_type);
 
   // Returns true if we're in a nested run loop running the menu.
   bool IsRunning() const;
diff --git a/ui/views/controls/menu/menu_runner_impl.cc b/ui/views/controls/menu/menu_runner_impl.cc
index 6ff3a6a..3f1fb8a 100644
--- a/ui/views/controls/menu/menu_runner_impl.cc
+++ b/ui/views/controls/menu/menu_runner_impl.cc
@@ -81,8 +81,7 @@
                                MenuButton* button,
                                const gfx::Rect& bounds,
                                MenuAnchorPosition anchor,
-                               int32_t run_types,
-                               base::flat_set<int> alerted_commands) {
+                               int32_t run_types) {
   closing_event_time_ = base::TimeTicks();
   if (running_) {
     // Ignore requests to show the menu while it's already showing. MenuItemView
@@ -138,7 +137,7 @@
 
   controller->Run(parent, button, menu_, bounds, anchor,
                   (run_types & MenuRunner::CONTEXT_MENU) != 0,
-                  (run_types & MenuRunner::NESTED_DRAG) != 0, alerted_commands);
+                  (run_types & MenuRunner::NESTED_DRAG) != 0);
 }
 
 void MenuRunnerImpl::Cancel() {
diff --git a/ui/views/controls/menu/menu_runner_impl.h b/ui/views/controls/menu/menu_runner_impl.h
index 9367a2a..a3f97c3 100644
--- a/ui/views/controls/menu/menu_runner_impl.h
+++ b/ui/views/controls/menu/menu_runner_impl.h
@@ -40,13 +40,11 @@
 
   bool IsRunning() const override;
   void Release() override;
-  void RunMenuAt(
-      Widget* parent,
-      MenuButton* button,
-      const gfx::Rect& bounds,
-      MenuAnchorPosition anchor,
-      int32_t run_types,
-      base::flat_set<int> alerted_commands = base::flat_set<int>()) override;
+  void RunMenuAt(Widget* parent,
+                 MenuButton* button,
+                 const gfx::Rect& bounds,
+                 MenuAnchorPosition anchor,
+                 int32_t run_types) override;
   void Cancel() override;
   base::TimeTicks GetClosingEventTime() const override;
 
diff --git a/ui/views/controls/menu/menu_runner_impl_adapter.cc b/ui/views/controls/menu/menu_runner_impl_adapter.cc
index 84121b26..08b8b81 100644
--- a/ui/views/controls/menu/menu_runner_impl_adapter.cc
+++ b/ui/views/controls/menu/menu_runner_impl_adapter.cc
@@ -30,9 +30,8 @@
                                       MenuButton* button,
                                       const gfx::Rect& bounds,
                                       MenuAnchorPosition anchor,
-                                      int32_t types,
-                                      base::flat_set<int> alerted_commands) {
-  impl_->RunMenuAt(parent, button, bounds, anchor, types, alerted_commands);
+                                      int32_t types) {
+  impl_->RunMenuAt(parent, button, bounds, anchor, types);
 }
 
 void MenuRunnerImplAdapter::Cancel() {
diff --git a/ui/views/controls/menu/menu_runner_impl_adapter.h b/ui/views/controls/menu/menu_runner_impl_adapter.h
index dd713eb..e70d7b60 100644
--- a/ui/views/controls/menu/menu_runner_impl_adapter.h
+++ b/ui/views/controls/menu/menu_runner_impl_adapter.h
@@ -32,8 +32,7 @@
                  MenuButton* button,
                  const gfx::Rect& bounds,
                  MenuAnchorPosition anchor,
-                 int32_t types,
-                 base::flat_set<int> alerted_commands) override;
+                 int32_t types) override;
   void Cancel() override;
   base::TimeTicks GetClosingEventTime() const override;
 
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.h b/ui/views/controls/menu/menu_runner_impl_cocoa.h
index 5b2382aa..599000d 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.h
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.h
@@ -29,13 +29,11 @@
 
   bool IsRunning() const override;
   void Release() override;
-  void RunMenuAt(
-      Widget* parent,
-      MenuButton* button,
-      const gfx::Rect& bounds,
-      MenuAnchorPosition anchor,
-      int32_t run_types,
-      base::flat_set<int> alerted_commands = base::flat_set<int>()) override;
+  void RunMenuAt(Widget* parent,
+                 MenuButton* button,
+                 const gfx::Rect& bounds,
+                 MenuAnchorPosition anchor,
+                 int32_t run_types) override;
   void Cancel() override;
   base::TimeTicks GetClosingEventTime() const override;
 
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
index 91585b2da..f67cdcbd 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -167,8 +167,7 @@
                                     MenuButton* button,
                                     const gfx::Rect& bounds,
                                     MenuAnchorPosition anchor,
-                                    int32_t run_types,
-                                    base::flat_set<int> alerted_commands) {
+                                    int32_t run_types) {
   DCHECK(!IsRunning());
   DCHECK(parent);
   closing_event_time_ = base::TimeTicks();
diff --git a/ui/views/controls/menu/menu_runner_impl_interface.h b/ui/views/controls/menu/menu_runner_impl_interface.h
index eaea27e..f6e5bd0 100644
--- a/ui/views/controls/menu/menu_runner_impl_interface.h
+++ b/ui/views/controls/menu/menu_runner_impl_interface.h
@@ -35,13 +35,11 @@
   virtual void Release() = 0;
 
   // Runs the menu. See MenuRunner::RunMenuAt for more details.
-  virtual void RunMenuAt(
-      Widget* parent,
-      MenuButton* button,
-      const gfx::Rect& bounds,
-      MenuAnchorPosition anchor,
-      int32_t run_types,
-      base::flat_set<int> alerted_commands = base::flat_set<int>()) = 0;
+  virtual void RunMenuAt(Widget* parent,
+                         MenuButton* button,
+                         const gfx::Rect& bounds,
+                         MenuAnchorPosition anchor,
+                         int32_t run_types) = 0;
 
   // Hides and cancels the menu.
   virtual void Cancel() = 0;
diff --git a/ui/views/controls/menu/menu_runner_unittest.cc b/ui/views/controls/menu/menu_runner_unittest.cc
index e300385..a5972e65 100644
--- a/ui/views/controls/menu/menu_runner_unittest.cc
+++ b/ui/views/controls/menu/menu_runner_unittest.cc
@@ -317,21 +317,6 @@
   EXPECT_NE(nullptr, delegate->on_menu_closed_menu());
 }
 
-TEST_F(MenuRunnerTest, AlertsShown) {
-  InitMenuRunner(0);
-  MenuRunner* runner = menu_runner();
-
-  base::flat_set<int> alerted_commands{2};
-  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                    ui::MENU_SOURCE_NONE, alerted_commands);
-  EXPECT_TRUE(runner->IsRunning());
-
-  MenuItemView* normal_item = menu_item_view()->GetMenuItemByID(1);
-  MenuItemView* alerted_item = menu_item_view()->GetMenuItemByID(2);
-  EXPECT_FALSE(normal_item->Alerted());
-  EXPECT_TRUE(alerted_item->Alerted());
-}
-
 namespace {
 
 // An EventHandler that launches a menu in response to a mouse press.
diff --git a/ui/webui/resources/cr_elements/shared_vars_css.html b/ui/webui/resources/cr_elements/shared_vars_css.html
index 0650ade..35aa3be4 100644
--- a/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -187,8 +187,6 @@
       white-space: nowrap;
     }
 
-    --cr-text-element-min-width: 200px;
-
     --cr-title-text: {
         color: var(--cr-title-text-color);
         font-size: 107.6923%;  /* Go to 14px from 13px. */
@@ -205,7 +203,7 @@
       font-size: 92.31%;  /* Effectively 12px if the host default is 13px. */
       font-weight: 500;
       max-width: 330px;
-      min-width: var(--cr-text-element-min-width);
+      min-width: 200px;
       padding: 10px 8px;
     }
 
diff --git a/ui/webui/resources/html/md_select_css.html b/ui/webui/resources/html/md_select_css.html
index c73f901..9c72fee 100644
--- a/ui/webui/resources/html/md_select_css.html
+++ b/ui/webui/resources/html/md_select_css.html
@@ -28,7 +28,6 @@
         font-size: inherit;
         line-height: inherit;
         max-width: 100%;
-        min-width: var(--cr-text-element-min-width);
         outline: none;
         padding-bottom: 6px;
         /* Ensures 3px space between text and arrow */