diff --git a/BUILD.gn b/BUILD.gn
index e18b1a8..f086203 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -219,7 +219,7 @@
       ":d8_fuchsia",
       "//build/fuchsia/fidlgen_js:fidlgen_js_unittests",
       "//fuchsia:gn_all",
-      "//headless",
+      "//headless:headless_non_renderer",
     ]
   }
 
@@ -747,7 +747,7 @@
 
   if (is_linux && use_ozone) {
     deps += [
-      "//headless",
+      "//headless:headless_non_renderer",
       "//headless:headless_tests",
     ]
   }
diff --git a/DEPS b/DEPS
index ef2fe0c..de86aab 100644
--- a/DEPS
+++ b/DEPS
@@ -133,11 +133,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'fd105f1b76a79a416fcfc4cf262cd3b26c2de079',
+  'skia_revision': '09db9d21756e0bcc37114224c433d01a99ec377e',
   # 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': 'e89d5754678ef28970176cc03071f4cf108185b1',
+  'v8_revision': '8482f4517758bf9c5c6e45e0aca44577defb8fa3',
   # 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.
@@ -200,7 +200,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'f27057bbc6ffd945168e51d32915831e253dd36b',
+  'catapult_revision': 'cca9447f62824814d1ae1dd6c6268a66745d9fab',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -276,7 +276,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': '97b690b069ce413a9e8d36aba12d868957ef9151',
+  'quiche_revision': '3f28356e440b0acac3030ad0e686b1d2c8c92542',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -768,7 +768,7 @@
   },
 
   'src/third_party/breakpad/breakpad':
-    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '1fc9cc0d0e1dfafb8d29dba8d01f09587d870026',
+    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '21b48a72aa50dde84149267f6b7402522b846b24',
 
   'src/third_party/byte_buddy': {
       'packages': [
@@ -806,7 +806,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a5d3e861c6847daf114f699a3e2c3584995b741c',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '14fc5d16ccf425fd6082f4e993cbf2e2f0c72be8',
       'condition': 'checkout_linux',
   },
 
@@ -821,7 +821,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'c6682b1f2e0d0f8430a0536ec165201a8e77be15',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'd6ec70dbe6b70c72cd943df8b0729cd993156ef1',
       'condition': 'checkout_linux',
   },
 
@@ -831,7 +831,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9c0620120980e4c247ff8325ee8bbdcd4d9576e0',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5b1f4aaf31d8f26b41db73ba1d3cde638649c92c',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1184,7 +1184,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'a1f3a86f3cc299d59a8ba54540cf000f204dde9e',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'ad7d5341ef84b3f0e2204d56482ef6f1cd5de9d6',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1396,7 +1396,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@900c3d21976c396c85a3cac6c5183f58c58612ed',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@caf7bdf789eb4e1ab8559327ca995aa43b4df9b7',
     'condition': 'checkout_src_internal',
   },
 
@@ -2547,6 +2547,7 @@
                 'src/third_party/depot_tools/download_from_google_storage.py',
                 '--no_resume',
                 '--no_auth',
+                '--num_threads=4',
                 '--bucket', 'chromium-browser-clang/orderfiles',
                 '-d', 'src/chrome/build',
     ],
diff --git a/android_webview/browser/aw_settings.cc b/android_webview/browser/aw_settings.cc
index d3232088..3c47202 100644
--- a/android_webview/browser/aw_settings.cc
+++ b/android_webview/browser/aw_settings.cc
@@ -436,7 +436,6 @@
   // Please see the corresponding Blink settings for bug references.
   web_prefs->support_deprecated_target_density_dpi = support_quirks;
   web_prefs->use_legacy_background_size_shorthand_behavior = support_quirks;
-  web_prefs->viewport_meta_layout_size_quirk = support_quirks;
   web_prefs->viewport_meta_merge_content_quirk = support_quirks;
   web_prefs->viewport_meta_non_user_scalable_quirk = support_quirks;
   web_prefs->viewport_meta_zero_values_quirk = support_quirks;
diff --git a/ash/accessibility/accessibility_controller.cc b/ash/accessibility/accessibility_controller.cc
index b06a8d74..6ac8a42 100644
--- a/ash/accessibility/accessibility_controller.cc
+++ b/ash/accessibility/accessibility_controller.cc
@@ -1026,6 +1026,10 @@
           prefs::kAccessibilityAutoclickMenuPosition));
 }
 
+void AccessibilityController::UpdateAutoclickMenuBoundsIfNeeded() {
+  Shell::Get()->autoclick_controller()->UpdateAutoclickMenuBoundsIfNeeded();
+}
+
 void AccessibilityController::UpdateCaretHighlightFromPref() {
   DCHECK(active_user_prefs_);
   const bool enabled = active_user_prefs_->GetBoolean(
diff --git a/ash/accessibility/accessibility_controller.h b/ash/accessibility/accessibility_controller.h
index d28156d..31c2df7 100644
--- a/ash/accessibility/accessibility_controller.h
+++ b/ash/accessibility/accessibility_controller.h
@@ -76,6 +76,11 @@
   void SetAutoclickMenuPosition(mojom::AutoclickMenuPosition position);
   mojom::AutoclickMenuPosition GetAutoclickMenuPosition();
 
+  // Update the autoclick menu bounds if necessary. This may need to happen when
+  // the display work area changes, or if system ui regions change (like the
+  // virtual keyboard position).
+  void UpdateAutoclickMenuBoundsIfNeeded();
+
   void SetCaretHighlightEnabled(bool enabled);
   bool caret_highlight_enabled() const { return caret_highlight_enabled_; }
 
diff --git a/ash/autoclick/autoclick_controller.cc b/ash/autoclick/autoclick_controller.cc
index 0c08108..84373da 100644
--- a/ash/autoclick/autoclick_controller.cc
+++ b/ash/autoclick/autoclick_controller.cc
@@ -147,6 +147,10 @@
 void AutoclickController::SetMenuPosition(
     mojom::AutoclickMenuPosition menu_position) {
   menu_position_ = menu_position;
+  UpdateAutoclickMenuBoundsIfNeeded();
+}
+
+void AutoclickController::UpdateAutoclickMenuBoundsIfNeeded() {
   if (menu_bubble_controller_)
     menu_bubble_controller_->SetPosition(menu_position_);
 }
diff --git a/ash/autoclick/autoclick_controller.h b/ash/autoclick/autoclick_controller.h
index b0d26008..998507ed 100644
--- a/ash/autoclick/autoclick_controller.h
+++ b/ash/autoclick/autoclick_controller.h
@@ -61,6 +61,9 @@
   // Sets the menu position and updates the UI.
   void SetMenuPosition(mojom::AutoclickMenuPosition menu_position);
 
+  // Update the bubble menu bounds if necessary to avoid system UI.
+  void UpdateAutoclickMenuBoundsIfNeeded();
+
   // Sets whether to revert to a left click after any other event type.
   void set_revert_to_left_click(bool revert_to_left_click) {
     revert_to_left_click_ = revert_to_left_click;
diff --git a/ash/autoclick/autoclick_unittest.cc b/ash/autoclick/autoclick_unittest.cc
index 9d4821a..781aa84 100644
--- a/ash/autoclick/autoclick_unittest.cc
+++ b/ash/autoclick/autoclick_unittest.cc
@@ -9,6 +9,8 @@
 #include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
 #include "ash/system/accessibility/autoclick_menu_view.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/collision_detection/collision_detection_utils.h"
+#include "ash/wm/desks/desks_util.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
@@ -757,9 +759,11 @@
     EXPECT_EQ(0u, events.size());
 
     // If we move over the bubble but not over any button than no real click
-    // occurs.
+    // occurs. There is no button at the top of the bubble.
     button_location = gfx::ScaleToRoundedPoint(
-        GetAutoclickMenuView()->GetBoundsInScreen().CenterPoint(), test.scale);
+        GetAutoclickMenuView()->GetBoundsInScreen().top_center() +
+            gfx::Vector2d(0, 1),
+        test.scale);
     GetEventGenerator()->MoveMouseTo(button_location);
     events = WaitForMouseEvents();
     EXPECT_EQ(0u, events.size());
@@ -841,12 +845,9 @@
   Shelf* shelf = GetPrimaryShelf();
 
   // Create a visible window so auto-hide behavior is enforced.
-  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
-  params.bounds = gfx::Rect(0, 0, 200, 200);
-  params.context = CurrentContext();
-  views::Widget* widget = new views::Widget;
-  widget->Init(params);
-  widget->Show();
+  std::unique_ptr<views::Widget> widget =
+      CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
+                       gfx::Rect(0, 0, 200, 200), true /* show */);
 
   // Turn on auto-hide for the shelf.
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
@@ -864,4 +865,55 @@
   Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
 }
 
+TEST_F(AutoclickTest, BubbleMovesWithShelfPositionChange) {
+  UpdateDisplay("800x600");
+  int screen_width = 800;
+  int screen_height = 600;
+
+  // Create a visible window so WMEvents occur.
+  std::unique_ptr<views::Widget> widget =
+      CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
+                       gfx::Rect(0, 0, 200, 200), true /* show */);
+
+  // Set up autoclick and the shelf.
+  Shell::Get()->accessibility_controller()->SetAutoclickEnabled(true);
+  Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
+      mojom::AutoclickMenuPosition::kBottomRight);
+  Shelf* shelf = GetPrimaryShelf();
+  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
+  EXPECT_EQ(shelf->GetVisibilityState(), SHELF_VISIBLE);
+  AutoclickMenuView* menu = GetAutoclickMenuView();
+  ASSERT_TRUE(menu);
+
+  shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+  // The menu should be positioned above the shelf, not overlapping.
+  EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
+            screen_height - shelf->GetIdealBounds().height() -
+                kCollisionWindowWorkAreaInsetsDp);
+  // And all the way to the right.
+  EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
+            screen_width - kCollisionWindowWorkAreaInsetsDp);
+
+  shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
+  // The menu should move to the bottom of the screen.
+  EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
+            screen_height - kCollisionWindowWorkAreaInsetsDp);
+  // Still be at the far right.
+  EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
+            screen_width - kCollisionWindowWorkAreaInsetsDp);
+
+  shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
+  // The menu should stay at the bottom of the screen.
+  EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
+            screen_height - kCollisionWindowWorkAreaInsetsDp);
+  // And should be offset from the far right by the shelf width.
+  EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
+            screen_width - kCollisionWindowWorkAreaInsetsDp -
+                shelf->GetIdealBounds().width());
+
+  // Reset state.
+  Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
+  shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+}
+
 }  // namespace ash
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc
index 6b95b9e..61e56bb 100644
--- a/ash/public/cpp/ash_switches.cc
+++ b/ash/public/cpp/ash_switches.cc
@@ -18,9 +18,6 @@
 // Enable keyboard shortcuts used by developers only.
 const char kAshDeveloperShortcuts[] = "ash-dev-shortcuts";
 
-// Disables the split view on tablet mode.
-const char kAshDisableTabletSplitView[] = "disable-tablet-splitview";
-
 // Disable the Touch Exploration Mode. Touch Exploration Mode will no longer be
 // turned on automatically when spoken feedback is enabled when this flag is
 // set.
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h
index 7b7d7f2e..0a4984b 100644
--- a/ash/public/cpp/ash_switches.h
+++ b/ash/public/cpp/ash_switches.h
@@ -19,7 +19,6 @@
 ASH_PUBLIC_EXPORT extern const char kAshConstrainPointerToRoot[];
 ASH_PUBLIC_EXPORT extern const char kAshDebugShortcuts[];
 ASH_PUBLIC_EXPORT extern const char kAshDeveloperShortcuts[];
-ASH_PUBLIC_EXPORT extern const char kAshDisableTabletSplitView[];
 ASH_PUBLIC_EXPORT extern const char kAshDisableTouchExplorationMode[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableCursorMotionBlur[];
 ASH_PUBLIC_EXPORT extern const char kAshEnableV1AppBackButton[];
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller.cc b/ash/system/accessibility/autoclick_menu_bubble_controller.cc
index 3ddd809..4119bb91 100644
--- a/ash/system/accessibility/autoclick_menu_bubble_controller.cc
+++ b/ash/system/accessibility/autoclick_menu_bubble_controller.cc
@@ -6,12 +6,15 @@
 
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/system/tray/tray_background_view.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/unified/unified_system_tray_view.h"
 #include "ash/wm/collision_detection/collision_detection_utils.h"
 #include "ash/wm/work_area_insets.h"
+#include "ash/wm/workspace/workspace_layout_manager.h"
+#include "ash/wm/workspace_controller.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/events/event_utils.h"
 
@@ -38,35 +41,50 @@
 
 void AutoclickMenuBubbleController::SetPosition(
     mojom::AutoclickMenuPosition position) {
-  if (!menu_view_ || !bubble_view_)
+  if (!menu_view_ || !bubble_view_ || !bubble_widget_)
     return;
 
-  menu_view_->UpdatePosition(position);
-  // TODO(katie): On first load it can display over top of the shelf on Chrome
-  // OS emulated on Linux (not reproduced on Eve). There must be a race
-  // condition with the user work area bounds loading.
+  // No need to update the menu view's UX if it's already in the right
+  // AutoclickMenuPosition.
+  if (position_ != position) {
+    menu_view_->UpdatePosition(position);
+    position_ = position;
+  }
 
-  // TODO(katie): Support multiple displays.
-  gfx::Rect work_area = WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow())
-                            ->user_work_area_bounds();
-  gfx::Rect new_position;
+  // Calculates the ideal bounds.
+  // TODO(katie): Support multiple displays: draw the menu on whichever display
+  // the cursor is on.
+  aura::Window* window = Shell::GetPrimaryRootWindow();
+  gfx::Rect work_area =
+      WorkAreaInsets::ForWindow(window)->user_work_area_bounds();
+  gfx::Rect new_bounds;
   switch (position) {
     case mojom::AutoclickMenuPosition::kBottomRight:
-      new_position = gfx::Rect(work_area.width(), work_area.height(), 0, 0);
+      new_bounds = gfx::Rect(work_area.right(), work_area.bottom(), 0, 0);
       break;
     case mojom::AutoclickMenuPosition::kBottomLeft:
-      new_position = gfx::Rect(work_area.x(), work_area.height(), 0, 0);
+      new_bounds = gfx::Rect(work_area.x(), work_area.bottom(), 0, 0);
       break;
     case mojom::AutoclickMenuPosition::kTopLeft:
       // Setting the top to 1 instead of 0 so that the view is drawn on screen.
-      new_position = gfx::Rect(work_area.x(), 1, 0, 0);
+      new_bounds = gfx::Rect(work_area.x(), 1, 0, 0);
       break;
     case mojom::AutoclickMenuPosition::kTopRight:
       // Setting the top to 1 instead of 0 so that the view is drawn on screen.
-      new_position = gfx::Rect(work_area.width(), 1, 0, 0);
+      new_bounds = gfx::Rect(work_area.right(), 1, 0, 0);
       break;
   }
-  bubble_view_->MoveToPosition(new_position);
+
+  // Update the preferred bounds based on other system windows.
+  gfx::Rect resting_bounds = CollisionDetectionUtils::GetRestingPosition(
+      display::Screen::GetScreen()->GetDisplayNearestWindow(
+          bubble_widget_->GetNativeWindow()),
+      new_bounds,
+      CollisionDetectionUtils::RelativePriority::kAutomaticClicksMenu);
+  if (bubble_view_->anchor_rect() == resting_bounds)
+    return;
+
+  bubble_view_->MoveToPosition(resting_bounds);
 }
 
 void AutoclickMenuBubbleController::ShowBubble(
@@ -84,9 +102,7 @@
   init_params.parent_window = Shell::GetContainer(
       Shell::GetPrimaryRootWindow(), kShellWindowId_AutoclickContainer);
   init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect;
-  init_params.insets =
-      gfx::Insets(kUnifiedMenuPadding, kUnifiedMenuPadding,
-                  kUnifiedMenuPadding - 1, kUnifiedMenuPadding - 1);
+  init_params.insets = gfx::Insets();
   init_params.min_width = kAutoclickMenuWidth;
   init_params.max_width = kAutoclickMenuWidth;
   init_params.corner_radius = kUnifiedTrayCornerRadius;
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller.h b/ash/system/accessibility/autoclick_menu_bubble_controller.h
index f0a047d..ca8768d 100644
--- a/ash/system/accessibility/autoclick_menu_bubble_controller.h
+++ b/ash/system/accessibility/autoclick_menu_bubble_controller.h
@@ -5,6 +5,7 @@
 #ifndef ASH_SYSTEM_ACCESSIBILITY_AUTOCLICK_MENU_BUBBLE_CONTROLLER_H_
 #define ASH_SYSTEM_ACCESSIBILITY_AUTOCLICK_MENU_BUBBLE_CONTROLLER_H_
 
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/system/accessibility/autoclick_menu_view.h"
 #include "ash/system/tray/tray_bubble_view.h"
 
@@ -44,6 +45,7 @@
   // Owned by views hierarchy.
   AutoclickMenuBubbleView* bubble_view_ = nullptr;
   AutoclickMenuView* menu_view_ = nullptr;
+  mojom::AutoclickMenuPosition position_ = kDefaultAutoclickMenuPosition;
 
   views::Widget* bubble_widget_ = nullptr;
 
diff --git a/ash/wm/base_state.cc b/ash/wm/base_state.cc
index 0858c5c..d062c929e 100644
--- a/ash/wm/base_state.cc
+++ b/ash/wm/base_state.cc
@@ -4,6 +4,7 @@
 
 #include "ash/wm/base_state.h"
 
+#include "ash/accessibility/accessibility_controller.h"
 #include "ash/public/cpp/window_animation_types.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/public/cpp/window_state_type.h"
@@ -26,6 +27,11 @@
 void BaseState::OnWMEvent(WindowState* window_state, const WMEvent* event) {
   if (event->IsWorkspaceEvent()) {
     HandleWorkspaceEvents(window_state, event);
+    if (Shell::Get()->accessibility_controller()->autoclick_enabled()) {
+      Shell::Get()
+          ->accessibility_controller()
+          ->UpdateAutoclickMenuBoundsIfNeeded();
+    }
     if (window_state->IsPip())
       window_state->UpdatePipBounds();
     return;
diff --git a/ash/wm/collision_detection/collision_detection_utils.cc b/ash/wm/collision_detection/collision_detection_utils.cc
index 7eb3aaaf..0543e19 100644
--- a/ash/wm/collision_detection/collision_detection_utils.cc
+++ b/ash/wm/collision_detection/collision_detection_utils.cc
@@ -18,7 +18,6 @@
 namespace ash {
 
 namespace {
-const int kCollisionWindowWorkAreaInsetsDp = 8;
 
 // A property key to store whether the a window should be ignored for window
 // collision detection. For example, StatusBubble windows.
diff --git a/ash/wm/collision_detection/collision_detection_utils.h b/ash/wm/collision_detection/collision_detection_utils.h
index 02bb80a..4ee425c6 100644
--- a/ash/wm/collision_detection/collision_detection_utils.h
+++ b/ash/wm/collision_detection/collision_detection_utils.h
@@ -12,6 +12,10 @@
 
 namespace ash {
 
+// The inset into the work area for a window's resting position. Visible for
+// testing.
+const static int kCollisionWindowWorkAreaInsetsDp = 8;
+
 // Provides utility functions to compute resting positions for windows which
 // wish to avoid other system windows, for example, the PIP and the Automatic
 // Clicks bubble menu.
@@ -109,4 +113,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_WM_COLLISION_DETECTION_COLLISION_DETECTION_UTILS_H_
\ No newline at end of file
+#endif  // ASH_WM_COLLISION_DETECTION_COLLISION_DETECTION_UTILS_H_
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc
index 03afe6b..5f859da 100644
--- a/ash/wm/splitview/split_view_utils.cc
+++ b/ash/wm/splitview/split_view_utils.cc
@@ -224,11 +224,6 @@
 }
 
 bool ShouldAllowSplitView() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAshDisableTabletSplitView)) {
-    return false;
-  }
-
   if (!Shell::Get()
            ->tablet_mode_controller()
            ->IsTabletModeWindowManagerEnabled() &&
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index b26cf0e..d406db8 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -39,18 +39,16 @@
 
 namespace ash {
 
-WorkspaceLayoutManager::SettingsBubbleWindowObserver::
-    SettingsBubbleWindowObserver(
-        WorkspaceLayoutManager* workspace_layout_manager)
+WorkspaceLayoutManager::BubbleWindowObserver::BubbleWindowObserver(
+    WorkspaceLayoutManager* workspace_layout_manager)
     : workspace_layout_manager_(workspace_layout_manager) {}
 
-WorkspaceLayoutManager::SettingsBubbleWindowObserver::
-    ~SettingsBubbleWindowObserver() {
+WorkspaceLayoutManager::BubbleWindowObserver::~BubbleWindowObserver() {
   for (auto* window : windows_)
     window->RemoveObserver(this);
 }
 
-void WorkspaceLayoutManager::SettingsBubbleWindowObserver::ObserveWindow(
+void WorkspaceLayoutManager::BubbleWindowObserver::ObserveWindow(
     aura::Window* window) {
   if (!windows_.count(window)) {
     windows_.insert(window);
@@ -58,8 +56,8 @@
   }
 }
 
-void WorkspaceLayoutManager::SettingsBubbleWindowObserver::
-    OnWindowHierarchyChanged(const HierarchyChangeParams& params) {
+void WorkspaceLayoutManager::BubbleWindowObserver::OnWindowHierarchyChanged(
+    const HierarchyChangeParams& params) {
   if (params.new_parent &&
       params.new_parent !=
           workspace_layout_manager_->settings_bubble_container_) {
@@ -67,26 +65,27 @@
   }
 }
 
-void WorkspaceLayoutManager::SettingsBubbleWindowObserver::
-    OnWindowVisibilityChanged(aura::Window* window, bool visible) {
+void WorkspaceLayoutManager::BubbleWindowObserver::OnWindowVisibilityChanged(
+    aura::Window* window,
+    bool visible) {
   workspace_layout_manager_->NotifySystemUiAreaChanged();
 }
 
-void WorkspaceLayoutManager::SettingsBubbleWindowObserver::OnWindowDestroying(
+void WorkspaceLayoutManager::BubbleWindowObserver::OnWindowDestroying(
     aura::Window* window) {
   StopOberservingWindow(window);
 }
 
-void WorkspaceLayoutManager::SettingsBubbleWindowObserver::
-    OnWindowBoundsChanged(aura::Window* window,
-                          const gfx::Rect& old_bounds,
-                          const gfx::Rect& new_bounds,
-                          ui::PropertyChangeReason reason) {
+void WorkspaceLayoutManager::BubbleWindowObserver::OnWindowBoundsChanged(
+    aura::Window* window,
+    const gfx::Rect& old_bounds,
+    const gfx::Rect& new_bounds,
+    ui::PropertyChangeReason reason) {
   workspace_layout_manager_->NotifySystemUiAreaChanged();
 }
 
-void WorkspaceLayoutManager::SettingsBubbleWindowObserver::
-    StopOberservingWindow(aura::Window* window) {
+void WorkspaceLayoutManager::BubbleWindowObserver::StopOberservingWindow(
+    aura::Window* window) {
   windows_.erase(window);
   window->RemoveObserver(this);
 }
@@ -96,6 +95,7 @@
       root_window_(window->GetRootWindow()),
       root_window_controller_(RootWindowController::ForWindow(root_window_)),
       settings_bubble_window_observer_(this),
+      autoclick_bubble_window_observer_(this),
       work_area_in_parent_(
           screen_util::GetDisplayWorkAreaBoundsInParent(window_)),
       is_fullscreen_(wm::GetWindowForFullscreenModeForContext(window) !=
@@ -109,6 +109,8 @@
   keyboard::KeyboardController::Get()->AddObserver(this);
   settings_bubble_container_ = window->GetRootWindow()->GetChildById(
       kShellWindowId_SettingBubbleContainer);
+  autoclick_bubble_container_ =
+      window->GetRootWindow()->GetChildById(kShellWindowId_AutoclickContainer);
   root_window_controller_->shelf()->AddObserver(this);
 }
 
@@ -118,6 +120,8 @@
     root_window_->RemoveObserver(this);
   if (settings_bubble_container_)
     settings_bubble_container_->RemoveObserver(this);
+  if (autoclick_bubble_container_)
+    autoclick_bubble_container_->RemoveObserver(this);
   for (aura::Window* window : windows_) {
     wm::WindowState* window_state = wm::GetWindowState(window);
     window_state->RemoveObserver(this);
@@ -261,8 +265,12 @@
 
 void WorkspaceLayoutManager::OnWindowHierarchyChanged(
     const HierarchyChangeParams& params) {
-  if (params.new_parent && params.new_parent == settings_bubble_container_)
-    settings_bubble_window_observer_.ObserveWindow(params.target);
+  if (params.new_parent) {
+    if (params.new_parent == settings_bubble_container_)
+      settings_bubble_window_observer_.ObserveWindow(params.target);
+    if (params.new_parent == autoclick_bubble_container_)
+      autoclick_bubble_window_observer_.ObserveWindow(params.target);
+  }
   // The window should have a parent (unless it's being removed), so we can
   // create WindowState, which requires its parent. (crbug.com/924305)
   // TODO(oshima): Change this to |EnsureWindowState|, then change
@@ -292,6 +300,8 @@
 void WorkspaceLayoutManager::OnWindowAdded(aura::Window* window) {
   if (window->parent() == settings_bubble_container_)
     settings_bubble_window_observer_.ObserveWindow(window);
+  if (window->parent() == autoclick_bubble_container_)
+    autoclick_bubble_window_observer_.ObserveWindow(window);
 }
 
 void WorkspaceLayoutManager::OnWindowPropertyChanged(aura::Window* window,
@@ -323,6 +333,8 @@
   }
   if (settings_bubble_container_ == window)
     settings_bubble_container_ = nullptr;
+  if (autoclick_bubble_container_ == window)
+    autoclick_bubble_container_ = nullptr;
 }
 
 void WorkspaceLayoutManager::OnWindowBoundsChanged(
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h
index d39b5b6..79efeaa7 100644
--- a/ash/wm/workspace/workspace_layout_manager.h
+++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -112,13 +112,12 @@
   friend class WorkspaceControllerTestApi;
   typedef std::set<aura::Window*> WindowSet;
 
-  // Observes changes in windows in the SettingsBubbleWindowObserver, and
+  // Observes changes in windows in the BubbleWindowObserver, and
   // notifies WorkspaceLayoutManager to send out system ui area change events.
-  class SettingsBubbleWindowObserver : public aura::WindowObserver {
+  class BubbleWindowObserver : public aura::WindowObserver {
    public:
-    SettingsBubbleWindowObserver(
-        WorkspaceLayoutManager* workspace_layout_manager);
-    ~SettingsBubbleWindowObserver() override;
+    BubbleWindowObserver(WorkspaceLayoutManager* workspace_layout_manager);
+    ~BubbleWindowObserver() override;
 
     void ObserveWindow(aura::Window* window);
 
@@ -138,7 +137,7 @@
 
     void StopOberservingWindow(aura::Window* window);
 
-    DISALLOW_COPY_AND_ASSIGN(SettingsBubbleWindowObserver);
+    DISALLOW_COPY_AND_ASSIGN(BubbleWindowObserver);
   };
 
   // Adjusts the bounds of all managed windows when the display area changes.
@@ -162,16 +161,18 @@
   void UpdateAlwaysOnTop(aura::Window* active_desk_fullscreen_window);
 
   // Notifies windows about a change in a system ui area. This could be
-  // the keyboard or any window in the SettingsBubbleContainer. Windows will
-  // only be notified about changes to system ui areas on the display they are
-  // on.
+  // the keyboard or any window in the SettingsBubbleContainer or
+  // autoclick_menu_bubble_container_. Windows will only be notified about
+  // changes to system ui areas on the display they are on.
   void NotifySystemUiAreaChanged();
 
   aura::Window* window_;
   aura::Window* root_window_;
   RootWindowController* root_window_controller_;
   aura::Window* settings_bubble_container_;
-  SettingsBubbleWindowObserver settings_bubble_window_observer_;
+  BubbleWindowObserver settings_bubble_window_observer_;
+  aura::Window* autoclick_bubble_container_;
+  BubbleWindowObserver autoclick_bubble_window_observer_;
 
   // Set of windows we're listening to.
   WindowSet windows_;
diff --git a/base/android/bundle_utils.cc b/base/android/bundle_utils.cc
index 6477c0f..759494b5 100644
--- a/base/android/bundle_utils.cc
+++ b/base/android/bundle_utils.cc
@@ -14,6 +14,11 @@
 namespace android {
 
 // static
+bool BundleUtils::IsBundle() {
+  return Java_BundleUtils_isBundle(base::android::AttachCurrentThread());
+}
+
+// static
 void* BundleUtils::DlOpenModuleLibrary(const std::string& libary_name) {
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jstring> java_path = Java_BundleUtils_getNativeLibraryPath(
diff --git a/base/android/bundle_utils.h b/base/android/bundle_utils.h
index 2591bff..e28c137 100644
--- a/base/android/bundle_utils.h
+++ b/base/android/bundle_utils.h
@@ -15,6 +15,9 @@
 // Utils to help working with android app bundles.
 class BASE_EXPORT BundleUtils {
  public:
+  // Returns true if the current build is a bundle.
+  static bool IsBundle();
+
   // dlopen variant that works for native libraries in dynamic feature modules.
   static void* DlOpenModuleLibrary(const std::string& libary_name);
 };
diff --git a/base/android/java/src/org/chromium/base/BundleUtils.java b/base/android/java/src/org/chromium/base/BundleUtils.java
index b3c9c085..b96edd9 100644
--- a/base/android/java/src/org/chromium/base/BundleUtils.java
+++ b/base/android/java/src/org/chromium/base/BundleUtils.java
@@ -24,6 +24,7 @@
     }
 
     /* Returns true if the current build is a bundle. */
+    @CalledByNative
     public static boolean isBundle() {
         return sIsBundle;
     }
diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc
index 2f1909b..0bf3bdc 100644
--- a/base/message_loop/message_pump_glib.cc
+++ b/base/message_loop/message_pump_glib.cc
@@ -11,6 +11,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
@@ -19,20 +20,19 @@
 
 namespace {
 
-// Return a timeout suitable for the glib loop, -1 to block forever,
-// 0 to return right away, or a timeout in milliseconds from now.
-int GetTimeIntervalMilliseconds(const TimeTicks& from) {
-  if (from.is_null())
+// Return a timeout suitable for the glib loop according to |next_task_time|, -1
+// to block forever, 0 to return right away, or a timeout in milliseconds from
+// now.
+int GetTimeIntervalMilliseconds(TimeTicks next_task_time) {
+  if (next_task_time.is_null())
+    return 0;
+  else if (next_task_time.is_max())
     return -1;
 
-  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
-  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
-  // 6?  It should be 6 to avoid executing delayed work too early.
-  int delay = static_cast<int>(
-      ceil((from - TimeTicks::Now()).InMillisecondsF()));
+  auto timeout_ms =
+      (next_task_time - TimeTicks::Now()).InMillisecondsRoundedUp();
 
-  // If this value is negative, then we need to run delayed work soon.
-  return delay < 0 ? 0 : delay;
+  return timeout_ms < 0 ? 0 : saturated_cast<int>(timeout_ms);
 }
 
 // A brief refresher on GLib:
@@ -68,8 +68,8 @@
 // - Return true if any of prepare() or check() returned true.
 //
 // gtk_main_iteration just calls g_main_context_iteration, which does the whole
-// thing, respecting the timeout for the poll (and block, although it is
-// expected not to if gtk_events_pending returned true), and call dispatch.
+// thing, respecting the timeout for the poll (and block, although it is to if
+// gtk_events_pending returned true), and call dispatch.
 //
 // Thus it is important to only return true from prepare or check if we
 // actually have events or work to do. We also need to make sure we keep
@@ -79,10 +79,9 @@
 //
 // For the GLib pump we try to follow the Windows UI pump model:
 // - Whenever we receive a wakeup event or the timer for delayed work expires,
-// we run DoWork and/or DoDelayedWork. That part will also run in the other
-// event pumps.
-// - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main
-// loop, around event handling.
+// we run DoSomeWork. That part will also run in the other event pumps.
+// - We also run DoSomeWork, and possibly DoIdleWork, in the main loop,
+// around event handling.
 
 struct WorkSource : public GSource {
   MessagePumpGlib* pump;
@@ -169,10 +168,10 @@
   // Used to count how many Run() invocations are on the stack.
   int run_depth;
 
-  // This keeps the state of whether the pump got signaled that there was new
-  // work to be done. Since we eat the message on the wake up pipe as soon as
-  // we get it, we keep that state here to stay consistent.
-  bool has_work;
+  // The information of the next task available at this run-level. Stored in
+  // RunState because different set of tasks can be accessible at various
+  // run-levels (e.g. non-nestable tasks).
+  Delegate::NextWorkInfo next_work_info;
 };
 
 MessagePumpGlib::MessagePumpGlib()
@@ -212,15 +211,11 @@
 
 // Return the timeout we want passed to poll.
 int MessagePumpGlib::HandlePrepare() {
-  // We know we have work, but we haven't called HandleDispatch yet. Don't let
-  // the pump block so that we can do some processing.
-  if (state_ &&  // state_ may be null during tests.
-      state_->has_work)
+  // |state_| may be null during tests.
+  if (!state_)
     return 0;
 
-  // We don't think we have work to do, but make sure not to block
-  // longer than the next time we need to run delayed work.
-  return GetTimeIntervalMilliseconds(delayed_work_time_);
+  return GetTimeIntervalMilliseconds(state_->next_work_info.delayed_run_time);
 }
 
 bool MessagePumpGlib::HandleCheck() {
@@ -240,18 +235,17 @@
     }
     DCHECK((num_bytes == 1 && msg[0] == '!') ||
            (num_bytes == 2 && msg[0] == '!' && msg[1] == '!'));
-    // Since we ate the message, we need to record that we have more work,
+    // Since we ate the message, we need to record that we have immediate work,
     // because HandleCheck() may be called without HandleDispatch being called
     // afterwards.
-    state_->has_work = true;
+    state_->next_work_info = {TimeTicks()};
+    return true;
   }
 
-  if (state_->has_work)
-    return true;
-
-  if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) {
-    // The timer has expired. That condition will stay true until we process
-    // that delayed work, so we don't need to record this differently.
+  // As described in the summary at the top : Check is a second-chance to
+  // Prepare, verify whether we have work ready again.
+  if (GetTimeIntervalMilliseconds(state_->next_work_info.delayed_run_time) ==
+      0) {
     return true;
   }
 
@@ -259,19 +253,7 @@
 }
 
 void MessagePumpGlib::HandleDispatch() {
-  state_->has_work = false;
-  if (state_->delegate->DoWork()) {
-    // NOTE: on Windows at this point we would call ScheduleWork (see
-    // MessagePumpGlib::HandleWorkMessage in message_pump_win.cc). But here,
-    // instead of posting a message on the wakeup pipe, we can avoid the
-    // syscalls and just signal that we have more work.
-    state_->has_work = true;
-  }
-
-  if (state_->should_quit)
-    return;
-
-  state_->delegate->DoDelayedWork(&delayed_work_time_);
+  state_->next_work_info = state_->delegate->DoSomeWork();
 }
 
 void MessagePumpGlib::Run(Delegate* delegate) {
@@ -283,7 +265,6 @@
   state.delegate = delegate;
   state.should_quit = false;
   state.run_depth = state_ ? state_->run_depth + 1 : 1;
-  state.has_work = false;
 
   RunState* previous_state = state_;
   state_ = &state;
@@ -306,12 +287,8 @@
     if (state_->should_quit)
       break;
 
-    more_work_is_plausible |= state_->delegate->DoWork();
-    if (state_->should_quit)
-      break;
-
-    more_work_is_plausible |=
-        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    state_->next_work_info = state_->delegate->DoSomeWork();
+    more_work_is_plausible |= state_->next_work_info.is_immediate();
     if (state_->should_quit)
       break;
 
@@ -347,7 +324,6 @@
 void MessagePumpGlib::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
   // We need to wake up the loop in case the poll timeout needs to be
   // adjusted.  This will cause us to try to do work, but that's OK.
-  delayed_work_time_ = delayed_work_time;
   ScheduleWork();
 }
 
diff --git a/base/message_loop/message_pump_glib.h b/base/message_loop/message_pump_glib.h
index d79dba55..a22e6fb 100644
--- a/base/message_loop/message_pump_glib.h
+++ b/base/message_loop/message_pump_glib.h
@@ -56,9 +56,6 @@
   // dispatched.
   GMainContext* context_;
 
-  // This is the time when we need to do delayed work.
-  TimeTicks delayed_work_time_;
-
   // The work source.  It is shared by all calls to Run and destroyed when
   // the message pump is destroyed.
   GSource* work_source_;
diff --git a/base/message_loop/message_pump_unittest.cc b/base/message_loop/message_pump_unittest.cc
index 16c0d04..d9d7532 100644
--- a/base/message_loop/message_pump_unittest.cc
+++ b/base/message_loop/message_pump_unittest.cc
@@ -44,7 +44,7 @@
       // iOS uses a MessagePumpDefault for UI in unit tests, ref.
       // test_support_ios.mm::CreateMessagePumpForUIForTests().
       return true;
-#elif defined(OS_WIN) || defined(OS_ANDROID)
+#elif defined(OS_WIN) || defined(OS_ANDROID) || defined(USE_GLIB)
       return true;
 #elif defined(OS_POSIX) && !defined(OS_NACL_SFI)
       // MessagePumpLibevent was migrated (ref. message_pump_for_ui.h and
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 7175865b..37bfe8b9 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -432,6 +432,7 @@
   "//build/config/compiler:default_stack_frames",
   "//build/config/compiler:default_symbols",
   "//build/config/compiler:export_dynamic",
+  "//build/config/compiler:fatal_linker_warnings_win",
   "//build/config/compiler:no_exceptions",
   "//build/config/compiler:no_rtti",
   "//build/config/compiler:runtime_library",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index f8a862a..b4b0522 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1085,7 +1085,8 @@
   }
 
   # Makes builds independent of absolute file path.
-  if (symbol_level != 0 && is_clang && strip_absolute_paths_from_debug_symbols) {
+  if (symbol_level != 0 && is_clang &&
+      strip_absolute_paths_from_debug_symbols) {
     # If debug option is given, clang includes $cwd in debug info by default.
     # For such build, this flag generates reproducible obj files even we use
     # different build directory like "out/feature_a" and "out/feature_b" if
@@ -1173,7 +1174,8 @@
 config("assembler_debug_dir") {
   # TODO(thakis): Once openmax_dl no longer uses -fno-integrated-as, move
   # this behind the -fdebug-compilation-dir cflags in the "compiler" config.
-  if (symbol_level != 0 && is_clang && strip_absolute_paths_from_debug_symbols) {
+  if (symbol_level != 0 && is_clang &&
+      strip_absolute_paths_from_debug_symbols) {
     if (!is_win) {
       # We don't use clang -cc1as on Windows (yet? https://crbug.com/762167)
       asmflags = [ "-Wa,-fdebug-compilation-dir,." ]
@@ -1242,9 +1244,6 @@
     if (treat_warnings_as_errors) {
       cflags += [ "/WX" ]
     }
-    if (fatal_linker_warnings) {
-      ldflags += [ "/WX" ]
-    }
 
     cflags += [
       # Warnings permanently disabled:
@@ -1509,6 +1508,14 @@
   }
 }
 
+config("fatal_linker_warnings_win") {
+  # TODO(thakis): Move this back into default_warnings once
+  # https://crbug.com/958955 is resolved.
+  if (is_win && fatal_linker_warnings) {
+    ldflags = [ "/WX" ]
+  }
+}
+
 # chromium_code ---------------------------------------------------------------
 #
 # Toggles between higher and lower warnings for code that is (or isn't)
diff --git a/cc/animation/scroll_timeline.cc b/cc/animation/scroll_timeline.cc
index 16ef8de..cc4b5bf 100644
--- a/cc/animation/scroll_timeline.cc
+++ b/cc/animation/scroll_timeline.cc
@@ -47,25 +47,33 @@
       time_range_, fill_);
 }
 
+bool ScrollTimeline::IsActive(const ScrollTree& scroll_tree,
+                              bool is_active_tree) const {
+  // If pending tree with our scroller hasn't been activated, or the scroller
+  // has been removed (e.g. if it is no longer composited).
+  if ((is_active_tree && !active_id_) || (!is_active_tree && !pending_id_))
+    return false;
+
+  ElementId scroller_id =
+      is_active_tree ? active_id_.value() : pending_id_.value();
+  // The scroller is not in the ScrollTree if it is not currently scrollable
+  // (e.g. has overflow: visible). In this case the timeline is not active.
+  return scroll_tree.FindNodeFromElementId(scroller_id);
+}
+
 base::Optional<base::TimeTicks> ScrollTimeline::CurrentTime(
     const ScrollTree& scroll_tree,
     bool is_active_tree) const {
-  // We may be asked for the CurrentTime before the pending tree with our
-  // scroller has been activated, or after the scroller has been removed (e.g.
-  // if it is no longer composited). In these cases the best we can do is to
-  // return an unresolved time value.
-  if ((is_active_tree && !active_id_) || (!is_active_tree && !pending_id_))
+  // If the timeline is not active return unresolved value by the spec.
+  // https://github.com/WICG/scroll-animations/issues/31
+  // https://wicg.github.io/scroll-animations/#current-time-algorithm
+  if (!IsActive(scroll_tree, is_active_tree))
     return base::nullopt;
 
   ElementId scroller_id =
       is_active_tree ? active_id_.value() : pending_id_.value();
-
-  // The scroller may not be in the ScrollTree if it is not currently scrollable
-  // (e.g. has overflow: visible). By the spec, return an unresolved time value.
   const ScrollNode* scroll_node =
       scroll_tree.FindNodeFromElementId(scroller_id);
-  if (!scroll_node)
-    return base::nullopt;
 
   gfx::ScrollOffset offset =
       scroll_tree.GetPixelSnappedScrollOffset(scroll_node->id);
diff --git a/cc/animation/scroll_timeline.h b/cc/animation/scroll_timeline.h
index 759d261..152c1a64 100644
--- a/cc/animation/scroll_timeline.h
+++ b/cc/animation/scroll_timeline.h
@@ -41,6 +41,11 @@
   // compositor.
   std::unique_ptr<ScrollTimeline> CreateImplInstance() const;
 
+  // ScrollTimeline is active if the scroll node exists in active or pending
+  // scroll tree.
+  virtual bool IsActive(const ScrollTree& scroll_tree,
+                        bool is_active_tree) const;
+
   // Calculate the current time of the ScrollTimeline. This is either a
   // base::TimeTicks value or base::nullopt if the current time is unresolved.
   // The internal calculations are performed using doubles and the result is
diff --git a/cc/animation/scroll_timeline_unittest.cc b/cc/animation/scroll_timeline_unittest.cc
index 490b9428..0b62b8f 100644
--- a/cc/animation/scroll_timeline_unittest.cc
+++ b/cc/animation/scroll_timeline_unittest.cc
@@ -181,8 +181,8 @@
                                base::nullopt, base::nullopt, 100,
                                KeyframeModel::FillMode::NONE);
 
-  // Now create an impl version of the ScrollTimeline. Initilly this should only
-  // have a pending scroller id, as the active tree may not yet have the
+  // Now create an impl version of the ScrollTimeline. Initially this should
+  // only have a pending scroller id, as the active tree may not yet have the
   // scroller in it (as in this case).
   std::unique_ptr<ScrollTimeline> impl_timeline =
       main_timeline.CreateImplInstance();
@@ -379,4 +379,41 @@
       time_range, fill_auto_timeline.CurrentTime(scroll_tree(), false));
 }
 
+TEST_F(ScrollTimelineTest, Activeness) {
+  // ScrollTimeline with zero scroller id is inactive.
+  ScrollTimeline inactive_timeline1(base::nullopt, ScrollTimeline::ScrollDown,
+                                    base::nullopt, base::nullopt, 100,
+                                    KeyframeModel::FillMode::NONE);
+  EXPECT_FALSE(
+      inactive_timeline1.IsActive(scroll_tree(), false /*is_active_tree*/));
+  EXPECT_FALSE(
+      inactive_timeline1.IsActive(scroll_tree(), true /*is_active_tree*/));
+
+  // ScrollTimeline with a scroller that is not in the scroll tree is
+  // inactive.
+  ScrollTimeline inactive_timeline2(ElementId(2), ScrollTimeline::ScrollDown,
+                                    base::nullopt, base::nullopt, 100,
+                                    KeyframeModel::FillMode::NONE);
+  EXPECT_FALSE(
+      inactive_timeline2.IsActive(scroll_tree(), false /*is_active_tree*/));
+  // Activate the scroll tree.
+  inactive_timeline2.PromoteScrollTimelinePendingToActive();
+  EXPECT_FALSE(
+      inactive_timeline2.IsActive(scroll_tree(), true /*is_active_tree*/));
+
+  ScrollTimeline active_timeline(scroller_id(), ScrollTimeline::ScrollDown,
+                                 base::nullopt, base::nullopt, 100,
+                                 KeyframeModel::FillMode::NONE);
+  EXPECT_TRUE(
+      active_timeline.IsActive(scroll_tree(), false /*is_active_tree*/));
+  EXPECT_FALSE(
+      active_timeline.IsActive(scroll_tree(), true /*is_active_tree*/));
+
+  // Activate the scroll tree.
+  active_timeline.PromoteScrollTimelinePendingToActive();
+  EXPECT_TRUE(
+      active_timeline.IsActive(scroll_tree(), false /*is_active_tree*/));
+  EXPECT_TRUE(active_timeline.IsActive(scroll_tree(), true /*is_active_tree*/));
+}
+
 }  // namespace cc
diff --git a/cc/animation/worklet_animation.cc b/cc/animation/worklet_animation.cc
index 32e078ca..9e360062 100644
--- a/cc/animation/worklet_animation.cc
+++ b/cc/animation/worklet_animation.cc
@@ -103,11 +103,14 @@
                                         base::TimeTicks monotonic_time,
                                         const ScrollTree& scroll_tree,
                                         bool is_active_tree) {
+  bool is_timeline_active = IsTimelineActive(scroll_tree, is_active_tree);
   // Record the monotonic time to be the start time first time state is
   // generated. This time is used as the origin for computing the current time.
   // The start time of scroll-linked animations is always initialized to zero.
   // See: https://github.com/w3c/csswg-drafts/issues/2075
-  if (!start_time_.has_value())
+  // To stay consistent with blink::WorkletAnimation, record start time only
+  // when the timeline becomes active.
+  if (!start_time_.has_value() && is_timeline_active)
     start_time_ = scroll_timeline_ ? base::TimeTicks() : monotonic_time;
 
   // Skip running worklet animations with unchanged input time and reuse
@@ -115,11 +118,13 @@
   if (!NeedsUpdate(monotonic_time, scroll_tree, is_active_tree))
     return;
 
+  DCHECK(is_timeline_active || state_ == State::REMOVED);
+  // When the timeline is inactive we apply last current time to the animation.
   double current_time =
-      CurrentTime(monotonic_time, scroll_tree, is_active_tree);
-  // TODO(yigu): If current_time becomes newly unresolved and last_current_time_
-  // is resolved, we apply the last current time to the animation if the scroll
-  // timeline becomes newly inactive. See https://crbug.com/906050.
+      is_timeline_active
+          ? CurrentTime(monotonic_time, scroll_tree, is_active_tree)
+          : last_current_time_.value_or(
+                std::numeric_limits<double>::quiet_NaN());
   last_current_time_ = current_time;
 
   switch (state_) {
@@ -178,6 +183,7 @@
 double WorkletAnimation::CurrentTime(base::TimeTicks monotonic_time,
                                      const ScrollTree& scroll_tree,
                                      bool is_active_tree) {
+  DCHECK(IsTimelineActive(scroll_tree, is_active_tree));
   base::TimeTicks timeline_time;
   if (scroll_timeline_) {
     base::Optional<base::TimeTicks> scroll_monotonic_time =
@@ -195,21 +201,26 @@
 bool WorkletAnimation::NeedsUpdate(base::TimeTicks monotonic_time,
                                    const ScrollTree& scroll_tree,
                                    bool is_active_tree) {
-  // If we don't have a start time it means that an update was never sent to
-  // the worklet therefore we need one.
-  if (!start_time_.has_value())
-    return true;
-
-  DCHECK(state_ == State::PENDING || last_current_time_.has_value());
   if (state_ == State::REMOVED)
     return true;
 
+  // When the timeline is inactive we apply the last current time to the
+  // animation.
+  if (!IsTimelineActive(scroll_tree, is_active_tree))
+    return false;
+
   double current_time =
       CurrentTime(monotonic_time, scroll_tree, is_active_tree);
   bool needs_update = last_current_time_ != current_time;
   return needs_update;
 }
 
+bool WorkletAnimation::IsTimelineActive(const ScrollTree& scroll_tree,
+                                        bool is_active_tree) const {
+  return !scroll_timeline_ ||
+         scroll_timeline_->IsActive(scroll_tree, is_active_tree);
+}
+
 void WorkletAnimation::UpdateScrollTimeline(
     base::Optional<ElementId> scroller_id,
     base::Optional<double> start_scroll_offset,
diff --git a/cc/animation/worklet_animation.h b/cc/animation/worklet_animation.h
index d558e1b..b4deafc 100644
--- a/cc/animation/worklet_animation.h
+++ b/cc/animation/worklet_animation.h
@@ -121,6 +121,9 @@
   // Called by the UI thread WorletAnimation instance during commit.
   void SetPlaybackRate(double playback_rate);
 
+  bool IsTimelineActive(const ScrollTree& scroll_tree,
+                        bool is_active_tree) const;
+
   WorkletAnimationId worklet_animation_id_;
   std::string name_;
 
@@ -149,8 +152,8 @@
   base::Optional<base::TimeDelta> local_time_;
 
   base::Optional<base::TimeTicks> start_time_;
-  // Last current time used for updatig. We use this to skip updating if current
-  // time has not changed since last update.
+  // Last current time used for updating. We use this to skip updating if
+  // current time has not changed since last update.
   base::Optional<double> last_current_time_;
 
   State state_;
diff --git a/cc/animation/worklet_animation_unittest.cc b/cc/animation/worklet_animation_unittest.cc
index a1801ac..c8b4580e4 100644
--- a/cc/animation/worklet_animation_unittest.cc
+++ b/cc/animation/worklet_animation_unittest.cc
@@ -58,6 +58,7 @@
                        KeyframeModel::FillMode::NONE) {}
   MOCK_CONST_METHOD2(CurrentTime,
                      base::Optional<base::TimeTicks>(const ScrollTree&, bool));
+  MOCK_CONST_METHOD2(IsActive, bool(const ScrollTree&, bool));
 };
 
 TEST_F(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe) {
@@ -111,6 +112,7 @@
 
 TEST_F(WorkletAnimationTest, CurrentTimeCorrectlyUsesScrollTimeline) {
   auto scroll_timeline = std::make_unique<MockScrollTimeline>();
+  EXPECT_CALL(*scroll_timeline, IsActive(_, _)).WillRepeatedly(Return(true));
   EXPECT_CALL(*scroll_timeline, CurrentTime(_, _))
       .WillRepeatedly(Return(
           (base::TimeTicks() + base::TimeDelta::FromMilliseconds(1234))));
@@ -219,27 +221,24 @@
   const double playback_rate_half = 0.5;
   auto scroll_timeline = std::make_unique<MockScrollTimeline>();
 
-  EXPECT_CALL(*scroll_timeline, CurrentTime(_, _))
-      // First UpdateInputState call.
-      .WillOnce(
-          Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(50)))
-      // First UpdateInputState call.
-      .WillOnce(
-          Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(50)))
-      // Second UpdateInputState call.
-      .WillRepeatedly(
-          Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(100)));
-
   scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create(
       worklet_animation_id_, "test_name", playback_rate_double,
       std::move(scroll_timeline), nullptr);
+  const MockScrollTimeline* mock_timeline =
+      static_cast<const MockScrollTimeline*>(
+          worklet_animation->scroll_timeline());
 
   ScrollTree scroll_tree;
   std::unique_ptr<MutatorInputState> state =
       std::make_unique<MutatorInputState>();
   // Start the animation.
+  EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(true));
+  EXPECT_CALL(*mock_timeline, CurrentTime(_, _))
+      .WillRepeatedly(
+          Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(50)));
   worklet_animation->UpdateInputState(state.get(), base::TimeTicks(),
                                       scroll_tree, true);
+  Mock::VerifyAndClearExpectations(&mock_timeline);
   std::unique_ptr<AnimationWorkletInput> input =
       state->TakeWorkletState(worklet_animation_id_.worklet_id);
 
@@ -253,8 +252,13 @@
   state.reset(new MutatorInputState());
 
   // Continue playing the animation.
+  EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(true));
+  EXPECT_CALL(*mock_timeline, CurrentTime(_, _))
+      .WillRepeatedly(
+          Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(100)));
   worklet_animation->UpdateInputState(state.get(), base::TimeTicks(),
                                       scroll_tree, true);
+  Mock::VerifyAndClearExpectations(&mock_timeline);
   input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
 
   // Verify that the current time is updated half as fast as the timeline time.
@@ -262,6 +266,59 @@
             input->updated_animations[0].current_time);
 }
 
+// Verifies correcteness of worklet animation current time when inactive
+// timeline becomes active and then inactive again.
+TEST_F(WorkletAnimationTest, InactiveScrollTimeline) {
+  auto scroll_timeline = std::make_unique<MockScrollTimeline>();
+
+  scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create(
+      worklet_animation_id_, "test_name", /*playback_rate*/ 1,
+      std::move(scroll_timeline), nullptr);
+
+  const MockScrollTimeline* mock_timeline =
+      static_cast<const MockScrollTimeline*>(
+          worklet_animation->scroll_timeline());
+  ScrollTree scroll_tree;
+  std::unique_ptr<MutatorInputState> state =
+      std::make_unique<MutatorInputState>();
+
+  // Start the animation with inactive timeline.
+  EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(false));
+  worklet_animation->UpdateInputState(state.get(), base::TimeTicks(),
+                                      scroll_tree, true);
+  Mock::VerifyAndClearExpectations(&mock_timeline);
+  std::unique_ptr<AnimationWorkletInput> input =
+      state->TakeWorkletState(worklet_animation_id_.worklet_id);
+  EXPECT_FALSE(input);
+  state.reset(new MutatorInputState());
+
+  // Now the timeline is active.
+  EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(true));
+  EXPECT_CALL(*mock_timeline, CurrentTime(_, _))
+      .WillRepeatedly(
+          Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(100)));
+  worklet_animation->UpdateInputState(state.get(), base::TimeTicks(),
+                                      scroll_tree, true);
+  Mock::VerifyAndClearExpectations(&mock_timeline);
+  input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
+  // Verify that the current time is updated when the timeline becomes newly
+  // active.
+  EXPECT_EQ(100, input->added_and_updated_animations[0].current_time);
+  state.reset(new MutatorInputState());
+
+  // Now the timeline is inactive.
+  EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(*mock_timeline, CurrentTime(_, _))
+      .WillRepeatedly(
+          Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(200)));
+  worklet_animation->UpdateInputState(state.get(), base::TimeTicks(),
+                                      scroll_tree, true);
+  Mock::VerifyAndClearExpectations(&mock_timeline);
+  input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
+  // No update of the input state when the timeline is inactive.
+  EXPECT_FALSE(input);
+}
+
 // This test verifies that worklet animation state is properly updated.
 TEST_F(WorkletAnimationTest, UpdateInputStateProducesCorrectState) {
   AttachWorkletAnimation();
diff --git a/cc/input/event_listener_properties.h b/cc/input/event_listener_properties.h
index a66ee2e6..f8891fe 100644
--- a/cc/input/event_listener_properties.h
+++ b/cc/input/event_listener_properties.h
@@ -8,8 +8,8 @@
 namespace cc {
 
 enum class EventListenerClass {
-  // This includes the pointerrawmove events which are non-rAF-aligned.
-  kPointerRawMove,
+  // This includes the pointerrawupdate events which are non-rAF-aligned.
+  kPointerRawUpdate,
   // This value includes "touchstart", "touchmove", and "pointer" events.
   kTouchStartOrMove,
   // This value includes "wheel" and "mousewheel" events.
diff --git a/cc/input/scrollbar_controller.cc b/cc/input/scrollbar_controller.cc
index 403d3cea..6bfeff2 100644
--- a/cc/input/scrollbar_controller.cc
+++ b/cc/input/scrollbar_controller.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "cc/base/math_util.h"
 #include "cc/input/scrollbar.h"
 #include "cc/input/scrollbar_controller.h"
 #include "cc/trees/layer_tree_impl.h"
@@ -65,8 +66,23 @@
       static_cast<const ScrollbarLayerImplBase*>(scrollbar_layer_impl);
   const ScrollbarOrientation orientation = scrollbar_layer->orientation();
 
-  ScrollbarPart scrollbar_part =
-      scrollbar_layer->IdentifyScrollbarPart(position_in_widget);
+  // position_in_widget needs to be transformed and made relative to the
+  // scrollbar layer because hit testing assumes layer relative coordinates.
+  ScrollbarPart scrollbar_part = ScrollbarPart::NO_PART;
+  gfx::Transform inverse_screen_space_transform(
+      gfx::Transform::kSkipInitialization);
+  if (scrollbar_layer_impl->ScreenSpaceTransform().GetInverse(
+          &inverse_screen_space_transform)) {
+    bool clipped;
+    gfx::PointF scroller_relative_position(MathUtil::ProjectPoint(
+        inverse_screen_space_transform, position_in_widget, &clipped));
+
+    if (clipped)
+      return gfx::ScrollOffset(0, 0);
+
+    scrollbar_part =
+        scrollbar_layer->IdentifyScrollbarPart(scroller_relative_position);
+  }
 
   float scroll_delta =
       layer_tree_host_impl_->active_tree()->device_scale_factor() *
diff --git a/cc/layers/painted_overlay_scrollbar_layer.cc b/cc/layers/painted_overlay_scrollbar_layer.cc
index ca94e661..e6fcf5f 100644
--- a/cc/layers/painted_overlay_scrollbar_layer.cc
+++ b/cc/layers/painted_overlay_scrollbar_layer.cc
@@ -73,10 +73,10 @@
   scrollbar_layer->SetThumbThickness(thumb_thickness_);
   scrollbar_layer->SetThumbLength(thumb_length_);
   if (scrollbar_->Orientation() == HORIZONTAL) {
-    scrollbar_layer->SetTrackStart(track_rect_.x() - location_.x());
+    scrollbar_layer->SetTrackStart(track_rect_.x());
     scrollbar_layer->SetTrackLength(track_rect_.width());
   } else {
-    scrollbar_layer->SetTrackStart(track_rect_.y() - location_.y());
+    scrollbar_layer->SetTrackStart(track_rect_.y());
     scrollbar_layer->SetTrackLength(track_rect_.height());
   }
 
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc
index ddf202b0..deda561 100644
--- a/cc/layers/painted_scrollbar_layer.cc
+++ b/cc/layers/painted_scrollbar_layer.cc
@@ -74,12 +74,10 @@
   scrollbar_layer->SetForwardButtonRect(forward_button_rect_);
   scrollbar_layer->SetThumbLength(thumb_length_);
   if (scrollbar_->Orientation() == HORIZONTAL) {
-    scrollbar_layer->SetTrackStart(
-        track_rect_.x() - location_.x());
+    scrollbar_layer->SetTrackStart(track_rect_.x());
     scrollbar_layer->SetTrackLength(track_rect_.width());
   } else {
-    scrollbar_layer->SetTrackStart(
-        track_rect_.y() - location_.y());
+    scrollbar_layer->SetTrackStart(track_rect_.y());
     scrollbar_layer->SetTrackLength(track_rect_.height());
   }
 
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index d4b4a4b..3320d74 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -414,10 +414,13 @@
   root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0));
   scrollbar_layer->SetBounds(gfx::Size(70, 10));
   scrollbar_layer->SetScrollElementId(root_layer->element_id());
+
+  // The track_rect should be relative to the scrollbar's origin.
   scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
-  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(10, 10, 50, 10));
   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
   scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
+
   LayerImpl* root_layer_impl = nullptr;
   PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
 
@@ -452,10 +455,13 @@
   root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0));
   scrollbar_layer->SetBounds(gfx::Size(70, 10));
   scrollbar_layer->SetScrollElementId(root_layer->element_id());
+
+  // The track_rect should be relative to the scrollbar's origin.
   scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
-  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(10, 10, 50, 10));
   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
   scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
+
   layer_tree_host_->UpdateLayers();
   LayerImpl* root_layer_impl = nullptr;
   PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
@@ -493,7 +499,7 @@
   // Shrink the scrollbar layer to cover only the track.
   scrollbar_layer->SetBounds(gfx::Size(50, 10));
   scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10));
-  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 10, 50, 10));
 
   UPDATE_AND_EXTRACT_LAYER_POINTERS();
   EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
@@ -502,7 +508,7 @@
   // Shrink the track in the non-scrolling dimension so that it only covers the
   // middle third of the scrollbar layer (this does not affect the thumb
   // position).
-  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6));
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 12, 50, 6));
 
   UPDATE_AND_EXTRACT_LAYER_POINTERS();
   EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index 22d86d8..d3256886 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -1219,6 +1219,7 @@
     DCHECK(IsScaleAdjustmentIdentity(op->scale_adjustment));
     SkAutoCanvasRestore save_restore(canvas, true);
     canvas->translate(op->left, op->top);
+    DCHECK(result && result.paint_record());
     result.paint_record()->Playback(canvas, params);
     return;
   }
@@ -1277,6 +1278,7 @@
     canvas->concat(
         SkMatrix::MakeRectToRect(op->src, op->dst, SkMatrix::kFill_ScaleToFit));
     canvas->clipRect(op->src);
+    DCHECK(result && result.paint_record());
     result.paint_record()->Playback(canvas, params);
     return;
   }
diff --git a/cc/tiles/paint_worklet_image_cache.cc b/cc/tiles/paint_worklet_image_cache.cc
index 639bf7d1..478dccc2 100644
--- a/cc/tiles/paint_worklet_image_cache.cc
+++ b/cc/tiles/paint_worklet_image_cache.cc
@@ -74,6 +74,8 @@
   // matches the PaintGeneratedImage::Draw.
   sk_sp<PaintRecord> record =
       painter_->Paint(paint_image.paint_worklet_input());
+  if (!record)
+    return;
   {
     base::AutoLock hold(records_lock_);
     // It is possible for two or more threads to both pass through the first
diff --git a/cc/trees/effect_node.cc b/cc/trees/effect_node.cc
index acf8f94..887756c 100644
--- a/cc/trees/effect_node.cc
+++ b/cc/trees/effect_node.cc
@@ -140,6 +140,9 @@
   value->SetDouble("opacity", opacity);
   value->SetDouble("backdrop_filter_quality", backdrop_filter_quality);
   value->SetBoolean("is_fast_rounded_corner", is_fast_rounded_corner);
+  if (is_fast_rounded_corner)
+    MathUtil::AddToTracedValue("rounded_corner_bounds", rounded_corner_bounds,
+                               value);
   value->SetString("blend_mode", SkBlendMode_Name(blend_mode));
   value->SetBoolean("cache_render_surface", cache_render_surface);
   value->SetBoolean("has_copy_request", has_copy_request);
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index a20f4d1..f4526fa 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -70,6 +70,7 @@
   "javatests/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityClientTest.java",
   "javatests/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPermissionsTest.java",
+  "javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPreferencesUiTest.java",
   "javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/compositor/CompositorVisibilityTest.java",
   "javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBaseTest.java",
@@ -385,6 +386,7 @@
   "javatests/src/org/chromium/chrome/browser/preferences/website/ManageSpaceActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/website/PermissionInfoTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java",
+  "javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsTestUtils.java",
   "javatests/src/org/chromium/chrome/browser/preferences/website/WebsiteAddressTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcherTest.java",
   "javatests/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandlerTest.java",
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
index 6e97197..39580529 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.vr;
 
+import org.chromium.base.BundleUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
@@ -44,6 +45,7 @@
      */
     public static void maybeRequestModuleIfDaydreamReady() {
         if (!VrBuildConfig.IS_VR_ENABLED) return;
+        if (!BundleUtils.isBundle()) return;
         if (VrModule.isInstalled()) return;
         if (!getDelegate().isDaydreamReadyDevice()) return;
 
diff --git a/chrome/android/java/res/layout/textbubble_text.xml b/chrome/android/java/res/layout/textbubble_text.xml
index 03a482a9..f9d77d6 100644
--- a/chrome/android/java/res/layout/textbubble_text.xml
+++ b/chrome/android/java/res/layout/textbubble_text.xml
@@ -8,4 +8,4 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:padding="16dp"
-    android:textAppearance="@style/TextAppearance.WhiteTitle2" />
+    android:textAppearance="@style/TextAppearance.Title2.Inverse" />
diff --git a/chrome/android/java/res/layout/textbubble_text_with_image.xml b/chrome/android/java/res/layout/textbubble_text_with_image.xml
index 130f508..91ee899 100644
--- a/chrome/android/java/res/layout/textbubble_text_with_image.xml
+++ b/chrome/android/java/res/layout/textbubble_text_with_image.xml
@@ -23,12 +23,12 @@
         android:layout_marginEnd="12dp"
         tools:ignore="ContentDescription"
         android:scaleType="centerInside"
-        app:tint="@color/white_mode_tint" />
+        app:tint="@color/default_icon_color_inverse" />
 
     <TextView
         android:id="@+id/message"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textAppearance="@style/TextAppearance.WhiteTitle2" />
+        android:textAppearance="@style/TextAppearance.Title2.Inverse" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/update_permissions_dialog.xml b/chrome/android/java/res/layout/update_permissions_dialog.xml
index 929e000..f75fc48 100644
--- a/chrome/android/java/res/layout/update_permissions_dialog.xml
+++ b/chrome/android/java/res/layout/update_permissions_dialog.xml
@@ -3,24 +3,28 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file.
 -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:gravity="start"
-    style="@style/AlertDialogContent" >
-    <ImageView
+    style="@style/AlertDialogContent">
+
+    <org.chromium.ui.widget.ChromeImageView
         android:id="@+id/icon"
         android:layout_width="32dp"
         android:layout_height="32dp"
         android:layout_marginTop="10dp"
         android:src="@drawable/exclamation_triangle"
-        tools:ignore="ContentDescription" />
-    <TextView
+        tools:ignore="ContentDescription"
+        app:tint="@color/default_icon_color" />
+
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/text"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:textSize="18sp"
+        android:textAppearance="@style/TextAppearance.BlackTitle1"
         android:paddingTop="0dp"
         android:layout_marginTop="10dp"
-        android:layout_marginStart="48dp" />
+        android:layout_marginStart="48dp"
+        app:leading="@dimen/text_size_large_leading" />
 </FrameLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 901d479c..fee00a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1381,7 +1381,9 @@
                         boolean loaded = false;
                         if (matchingTabIndex != TabModel.INVALID_TAB_INDEX) {
                             Tab tab = tabModel.getTabAt(matchingTabIndex);
-                            if (tab.getUrl().equals(url)) {
+                            if (tab.getUrl().equals(url)
+                                    || tab.getUrl().equals(IntentUtils.safeGetStringExtra(
+                                            intent, TabOpenType.REUSE_TAB_ORIGINAL_URL_STRING))) {
                                 tabModel.setIndex(matchingTabIndex, TabSelectionType.FROM_USER);
                                 LoadUrlParams loadUrlParams =
                                         ChromeTabbedActivity.createLoadUrlParamsForIntent(url,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index 50003bbc..6b9d6ed0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -303,12 +303,16 @@
         // Opens a new incognito tab.
         int OPEN_NEW_INCOGNITO_TAB = 5;
         // Tab is reused only if the tab ID exists (tab ID is specified with the integer extra
-        // REUSE_TAB_MATCHING_ID_STRING), and if the tab matches the requested URL.
-        // Otherwise, the URL is opened in a new tab.
+        // REUSE_TAB_MATCHING_ID_STRING), and if the tab matches either the requested URL, or
+        // the URL provided in the REUSE_TAB_ORIGINAL_URL_STRING extra.
+        // Otherwise, the URL is opened in a new tab. REUSE_TAB_ORIGINAL_URL_STRING can be used if
+        // the intent url is a result of a redirect, so that a tab pointing at the original URL can
+        // be reused.
         int REUSE_TAB_MATCHING_ID_ELSE_NEW_TAB = 6;
 
         String BRING_TAB_TO_FRONT_STRING = "BRING_TAB_TO_FRONT";
         String REUSE_TAB_MATCHING_ID_STRING = "REUSE_TAB_MATCHING_ID";
+        String REUSE_TAB_ORIGINAL_URL_STRING = "REUSE_TAB_ORIGINAL_URL";
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java
index 903e1c9f..81690e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java
@@ -267,24 +267,25 @@
      * If the notification is tapped, it opens the offline page in Chrome.
      *
      * @param pageTitle     The title of the page. This is displayed on the notification.
-     * @param finalUrl      The requested URL (after any redirection).
+     * @param originalUrl   The requested URL before any redirection.
+     * @param finalUrl      The requested URL after any redirection.
      * @param tabId         ID of the tab where the auto-fetch occurred. This tab is used, if
      *                      available, to open the offline page when the notification is tapped.
      * @param offlineId     The offlineID for the offline page that was just saved.
      */
     @CalledByNative
     private static void showCompleteNotification(
-            String pageTitle, String finalUrl, int tabId, long offlineId) {
+            String pageTitle, String originalUrl, String finalUrl, int tabId, long offlineId) {
         Context context = ContextUtils.getApplicationContext();
         OfflinePageUtils.getLoadUrlParamsForOpeningOfflineVersion(
                 finalUrl, offlineId, LaunchLocation.NOTIFICATION, (params) -> {
                     showCompleteNotificationWithParams(
-                            pageTitle, tabId, offlineId, finalUrl, params);
+                            pageTitle, tabId, offlineId, originalUrl, finalUrl, params);
                 });
     }
 
-    private static void showCompleteNotificationWithParams(
-            String pageTitle, int tabId, long offlineId, String finalUrl, LoadUrlParams params) {
+    private static void showCompleteNotificationWithParams(String pageTitle, int tabId,
+            long offlineId, String originalUrl, String finalUrl, LoadUrlParams params) {
         Context context = ContextUtils.getApplicationContext();
         // Create an intent to handle tapping the notification.
         Intent clickIntent = new Intent(context, CompleteNotificationReceiver.class);
@@ -292,6 +293,7 @@
         // the page load. This will result in opening a new tab if there was a redirect (because
         // the URL doesn't match the old dino page), which is not ideal.
         clickIntent.putExtra(EXTRA_URL, finalUrl);
+        clickIntent.putExtra(TabOpenType.REUSE_TAB_ORIGINAL_URL_STRING, originalUrl);
         IntentHandler.setIntentExtraHeaders(params.getExtraHeaders(), clickIntent);
         clickIntent.putExtra(TabOpenType.REUSE_TAB_MATCHING_ID_STRING, tabId);
         clickIntent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ProvidedByWebApkSplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ProvidedByWebApkSplashDelegate.java
index 507a32a..073a58b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ProvidedByWebApkSplashDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ProvidedByWebApkSplashDelegate.java
@@ -8,7 +8,6 @@
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.ImageView;
 
 import org.chromium.base.ApiCompatibilityUtils;
@@ -22,19 +21,14 @@
 
 /** Delegate which uses splash screen screenshot from the WebAPK's content provider. */
 public class ProvidedByWebApkSplashDelegate implements SplashDelegate {
-    private ViewGroup mParentView;
-    private ImageView mSplashView;
-
     @Override
-    public void showSplash(ViewGroup parentView, WebappInfo webappInfo) {
-        mParentView = parentView;
-
+    public View buildSplashView(WebappInfo webappInfo) {
         Context appContext = ContextUtils.getApplicationContext();
-        mSplashView = new ImageView(appContext);
+        ImageView splashView = new ImageView(appContext);
         int backgroundColor =
                 ColorUtils.getOpaqueColor(webappInfo.backgroundColor(ApiCompatibilityUtils.getColor(
                         appContext.getResources(), R.color.webapp_default_bg)));
-        mSplashView.setBackgroundColor(backgroundColor);
+        splashView.setBackgroundColor(backgroundColor);
 
         Bitmap splashBitmap = null;
         try (StrictModeContext smc = StrictModeContext.allowDiskReads()) {
@@ -43,29 +37,19 @@
                             webappInfo.webApkPackageName())));
         }
         if (splashBitmap != null) {
-            mSplashView.setScaleType(ImageView.ScaleType.FIT_CENTER);
-            mSplashView.setImageBitmap(splashBitmap);
+            splashView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+            splashView.setImageBitmap(splashBitmap);
         }
 
-        parentView.addView(mSplashView);
+        return splashView;
     }
 
     @Override
-    public void hideSplash(Tab tab, Runnable finishedHidingCallback) {
+    public void onSplashHidden(Tab tab) {
         // TODO(pkotwicz) implement.
     }
 
     @Override
-    public boolean isSplashVisible() {
-        return true;
-    }
-
-    @Override
-    public View getSplashViewIfChildOf(ViewGroup parent) {
-        return (mParentView == parent) ? mSplashView : null;
-    }
-
-    @Override
     public boolean shouldWaitForSubsequentPageLoadToHideSplash() {
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameActivityWebappSplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameActivityWebappSplashDelegate.java
index 5c6b49c..197d832 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameActivityWebappSplashDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameActivityWebappSplashDelegate.java
@@ -11,12 +11,10 @@
 import android.util.DisplayMetrics;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
-import org.chromium.base.TraceEvent;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
@@ -35,14 +33,6 @@
     private ActivityLifecycleDispatcher mLifecycleDispatcher;
     private TabObserverRegistrar mTabObserverRegistrar;
 
-    /** View to which the splash screen is added. */
-    private ViewGroup mParentView;
-
-    private ViewGroup mSplashScreen;
-
-    /** Whether the splash screen is visible and not in the process of hiding. */
-    private boolean mIsSplashVisible;
-
     /** Whether native was loaded. Native must be loaded in order to record metrics. */
     private boolean mNativeLoaded;
 
@@ -52,31 +42,6 @@
 
     private WebApkSplashNetworkErrorObserver mWebApkNetworkErrorObserver;
 
-    private static class SingleShotOnDrawListener implements ViewTreeObserver.OnDrawListener {
-        private final View mView;
-        private final Runnable mAction;
-        private boolean mHasRun;
-
-        public static void install(View view, Runnable action) {
-            SingleShotOnDrawListener listener = new SingleShotOnDrawListener(view, action);
-            view.getViewTreeObserver().addOnDrawListener(listener);
-        }
-
-        private SingleShotOnDrawListener(View view, Runnable action) {
-            mView = view;
-            mAction = action;
-        }
-
-        @Override
-        public void onDraw() {
-            if (mHasRun) return;
-            mHasRun = true;
-            mAction.run();
-            // Cannot call removeOnDrawListener within OnDraw, so do on next tick.
-            mView.post(() -> mView.getViewTreeObserver().removeOnDrawListener(this));
-        }
-    };
-
     public SameActivityWebappSplashDelegate(Activity activity,
             ActivityLifecycleDispatcher lifecycleDispatcher,
             TabObserverRegistrar tabObserverRegistrar) {
@@ -88,10 +53,8 @@
     }
 
     @Override
-    public void showSplash(ViewGroup parentView, WebappInfo webappInfo) {
-        mParentView = parentView;
+    public View buildSplashView(WebappInfo webappInfo) {
         mWebappInfo = webappInfo;
-        mIsSplashVisible = true;
 
         if (mWebappInfo.isForWebApk()) {
             mWebApkNetworkErrorObserver =
@@ -103,29 +66,29 @@
         final int backgroundColor = ColorUtils.getOpaqueColor(webappInfo.backgroundColor(
                 ApiCompatibilityUtils.getColor(context.getResources(), R.color.webapp_default_bg)));
 
-        mSplashScreen = new FrameLayout(context);
-        mSplashScreen.setBackgroundColor(backgroundColor);
-        mParentView.addView(mSplashScreen);
-        recordTraceEventsShowedSplash();
+        ViewGroup splashScreen = new FrameLayout(context);
+        splashScreen.setBackgroundColor(backgroundColor);
 
         if (webappInfo.isForWebApk()) {
-            initializeLayout(webappInfo, backgroundColor, ((WebApkInfo) webappInfo).splashIcon());
-            return;
+            initializeLayout(webappInfo, splashScreen, backgroundColor,
+                    ((WebApkInfo) webappInfo).splashIcon());
+            return splashScreen;
         }
 
         WebappDataStorage storage =
                 WebappRegistry.getInstance().getWebappDataStorage(webappInfo.id());
         if (storage == null) {
-            initializeLayout(webappInfo, backgroundColor, null);
-            return;
+            initializeLayout(webappInfo, splashScreen, backgroundColor, null);
+            return splashScreen;
         }
 
         storage.getSplashScreenImage(new WebappDataStorage.FetchCallback<Bitmap>() {
             @Override
             public void onDataRetrieved(Bitmap splashImage) {
-                initializeLayout(webappInfo, backgroundColor, splashImage);
+                initializeLayout(webappInfo, splashScreen, backgroundColor, splashImage);
             }
         });
+        return splashScreen;
     }
 
     @Override
@@ -135,38 +98,15 @@
     }
 
     @Override
-    public void hideSplash(Tab tab, final Runnable finishedHidingCallback) {
-        assert mIsSplashVisible;
+    public void onSplashHidden(Tab tab) {
+        if (mWebApkNetworkErrorObserver != null) {
+            mTabObserverRegistrar.unregisterTabObserver(mWebApkNetworkErrorObserver);
+            tab.removeObserver(mWebApkNetworkErrorObserver);
+            mWebApkNetworkErrorObserver = null;
+        }
+        mLifecycleDispatcher.unregister(SameActivityWebappSplashDelegate.this);
 
-        mIsSplashVisible = false;
-        recordTraceEventsStartedHidingSplash();
-        mSplashScreen.animate().alpha(0f).withEndAction(new Runnable() {
-            @Override
-            public void run() {
-                mParentView.removeView(mSplashScreen);
-                if (mWebApkNetworkErrorObserver != null) {
-                    mTabObserverRegistrar.unregisterTabObserver(mWebApkNetworkErrorObserver);
-                    tab.removeObserver(mWebApkNetworkErrorObserver);
-                    mWebApkNetworkErrorObserver = null;
-                }
-                mLifecycleDispatcher.unregister(SameActivityWebappSplashDelegate.this);
-
-                recordTraceEventsFinishedHidingSplash();
-                mActivity = null;
-                mSplashScreen = null;
-                finishedHidingCallback.run();
-            }
-        });
-    }
-
-    @Override
-    public boolean isSplashVisible() {
-        return mIsSplashVisible;
-    }
-
-    @Override
-    public View getSplashViewIfChildOf(ViewGroup parent) {
-        return (mParentView == parent) ? mSplashScreen : null;
+        mActivity = null;
     }
 
     @Override
@@ -176,7 +116,8 @@
     }
 
     /** Sets the splash screen layout and sets the splash screen's title and icon. */
-    private void initializeLayout(WebappInfo webappInfo, int backgroundColor, Bitmap splashImage) {
+    private void initializeLayout(WebappInfo webappInfo, ViewGroup splashScreen,
+            int backgroundColor, Bitmap splashImage) {
         Context context = ContextUtils.getApplicationContext();
         Resources resources = context.getResources();
 
@@ -192,7 +133,7 @@
         int selectedIconClassification = SplashLayout.classifyIcon(
                 context.getResources(), selectedIcon, selectedIconGenerated);
 
-        SplashLayout.createLayout(context, mSplashScreen, selectedIcon, selectedIconAdaptive,
+        SplashLayout.createLayout(context, splashScreen, selectedIcon, selectedIconAdaptive,
                 selectedIconClassification, webappInfo.name(),
                 ColorUtils.shouldUseLightForegroundOnBackground(backgroundColor));
 
@@ -229,19 +170,4 @@
 
         if (mNativeLoaded) mUmaCache.commitMetrics();
     }
-
-    private void recordTraceEventsShowedSplash() {
-        SingleShotOnDrawListener.install(mParentView,
-                () -> { TraceEvent.startAsync("WebappSplashScreen.visible", hashCode()); });
-    }
-
-    private void recordTraceEventsStartedHidingSplash() {
-        TraceEvent.startAsync("WebappSplashScreen.hidingAnimation", hashCode());
-    }
-
-    private void recordTraceEventsFinishedHidingSplash() {
-        TraceEvent.finishAsync("WebappSplashScreen.hidingAnimation", hashCode());
-        SingleShotOnDrawListener.install(mParentView,
-                () -> { TraceEvent.finishAsync("WebappSplashScreen.visible", hashCode()); });
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java
index a8568266..c6052d0e0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java
@@ -8,8 +8,10 @@
 import android.support.annotation.IntDef;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 
 import org.chromium.base.ObserverList;
+import org.chromium.base.TraceEvent;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.WarmupManager;
@@ -23,6 +25,31 @@
 
 /** Shows and hides splash screen. */
 public class SplashController extends EmptyTabObserver {
+    private static class SingleShotOnDrawListener implements ViewTreeObserver.OnDrawListener {
+        private final View mView;
+        private final Runnable mAction;
+        private boolean mHasRun;
+
+        public static void install(View view, Runnable action) {
+            view.getViewTreeObserver().addOnDrawListener(
+                    new SingleShotOnDrawListener(view, action));
+        }
+
+        private SingleShotOnDrawListener(View view, Runnable action) {
+            mView = view;
+            mAction = action;
+        }
+
+        @Override
+        public void onDraw() {
+            if (mHasRun) return;
+            mHasRun = true;
+            mAction.run();
+            // Cannot call removeOnDrawListener within OnDraw, so do on next tick.
+            mView.post(() -> mView.getViewTreeObserver().removeOnDrawListener(this));
+        }
+    };
+
     // SplashHidesReason defined in tools/metrics/histograms/enums.xml.
     @IntDef({SplashHidesReason.PAINT, SplashHidesReason.LOAD_FINISHED,
             SplashHidesReason.LOAD_FAILED, SplashHidesReason.CRASH})
@@ -45,6 +72,11 @@
     /** View to which the splash screen is added. */
     private ViewGroup mParentView;
 
+    private View mSplashView;
+
+    /** Whether the splash hide animation was started. */
+    private boolean mWasSplashHideAnimationStarted;
+
     /** Time that the splash screen was shown. */
     private long mSplashShownTimestamp;
 
@@ -63,7 +95,8 @@
         mParentView = parentView;
         mSplashShownTimestamp = SystemClock.elapsedRealtime();
 
-        mDelegate.showSplash(parentView, webappInfo);
+        mSplashView = mDelegate.buildSplashView(webappInfo);
+        mParentView.addView(mSplashView);
 
         notifySplashscreenVisible(mSplashShownTimestamp);
     }
@@ -73,17 +106,15 @@
      * splashscreen on top.
      */
     public void setViewHierarchyBelowSplashscreen(ViewGroup viewHierarchy) {
-        View splashView = mDelegate.getSplashViewIfChildOf(mParentView);
         WarmupManager.transferViewHeirarchy(viewHierarchy, mParentView);
-        if (splashView != null) {
-            mParentView.bringChildToFront(splashView);
+        if (mSplashView != null) {
+            mParentView.bringChildToFront(mSplashView);
         }
     }
 
     @VisibleForTesting
     View getSplashScreenForTests() {
-        if (mDelegate == null) return null;
-        return mDelegate.getSplashViewIfChildOf(mParentView);
+        return mSplashView;
     }
 
     @Override
@@ -117,24 +148,9 @@
     }
 
     /** Hides the splash screen. */
-    private void hideSplash(Tab tab, final @SplashHidesReason int reason) {
-        if (!mDelegate.isSplashVisible()) return;
-
-        final Runnable onHiddenCallback = new Runnable() {
-            @Override
-            public void run() {
-                mTabObserverRegistrar.unregisterTabObserver(SplashController.this);
-                tab.removeObserver(SplashController.this);
-                mDelegate = null;
-
-                long splashHiddenTimestamp = SystemClock.elapsedRealtime();
-                notifySplashscreenHidden(splashHiddenTimestamp);
-
-                recordSplashHiddenUma(reason, splashHiddenTimestamp);
-            }
-        };
+    private void hideSplash(final Tab tab, final @SplashHidesReason int reason) {
         if (reason == SplashHidesReason.LOAD_FAILED || reason == SplashHidesReason.CRASH) {
-            mDelegate.hideSplash(tab, onHiddenCallback);
+            animateHideSplash(tab, reason);
             return;
         }
         // Delay hiding the splash screen till the compositor has finished drawing the next frame.
@@ -142,10 +158,33 @@
         // the web content (crbug.com/734500).
         CompositorView compositorView =
                 tab.getActivity().getCompositorViewHolder().getCompositorView();
-        compositorView.surfaceRedrawNeededAsync(() -> {
-            if (mDelegate == null || !mDelegate.isSplashVisible()) return;
-            mDelegate.hideSplash(tab, onHiddenCallback);
-        });
+        compositorView.surfaceRedrawNeededAsync(() -> { animateHideSplash(tab, reason); });
+    }
+
+    private void animateHideSplash(final Tab tab, final @SplashHidesReason int reason) {
+        if (mWasSplashHideAnimationStarted) return;
+
+        mWasSplashHideAnimationStarted = true;
+        mTabObserverRegistrar.unregisterTabObserver(this);
+        tab.removeObserver(this);
+
+        recordTraceEventsStartedHidingSplash();
+
+        mSplashView.animate().alpha(0f).withEndAction(() -> { hideSplashNow(tab, reason); });
+    }
+
+    private void hideSplashNow(Tab tab, @SplashHidesReason int reason) {
+        mParentView.removeView(mSplashView);
+
+        long splashHiddenTimestamp = SystemClock.elapsedRealtime();
+        recordTraceEventsFinishedHidingSplash();
+
+        mDelegate.onSplashHidden(tab);
+        recordSplashHiddenUma(reason, splashHiddenTimestamp);
+        notifySplashscreenHidden(splashHiddenTimestamp);
+
+        mDelegate = null;
+        mSplashView = null;
     }
 
     /** Called once the splash screen is hidden to record UMA metrics. */
@@ -184,4 +223,19 @@
         }
         mObservers.clear();
     }
+
+    private void recordTraceEventsShowedSplash() {
+        SingleShotOnDrawListener.install(
+                mParentView, () -> { TraceEvent.startAsync("SplashScreen.visible", hashCode()); });
+    }
+
+    private void recordTraceEventsStartedHidingSplash() {
+        TraceEvent.startAsync("SplashScreen.hidingAnimation", hashCode());
+    }
+
+    private void recordTraceEventsFinishedHidingSplash() {
+        TraceEvent.finishAsync("SplashScreen.hidingAnimation", hashCode());
+        SingleShotOnDrawListener.install(mParentView,
+                () -> { TraceEvent.finishAsync("WebappSplashScreen.visible", hashCode()); });
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java
index fbd9505..8e83782 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java
@@ -5,26 +5,16 @@
 package org.chromium.chrome.browser.webapps;
 
 import android.view.View;
-import android.view.ViewGroup;
 
 import org.chromium.chrome.browser.tab.Tab;
 
 /** Delegate for {@link SplashController}. */
 interface SplashDelegate {
-    /** Shows the splash screen. */
-    void showSplash(ViewGroup parentView, WebappInfo webappInfo);
+    /** Builds the splash view. */
+    View buildSplashView(WebappInfo webappInfo);
 
-    /** Hides the splash screen. Runs the callback once the splash screen is hidden. */
-    void hideSplash(Tab tab, Runnable finishedHidingCallback);
-
-    /** Returns whether the splash screen is visible and not in the process of hiding. */
-    boolean isSplashVisible();
-
-    /**
-     * Returns the {@link View} containing the splash screen if it is a direct child of
-     * the passed-in view.
-     */
-    View getSplashViewIfChildOf(ViewGroup parent);
+    /** Called when splash screen has been hidden. */
+    void onSplashHidden(Tab tab);
 
     /** Returns whether to wait for a subsequent page load to hide the splash screen. */
     boolean shouldWaitForSubsequentPageLoadToHideSplash();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPreferencesUiTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPreferencesUiTest.java
new file mode 100644
index 0000000..e4f2ba8
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPreferencesUiTest.java
@@ -0,0 +1,151 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.browserservices.permissiondelegation;
+
+import android.preference.Preference;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeApplication;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.browserservices.Origin;
+import org.chromium.chrome.browser.preferences.ChromeImageViewPreference;
+import org.chromium.chrome.browser.preferences.ExpandablePreferenceGroup;
+import org.chromium.chrome.browser.preferences.Preferences;
+import org.chromium.chrome.browser.preferences.website.SingleCategoryPreferences;
+import org.chromium.chrome.browser.preferences.website.SingleWebsitePreferences;
+import org.chromium.chrome.browser.preferences.website.SiteSettingsCategory;
+import org.chromium.chrome.browser.preferences.website.SiteSettingsTestUtils;
+import org.chromium.chrome.browser.preferences.website.Website;
+import org.chromium.chrome.browser.preferences.website.WebsiteAddress;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.content_public.browser.test.util.Criteria;
+import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+
+/**
+ * Tests for TrustedWebActivity functionality under Settings > Site Settings.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@RetryOnFailure
+@CommandLineFlags.Add({
+        ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+})
+public class TrustedWebActivityPreferencesUiTest {
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+
+    private String mPackage;
+    private TrustedWebActivityPermissionManager mPermissionMananger;
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+
+        mPackage = InstrumentationRegistry.getTargetContext().getPackageName();
+        mPermissionMananger = ChromeApplication.getComponent().resolveTwaPermissionManager();
+    }
+
+    /**
+     * Tests that the 'Managed by' section appears correctly and that it contains our registered
+     * website.
+     * @throws Exception
+     */
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    public void testSingleCategoryManagedBy() throws Exception {
+        final String site = "http://example.com";
+        final Origin origin = new Origin(site);
+
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> mPermissionMananger.register(origin, mPackage, true));
+
+        Preferences preferenceActivity = SiteSettingsTestUtils.startSiteSettingsCategory(
+                SiteSettingsCategory.Type.NOTIFICATIONS);
+        final String groupName = "managed_group";
+
+        final SingleCategoryPreferences websitePreferences =
+                TestThreadUtils.runOnUiThreadBlocking(() -> {
+                    final SingleCategoryPreferences preferences =
+                            (SingleCategoryPreferences) preferenceActivity.getFragmentForTest();
+                    final ExpandablePreferenceGroup group =
+                            (ExpandablePreferenceGroup) preferences.findPreference(groupName);
+                    preferences.onPreferenceClick(group);
+                    return preferences;
+                });
+
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                // The preference group gets recreated in onPreferenceClick, so we need to find it
+                // again.
+                final ExpandablePreferenceGroup group =
+                        (ExpandablePreferenceGroup) websitePreferences.findPreference(groupName);
+                return group.isExpanded();
+            }
+        });
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            final ExpandablePreferenceGroup group =
+                    (ExpandablePreferenceGroup) websitePreferences.findPreference(groupName);
+            Assert.assertEquals(1, group.getPreferenceCount());
+            Preference preference = group.getPreference(0);
+            CharSequence title = preference.getTitle();
+            Assert.assertEquals("example.com", title.toString());
+        });
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> mPermissionMananger.unregister(origin));
+
+        preferenceActivity.finish();
+    }
+
+    /**
+     * Tests that registered sites show 'Managed by' in the title when viewing the details for a
+     * single website.
+     * @throws Exception
+     */
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    public void testWebsitePreferencesManagedBy() throws Exception {
+        final String site = "http://example.com";
+        final Origin origin = new Origin(site);
+
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> mPermissionMananger.register(origin, mPackage, true));
+
+        WebsiteAddress address = WebsiteAddress.create(site);
+        Website website = new Website(address, address);
+        final Preferences preferenceActivity =
+                SiteSettingsTestUtils.startSingleWebsitePreferences(website);
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            final SingleWebsitePreferences websitePreferences =
+                    (SingleWebsitePreferences) preferenceActivity.getFragmentForTest();
+            final ChromeImageViewPreference notificationPreference =
+                    (ChromeImageViewPreference) websitePreferences.findPreference(
+                            "push_notifications_list");
+            CharSequence summary = notificationPreference.getSummary();
+            Assert.assertTrue(summary.toString().startsWith("Managed by "));
+        });
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> mPermissionMananger.unregister(origin));
+
+        preferenceActivity.finish();
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java
index 8d80915..0b24434d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java
@@ -98,13 +98,18 @@
         }
     }
 
+    private static final String DEFAULT_BODY = "<html><title>MyTestPage</title>Hello World!</html>";
     private void startWebServer() throws Exception {
         Assert.assertTrue(mWebServer == null);
         mWebServer = new WebServer(0, false);
+        useDefaultWebServerResponse();
+    }
+
+    private void useDefaultWebServerResponse() {
+        Assert.assertTrue(mWebServer != null);
         mWebServer.setRequestHandler((HTTPRequest request, OutputStream stream) -> {
             try {
-                WebServer.writeResponse(stream, WebServer.STATUS_OK,
-                        "<html><title>MyTestPage</title>Hello World!</html>".getBytes());
+                WebServer.writeResponse(stream, WebServer.STATUS_OK, DEFAULT_BODY.getBytes());
             } catch (IOException e) {
             }
         });
@@ -112,10 +117,25 @@
 
     private void useAlternateWebServerResponse() {
         Assert.assertTrue(mWebServer != null);
+        String body = "<html><title>A Different Page</title>Alternate page!</html>";
         mWebServer.setRequestHandler((HTTPRequest request, OutputStream stream) -> {
             try {
-                WebServer.writeResponse(stream, WebServer.STATUS_OK,
-                        "<html><title>A Different Page</title>Alternate page!</html>".getBytes());
+                WebServer.writeResponse(stream, WebServer.STATUS_OK, body.getBytes());
+            } catch (IOException e) {
+            }
+        });
+    }
+
+    private void useRedirectWebServerResponse() {
+        Assert.assertTrue(mWebServer != null);
+        String redirectBody =
+                "<html><meta http-equiv=\"refresh\" content=\"0; url=/redirect_target\">"
+                + "<title>RedirectingFromHere</title>redirect</html>";
+        mWebServer.setRequestHandler((HTTPRequest request, OutputStream stream) -> {
+            try {
+                String body =
+                        request.getURI().endsWith("redirect_from") ? redirectBody : DEFAULT_BODY;
+                WebServer.writeResponse(stream, WebServer.STATUS_OK, body.getBytes());
             } catch (IOException e) {
             }
         });
@@ -217,6 +237,54 @@
     @Test
     @MediumTest
     @Feature({"OfflineAutoFetch"})
+    public void testAutoFetchWithRedirect() throws Exception {
+        startWebServer();
+        useRedirectWebServerResponse();
+        final String testUrl = mWebServer.getBaseUrl() + "/redirect_from";
+
+        // Make |testUrl| return an offline error and attempt to load the page.
+        // This should trigger an auto-fetch request.
+        OfflineTestUtil.interceptWithOfflineError(testUrl);
+        attemptLoadPage(testUrl);
+        waitForRequestCount(1);
+
+        // Navigate away from the page, so that the auto-fetch request is allowed to complete,
+        // and go back online.
+        attemptLoadPage(UrlConstants.ABOUT_URL);
+        // The tab no longer has the requested URL active, so the in-progress notification should
+        // appear.
+        waitForInProgressNotification();
+        OfflineTestUtil.clearIntercepts();
+        forceConnectivityState(true);
+        OfflineTestUtil.startRequestCoordinatorProcessing();
+
+        // Wait for the background request to complete.
+        waitForPageAdded();
+        Assert.assertTrue(mAddedPage != null);
+        waitForHistogram("OfflinePages.AutoFetch.CompleteNotificationAction:SHOWN", 1);
+
+        // Navigate back to testUrl, this time there is no redirect.
+        useDefaultWebServerResponse();
+        attemptLoadPage(testUrl);
+
+        // Simulate click on the complete notification, and ensure the offline page loads by
+        // swapping out the live page contents.
+        useAlternateWebServerResponse();
+        sendBroadcast(mLastCompleteClickIntent);
+
+        waitForHistogram("OfflinePages.AutoFetch.CompleteNotificationAction:TAPPED", 1);
+
+        pollInstrumentationThread(() -> {
+            // No new tab is opened, because the URL of the tab matches the original URL.
+            return getCurrentTabModel().getCount() == 1
+                    // The title matches the original page, not the 'AlternativeWebServerResponse'.
+                    && getCurrentTab().getTitle().equals("MyTestPage");
+        });
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"OfflineAutoFetch"})
     public void testSwipeAwayCompleteNotification() throws Exception {
         // Standard setup to trigger auto-fetch.
         startWebServer();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
index b9a2124f..115332d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.preferences.website;
 
-import android.content.Intent;
-import android.os.Bundle;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceScreen;
@@ -32,7 +30,6 @@
 import org.chromium.chrome.browser.preferences.LocationSettings;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.Preferences;
-import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.InfoBarTestAnimationListener;
@@ -74,8 +71,8 @@
 
     private void setAllowLocation(final boolean enabled) {
         LocationSettingsTestUtil.setSystemLocationSettingEnabled(true);
-        final Preferences preferenceActivity =
-                startSiteSettingsCategory(SiteSettingsCategory.Type.DEVICE_LOCATION);
+        final Preferences preferenceActivity = SiteSettingsTestUtils.startSiteSettingsCategory(
+                SiteSettingsCategory.Type.DEVICE_LOCATION);
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SingleCategoryPreferences websitePreferences =
@@ -145,34 +142,6 @@
         Assert.assertTrue(mActivityTestRule.getInfoBars().isEmpty());
     }
 
-    private Preferences startSiteSettingsMenu(String category) {
-        Bundle fragmentArgs = new Bundle();
-        fragmentArgs.putString(SingleCategoryPreferences.EXTRA_CATEGORY, category);
-        Intent intent = PreferencesLauncher.createIntentForSettingsPage(
-                InstrumentationRegistry.getTargetContext(), SiteSettingsPreferences.class.getName(),
-                fragmentArgs);
-        return (Preferences) InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
-    }
-
-    private Preferences startSiteSettingsCategory(@SiteSettingsCategory.Type int type) {
-        Bundle fragmentArgs = new Bundle();
-        fragmentArgs.putString(
-                SingleCategoryPreferences.EXTRA_CATEGORY, SiteSettingsCategory.preferenceKey(type));
-        Intent intent = PreferencesLauncher.createIntentForSettingsPage(
-                InstrumentationRegistry.getTargetContext(),
-                SingleCategoryPreferences.class.getName(), fragmentArgs);
-        return (Preferences) InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
-    }
-
-    private Preferences startSingleWebsitePreferences(Website site) {
-        Bundle fragmentArgs = new Bundle();
-        fragmentArgs.putSerializable(SingleWebsitePreferences.EXTRA_SITE, site);
-        Intent intent = PreferencesLauncher.createIntentForSettingsPage(
-                InstrumentationRegistry.getTargetContext(),
-                SingleWebsitePreferences.class.getName(), fragmentArgs);
-        return (Preferences) InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
-    }
-
     private void setCookiesEnabled(final Preferences preferenceActivity, final boolean enabled) {
         TestThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
@@ -219,7 +188,8 @@
 
     private void setGlobalToggleForCategory(
             final @SiteSettingsCategory.Type int type, final boolean enabled) {
-        final Preferences preferenceActivity = startSiteSettingsCategory(type);
+        final Preferences preferenceActivity =
+                SiteSettingsTestUtils.startSiteSettingsCategory(type);
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SingleCategoryPreferences preferences =
@@ -260,7 +230,8 @@
      */
     private void checkPreferencesForCategory(
             final @SiteSettingsCategory.Type int type, String[] expectedKeys) {
-        final Preferences preferenceActivity = startSiteSettingsCategory(type);
+        final Preferences preferenceActivity =
+                SiteSettingsTestUtils.startSiteSettingsCategory(type);
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             PreferenceFragment preferenceFragment =
@@ -295,7 +266,7 @@
     @Feature({"Preferences"})
     public void testThirdPartyCookieToggleGetsDisabled() throws Exception {
         Preferences preferenceActivity =
-                startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
+                SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
         setCookiesEnabled(preferenceActivity, true);
         setThirdPartyCookiesEnabled(preferenceActivity, false);
         setThirdPartyCookiesEnabled(preferenceActivity, true);
@@ -311,7 +282,7 @@
     @Feature({"Preferences"})
     public void testCookiesNotBlocked() throws Exception {
         Preferences preferenceActivity =
-                startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
+                SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
         setCookiesEnabled(preferenceActivity, true);
         preferenceActivity.finish();
 
@@ -338,7 +309,7 @@
     @Feature({"Preferences"})
     public void testCookiesBlocked() throws Exception {
         Preferences preferenceActivity =
-                startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
+                SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
         setCookiesEnabled(preferenceActivity, false);
         preferenceActivity.finish();
 
@@ -403,7 +374,8 @@
 
     private void resetSite(WebsiteAddress address) {
         Website website = new Website(address, address);
-        final Preferences preferenceActivity = startSingleWebsitePreferences(website);
+        final Preferences preferenceActivity =
+                SiteSettingsTestUtils.startSingleWebsitePreferences(website);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SingleWebsitePreferences websitePreferences =
                     (SingleWebsitePreferences) preferenceActivity.getFragmentForTest();
@@ -454,7 +426,7 @@
     @SmallTest
     @Feature({"Preferences"})
     public void testSiteSettingsMenu() throws Exception {
-        final Preferences preferenceActivity = startSiteSettingsMenu("");
+        final Preferences preferenceActivity = SiteSettingsTestUtils.startSiteSettingsMenu("");
         preferenceActivity.finish();
     }
 
@@ -467,7 +439,7 @@
     @Feature({"Preferences"})
     public void testMediaMenu() throws Exception {
         final Preferences preferenceActivity =
-                startSiteSettingsMenu(SiteSettingsPreferences.MEDIA_KEY);
+                SiteSettingsTestUtils.startSiteSettingsMenu(SiteSettingsPreferences.MEDIA_KEY);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SiteSettingsPreferences siteSettings =
                     (SiteSettingsPreferences) preferenceActivity.getFragmentForTest();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsTestUtils.java
new file mode 100644
index 0000000..911df4c
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsTestUtils.java
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.preferences.website;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+
+import org.chromium.chrome.browser.preferences.Preferences;
+import org.chromium.chrome.browser.preferences.PreferencesLauncher;
+
+/**
+ * Util functions for testing SiteSettings functionality.
+ */
+public class SiteSettingsTestUtils {
+    public static Preferences startSiteSettingsMenu(String category) {
+        Bundle fragmentArgs = new Bundle();
+        fragmentArgs.putString(SingleCategoryPreferences.EXTRA_CATEGORY, category);
+        Intent intent = PreferencesLauncher.createIntentForSettingsPage(
+                InstrumentationRegistry.getTargetContext(), SiteSettingsPreferences.class.getName(),
+                fragmentArgs);
+        return (Preferences) InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+    }
+
+    public static Preferences startSiteSettingsCategory(@SiteSettingsCategory.Type int type) {
+        Bundle fragmentArgs = new Bundle();
+        fragmentArgs.putString(
+                SingleCategoryPreferences.EXTRA_CATEGORY, SiteSettingsCategory.preferenceKey(type));
+        Intent intent = PreferencesLauncher.createIntentForSettingsPage(
+                InstrumentationRegistry.getTargetContext(),
+                SingleCategoryPreferences.class.getName(), fragmentArgs);
+        return (Preferences) InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+    }
+
+    public static Preferences startSingleWebsitePreferences(Website site) {
+        Bundle fragmentArgs = new Bundle();
+        fragmentArgs.putSerializable(SingleWebsitePreferences.EXTRA_SITE, site);
+        Intent intent = PreferencesLauncher.createIntentForSettingsPage(
+                InstrumentationRegistry.getTargetContext(),
+                SingleWebsitePreferences.class.getName(), fragmentArgs);
+        return (Preferences) InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java
index a620ef6..d31e4e6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java
@@ -48,7 +48,7 @@
 @UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=LogJsConsoleMessages", "enable-webvr"})
-@MinAndroidSdkLevel(Build.VERSION_CODES.KITKAT) // WebVR is only supported on K+
+@MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP) // WebVR is only supported on L+
 public class WebXrVrDeviceTest {
     @ClassParameter
     private static List<ParameterSet> sClassParams =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
index 0d068ce..6da5b9c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
@@ -65,7 +65,7 @@
 @UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=LogJsConsoleMessages", "enable-webvr"})
-@MinAndroidSdkLevel(Build.VERSION_CODES.KITKAT) // WebVR and WebXR are only supported on K+
+@MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP) // WebVR and WebXR are only supported on L+
 public class WebXrVrInputTest {
     @ClassParameter
     private static List<ParameterSet> sClassParams =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
index 69aab7d..cdd01eb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
@@ -69,7 +69,7 @@
 @UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=LogJsConsoleMessages", "enable-webvr"})
-@MinAndroidSdkLevel(Build.VERSION_CODES.KITKAT) // WebVR and WebXR are only supported on K+
+@MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP) // WebVR and WebXR are only supported on L+
 @TargetApi(Build.VERSION_CODES.KITKAT) // Necessary to allow taking screenshots with UiAutomation
 public class WebXrVrTransitionTest {
     @ClassParameter
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index ec6e0500..e6f97cd0 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -466,7 +466,6 @@
       "//chromeos/services/multidevice_setup/public/mojom",
       "//chromeos/services/network_config/public/mojom",
       "//media/capture/video/chromeos/mojo:cros_camera",
-      "//ui/accessibility/mojom",
     ]
 
     if (enable_cros_assistant) {
@@ -626,7 +625,6 @@
       "//chromeos/services/network_config/public/cpp:manifest",
       "//chromeos/services/secure_channel/public/cpp:manifest",
       "//services/ws/public/mojom/input_devices",
-      "//ui/accessibility:ax_host_manifest",
     ]
   }
 
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index fd835ed5..215115b 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -60,7 +60,6 @@
 #include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
 #include "services/ws/common/switches.h"
 #include "services/ws/public/mojom/constants.mojom.h"
-#include "ui/accessibility/mojom/ax_host.mojom.h"  // nogncheck
 #if BUILDFLAG(ENABLE_CROS_ASSISTANT)
 #include "chromeos/services/assistant/public/cpp/manifest.h"  // nogncheck
 #endif
@@ -119,11 +118,6 @@
             .ExposeCapability("gpu",
                               service_manager::Manifest::InterfaceList<
                                   metrics::mojom::CallStackProfileCollector>())
-#if defined(OS_CHROMEOS)
-            .ExposeCapability(
-                "app",
-                service_manager::Manifest::InterfaceList<ax::mojom::AXHost>())
-#endif
             .ExposeCapability("profiling_client",
                               service_manager::Manifest::InterfaceList<
                                   heap_profiling::mojom::ProfilingClient>())
diff --git a/chrome/app/chrome_packaged_service_manifests.cc b/chrome/app/chrome_packaged_service_manifests.cc
index 00c14934..1ef15dc 100644
--- a/chrome/app/chrome_packaged_service_manifests.cc
+++ b/chrome/app/chrome_packaged_service_manifests.cc
@@ -31,7 +31,6 @@
 #include "chromeos/services/network_config/public/cpp/manifest.h"
 #include "chromeos/services/secure_channel/public/cpp/manifest.h"
 #include "services/ws/public/mojom/input_devices/input_device_controller.mojom.h"
-#include "ui/accessibility/ax_host_manifest.h"  // nogncheck
 #endif
 
 #if defined(OS_MACOSX)
@@ -174,7 +173,6 @@
       chromeos::ime::GetManifest(),
       chromeos::network_config::GetManifest(),
       chromeos::secure_channel::GetManifest(),
-      ui::GetAXHostManifest(),
 #endif
   }};
   return *manifests;
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 74a54e4..b22bdc0 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2786,12 +2786,6 @@
      flag_descriptions::kEnablePixelCanvasRecordingDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kEnablePixelCanvasRecording)},
 
-#if defined(OS_CHROMEOS)
-    {"disable-tablet-splitview", flag_descriptions::kDisableTabletSplitViewName,
-     flag_descriptions::kDisableTabletSplitViewDescription, kOsCrOS,
-     SINGLE_VALUE_TYPE(ash::switches::kAshDisableTabletSplitView)},
-#endif  // defined(OS_CHROMEOS)
-
     {"enable-parallel-downloading", flag_descriptions::kParallelDownloadingName,
      flag_descriptions::kParallelDownloadingDescription, kOsAll,
      FEATURE_VALUE_TYPE(download::features::kParallelDownloading)},
@@ -3890,6 +3884,11 @@
      flag_descriptions::kAutofillPruneSuggestionsDescription, kOsAll,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillPruneSuggestions)},
 
+    {"allow-popups-during-page-unload",
+     flag_descriptions::kAllowPopupsDuringPageUnloadName,
+     flag_descriptions::kAllowPopupsDuringPageUnloadDescription, kOsAll,
+     SINGLE_VALUE_TYPE(switches::kAllowPopupsDuringPageUnload)},
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h b/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h
index 5d1d8f2..8acf9c03 100644
--- a/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h
+++ b/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h
@@ -10,12 +10,12 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "net/base/linked_hash_map.h"
+#include "net/third_party/quiche/src/common/simple_linked_hash_map.h"
 
 template <class Key, class Value>
 class ScopedPtrExpiringCache {
  private:
-  typedef net::linked_hash_map<Key, Value*> LinkedHashMap;
+  typedef quiche::SimpleLinkedHashMap<Key, Value*> LinkedHashMap;
 
  public:
   typedef typename LinkedHashMap::iterator iterator;
diff --git a/chrome/browser/ash_service_registry.cc b/chrome/browser/ash_service_registry.cc
index 4162d00..8faaa127 100644
--- a/chrome/browser/ash_service_registry.cc
+++ b/chrome/browser/ash_service_registry.cc
@@ -13,7 +13,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "chrome/browser/chromeos/accessibility/ax_host_service.h"
 #include "chrome/browser/chromeos/prefs/pref_connector_service.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/common/service_manager_connection.h"
@@ -69,8 +68,6 @@
   }
   if (service_name == ash::mojom::kPrefConnectorServiceName)
     return std::make_unique<AshPrefConnector>(std::move(request));
-  if (service_name == ax::mojom::kAXHostServiceName)
-    return std::make_unique<AXHostService>(std::move(request));
 
   return nullptr;
 }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index c6253baf..53e92dc 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
+import("//chrome/browser/chromeos/kiosk_next_home/kiosk_next.gni")
 import("//extensions/buildflags/buildflags.gni")
 import("//media/media_options.gni")
 import("//printing/buildflags/buildflags.gni")
@@ -73,8 +74,8 @@
     "//chrome/services/app_service:lib",
     "//chrome/services/app_service/public/cpp:app_service_proxy",
     "//chrome/services/app_service/public/cpp:app_update",
-    "//chrome/services/diagnosticsd/public/mojom",
     "//chrome/services/file_util/public/cpp",
+    "//chrome/services/wilco_dtc_supportd/public/mojom",
     "//chromeos",
     "//chromeos/assistant:buildflags",
     "//chromeos/attestation",
@@ -300,10 +301,6 @@
     "accessibility/accessibility_manager.h",
     "accessibility/accessibility_panel.cc",
     "accessibility/accessibility_panel.h",
-    "accessibility/ax_host_service.cc",
-    "accessibility/ax_host_service.h",
-    "accessibility/ax_remote_host_delegate.cc",
-    "accessibility/ax_remote_host_delegate.h",
     "accessibility/chromevox_panel.cc",
     "accessibility/chromevox_panel.h",
     "accessibility/dictation_chromeos.cc",
@@ -685,8 +682,6 @@
     "child_accounts/parent_access_code/config_source.h",
     "child_accounts/parent_access_code/parent_access_service.cc",
     "child_accounts/parent_access_code/parent_access_service.h",
-    "child_accounts/parent_access_code/policy_config_source.cc",
-    "child_accounts/parent_access_code/policy_config_source.h",
     "child_accounts/screen_time_controller.cc",
     "child_accounts/screen_time_controller.h",
     "child_accounts/screen_time_controller_factory.cc",
@@ -782,16 +777,6 @@
     "dbus/vm_applications_service_provider.h",
     "device_sync/device_sync_client_factory.cc",
     "device_sync/device_sync_client_factory.h",
-    "diagnosticsd/diagnosticsd_bridge.cc",
-    "diagnosticsd/diagnosticsd_bridge.h",
-    "diagnosticsd/diagnosticsd_manager.cc",
-    "diagnosticsd/diagnosticsd_manager.h",
-    "diagnosticsd/diagnosticsd_messaging.cc",
-    "diagnosticsd/diagnosticsd_messaging.h",
-    "diagnosticsd/diagnosticsd_web_request_service.cc",
-    "diagnosticsd/diagnosticsd_web_request_service.h",
-    "diagnosticsd/mojo_utils.cc",
-    "diagnosticsd/mojo_utils.h",
     "display/output_protection_controller_ash.cc",
     "display/output_protection_controller_ash.h",
     "display/output_protection_controller_mus.cc",
@@ -2013,6 +1998,16 @@
     "usb/cros_usb_detector.h",
     "virtual_machines/virtual_machines_util.cc",
     "virtual_machines/virtual_machines_util.h",
+    "wilco_dtc_supportd/mojo_utils.cc",
+    "wilco_dtc_supportd/mojo_utils.h",
+    "wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc",
+    "wilco_dtc_supportd/wilco_dtc_supportd_bridge.h",
+    "wilco_dtc_supportd/wilco_dtc_supportd_manager.cc",
+    "wilco_dtc_supportd/wilco_dtc_supportd_manager.h",
+    "wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc",
+    "wilco_dtc_supportd/wilco_dtc_supportd_messaging.h",
+    "wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc",
+    "wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.h",
 
     # Extension API implementations.
     "extensions/autotest_private/autotest_private_api.cc",
@@ -2093,8 +2088,16 @@
     ]
   }
 
+  defines = []
   if (use_cras) {
-    defines = [ "USE_CRAS" ]
+    defines += [ "USE_CRAS" ]
+  }
+  if (enable_kiosk_next) {
+    defines += [ "KIOSK_NEXT" ]
+    if (is_chrome_branded) {
+      public_deps +=
+          [ "//chrome/browser/resources:kiosk_next_internal_resources" ]
+    }
   }
 }
 
@@ -2228,7 +2231,6 @@
     "../policy/default_geolocation_policy_handler_unittest.cc",
     "../resources/chromeos/zip_archiver/test/char_coding_test.cc",
     "../ui/browser_finder_chromeos_unittest.cc",
-    "accessibility/ax_host_service_unittest.cc",
     "accessibility/switch_access_panel_unittest.cc",
     "account_manager/account_migration_runner_unittest.cc",
     "android_sms/android_sms_app_manager_impl_unittest.cc",
@@ -2304,9 +2306,8 @@
     "certificate_provider/certificate_provider_service_unittest.cc",
     "child_accounts/event_based_status_reporting_service_unittest.cc",
     "child_accounts/parent_access_code/authenticator_unittest.cc",
-    "child_accounts/parent_access_code/parent_access_service_unittest.cc",
-    "child_accounts/parent_access_code/test_utils.cc",
-    "child_accounts/parent_access_code/test_utils.h",
+    "child_accounts/parent_access_code/parent_access_test_utils.cc",
+    "child_accounts/parent_access_code/parent_access_test_utils.h",
     "child_accounts/time_limit_notifier_unittest.cc",
     "child_accounts/time_limit_test_utils.cc",
     "child_accounts/usage_time_limit_processor_unittest.cc",
@@ -2320,12 +2321,6 @@
     "cryptauth/client_app_metadata_provider_service_unittest.cc",
     "customization/customization_document_unittest.cc",
     "dbus/proxy_resolution_service_provider_unittest.cc",
-    "diagnosticsd/diagnosticsd_bridge_unittest.cc",
-    "diagnosticsd/diagnosticsd_manager_unittest.cc",
-    "diagnosticsd/diagnosticsd_messaging_unittest.cc",
-    "diagnosticsd/diagnosticsd_web_request_service_unittest.cc",
-    "diagnosticsd/testing_diagnosticsd_bridge_wrapper.cc",
-    "diagnosticsd/testing_diagnosticsd_bridge_wrapper.h",
     "drive/download_handler_unittest.cc",
     "drive/drive_file_stream_reader_unittest.cc",
     "drive/drive_integration_service_unittest.cc",
@@ -2599,6 +2594,12 @@
     "tpm_firmware_update_unittest.cc",
     "ui/idle_app_name_notification_view_unittest.cc",
     "ui/low_disk_notification_unittest.cc",
+    "wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.cc",
+    "wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h",
+    "wilco_dtc_supportd/wilco_dtc_supportd_bridge_unittest.cc",
+    "wilco_dtc_supportd/wilco_dtc_supportd_manager_unittest.cc",
+    "wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc",
+    "wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc",
 
     # TODO(zturner): Enable this on Windows. See
     # BrowserWithTestWindowTest::SetUp() for a comment explaining why this is
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index feded107..5ec2058c 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -5,6 +5,7 @@
   "+chrome/browser/ui/views/chrome_layout_provider.h",
 
   "+chrome/services/app_service/public",
+  "+chrome/services/wilco_dtc_supportd/public",
   "+cros",
   "+dbus",
   "+device/bluetooth",
diff --git a/chrome/browser/chromeos/accessibility/ax_host_service.cc b/chrome/browser/chromeos/accessibility/ax_host_service.cc
deleted file mode 100644
index ac9ebcb..0000000
--- a/chrome/browser/chromeos/accessibility/ax_host_service.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/accessibility/ax_host_service.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/stl_util.h"
-#include "chrome/browser/chromeos/accessibility/ax_remote_host_delegate.h"
-#include "ui/accessibility/ax_tree_id.h"
-
-AXHostService* AXHostService::instance_ = nullptr;
-
-bool AXHostService::automation_enabled_ = false;
-
-AXHostService::AXHostService(service_manager::mojom::ServiceRequest request)
-    : service_binding_(this, std::move(request)) {
-  DCHECK(!instance_);
-  instance_ = this;
-  registry_.AddInterface<ax::mojom::AXHost>(
-      base::BindRepeating(&AXHostService::AddBinding, base::Unretained(this)));
-}
-
-AXHostService::~AXHostService() {
-  DCHECK_EQ(instance_, this);
-  instance_ = nullptr;
-}
-
-// static
-void AXHostService::SetAutomationEnabled(bool enabled) {
-  automation_enabled_ = enabled;
-  if (instance_)
-    instance_->NotifyAutomationEnabled();
-}
-
-void AXHostService::OnBindInterface(
-    const service_manager::BindSourceInfo& remote_info,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  registry_.BindInterface(interface_name, std::move(interface_pipe));
-}
-
-void AXHostService::RegisterRemoteHost(
-    ax::mojom::AXRemoteHostPtr remote_host_ptr,
-    RegisterRemoteHostCallback cb) {
-  // Create the AXRemoteHostDelegate first so a tree ID will be assigned.
-  auto remote_host_delegate =
-      std::make_unique<AXRemoteHostDelegate>(this, std::move(remote_host_ptr));
-  ui::AXTreeID tree_id = remote_host_delegate->ax_tree_id();
-  DCHECK_NE(ui::AXTreeIDUnknown(), tree_id);
-  DCHECK(!base::ContainsKey(remote_host_delegate_map_, tree_id));
-  remote_host_delegate_map_[tree_id] = std::move(remote_host_delegate);
-
-  // Inform the remote process of the tree ID.
-  std::move(cb).Run(tree_id, automation_enabled_);
-}
-
-void AXHostService::HandleAccessibilityEvent(
-    const ui::AXTreeID& tree_id,
-    const std::vector<ui::AXTreeUpdate>& updates,
-    const ui::AXEvent& event) {
-  auto it = remote_host_delegate_map_.find(tree_id);
-  if (it == remote_host_delegate_map_.end())
-    return;
-  AXRemoteHostDelegate* delegate = it->second.get();
-  delegate->HandleAccessibilityEvent(tree_id, updates, event);
-}
-
-void AXHostService::OnRemoteHostDisconnected(const ui::AXTreeID& tree_id) {
-  // AXRemoteHostDelegate notified the extension that the tree was destroyed.
-  // Delete the AXRemoteHostDelegate.
-  remote_host_delegate_map_.erase(tree_id);
-}
-
-void AXHostService::FlushForTesting() {
-  for (const auto& pair : remote_host_delegate_map_) {
-    AXRemoteHostDelegate* delegate = pair.second.get();
-    delegate->FlushForTesting();
-  }
-}
-
-void AXHostService::AddBinding(ax::mojom::AXHostRequest request) {
-  bindings_.AddBinding(this, std::move(request));
-}
-
-void AXHostService::NotifyAutomationEnabled() {
-  for (const auto& pair : remote_host_delegate_map_) {
-    AXRemoteHostDelegate* delegate = pair.second.get();
-    delegate->OnAutomationEnabled(automation_enabled_);
-  }
-}
diff --git a/chrome/browser/chromeos/accessibility/ax_host_service.h b/chrome/browser/chromeos/accessibility/ax_host_service.h
deleted file mode 100644
index 94b7188..0000000
--- a/chrome/browser/chromeos/accessibility/ax_host_service.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_AX_HOST_SERVICE_H_
-#define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_AX_HOST_SERVICE_H_
-
-#include <map>
-#include <memory>
-
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
-#include "ui/accessibility/mojom/ax_host.mojom.h"
-
-class AXRemoteHostDelegate;
-
-// Manages a set of remote processes that use aura and views. Renderers such as
-// web content, PDF, etc. use a different path. Created when the first client
-// connects over mojo.
-class AXHostService : public service_manager::Service,
-                      public ax::mojom::AXHost {
- public:
-  explicit AXHostService(service_manager::mojom::ServiceRequest request);
-  ~AXHostService() override;
-
-  // Requests AX node trees from remote clients and starts listening for remote
-  // AX events. Static because the mojo service_manager creates and owns the
-  // service object, but automation may be enabled before a client connects and
-  // the service starts.
-  static void SetAutomationEnabled(bool enabled);
-
-  // service_manager::Service:
-  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override;
-
-  // ax::mojom::AXHost:
-  void RegisterRemoteHost(ax::mojom::AXRemoteHostPtr remote_host_ptr,
-                          RegisterRemoteHostCallback cb) override;
-  void HandleAccessibilityEvent(const ui::AXTreeID& tree_id,
-                                const std::vector<ui::AXTreeUpdate>& updates,
-                                const ui::AXEvent& event) override;
-
-  // Cleans up after a remote host disconnects.
-  void OnRemoteHostDisconnected(const ui::AXTreeID& tree_id);
-
-  void FlushForTesting();
-
- private:
-  void AddBinding(ax::mojom::AXHostRequest request);
-
-  // Notifies all remote trees of automation enabled state.
-  void NotifyAutomationEnabled();
-
-  static AXHostService* instance_;
-  static bool automation_enabled_;
-
-  service_manager::ServiceBinding service_binding_;
-  service_manager::BinderRegistry registry_;
-  mojo::BindingSet<ax::mojom::AXHost> bindings_;
-
-  // Map from a child tree id to the remote host responsible for that tree.
-  std::map<ui::AXTreeID, std::unique_ptr<AXRemoteHostDelegate>>
-      remote_host_delegate_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(AXHostService);
-};
-
-#endif  // CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_AX_HOST_SERVICE_H_
diff --git a/chrome/browser/chromeos/accessibility/ax_host_service_unittest.cc b/chrome/browser/chromeos/accessibility/ax_host_service_unittest.cc
deleted file mode 100644
index 1c0bd2d..0000000
--- a/chrome/browser/chromeos/accessibility/ax_host_service_unittest.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/accessibility/ax_host_service.h"
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/test/scoped_task_environment.h"
-#include "chrome/browser/chromeos/accessibility/ax_remote_host_delegate.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
-#include "ui/accessibility/mojom/ax_host.mojom.h"
-
-namespace {
-
-class TestAXRemoteHost : ax::mojom::AXRemoteHost {
- public:
-  TestAXRemoteHost() : binding_(this) {}
-  ~TestAXRemoteHost() override = default;
-
-  ax::mojom::AXRemoteHostPtr CreateInterfacePtr() {
-    ax::mojom::AXRemoteHostPtr ptr;
-    binding_.Bind(mojo::MakeRequest(&ptr));
-    return ptr;
-  }
-
-  // Simulates the real AXRemoteHost.
-  void RegisterRemoteHostCallback(const ui::AXTreeID& tree_id, bool enabled) {
-    tree_id_ = tree_id;
-    OnAutomationEnabled(enabled);
-  }
-
-  // ax::mojom::AXRemoteHost:
-  void OnAutomationEnabled(bool enabled) override {
-    ++automation_enabled_count_;
-    last_automation_enabled_ = enabled;
-  }
-  void PerformAction(const ui::AXActionData& action) override {
-    ++perform_action_count_;
-    last_action_ = action;
-  }
-
-  mojo::Binding<ax::mojom::AXRemoteHost> binding_;
-  ui::AXTreeID tree_id_;
-  int automation_enabled_count_ = 0;
-  bool last_automation_enabled_ = false;
-  int perform_action_count_ = 0;
-  ui::AXActionData last_action_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestAXRemoteHost);
-};
-
-class AXHostServiceTest : public testing::Test {
- public:
-  AXHostServiceTest() = default;
-  ~AXHostServiceTest() override = default;
-
-  void RegisterRemoteHost(AXHostService* service, TestAXRemoteHost* remote) {
-    service->RegisterRemoteHost(
-        remote->CreateInterfacePtr(),
-        base::BindOnce(&TestAXRemoteHost::RegisterRemoteHostCallback,
-                       base::Unretained(remote)));
-    service->FlushForTesting();
-  }
-
- private:
-  base::test::ScopedTaskEnvironment scoped_task_enviroment_;
-
-  DISALLOW_COPY_AND_ASSIGN(AXHostServiceTest);
-};
-
-TEST_F(AXHostServiceTest, AddClientThenEnable) {
-  AXHostService service(nullptr);
-  TestAXRemoteHost remote;
-  RegisterRemoteHost(&service, &remote);
-
-  // Remote received initial state.
-  EXPECT_EQ(1, remote.automation_enabled_count_);
-  EXPECT_FALSE(remote.last_automation_enabled_);
-
-  // AXHostService assigned a tree id.
-  ui::AXTreeID tree_id = remote.tree_id_;
-  EXPECT_NE(ui::AXTreeIDUnknown(), tree_id);
-
-  AXHostService::SetAutomationEnabled(true);
-  service.FlushForTesting();
-
-  // Remote received updated state.
-  EXPECT_EQ(2, remote.automation_enabled_count_);
-  EXPECT_TRUE(remote.last_automation_enabled_);
-}
-
-TEST_F(AXHostServiceTest, EnableThenAddClient) {
-  AXHostService service(nullptr);
-  AXHostService::SetAutomationEnabled(true);
-
-  TestAXRemoteHost remote;
-  RegisterRemoteHost(&service, &remote);
-
-  // Remote received initial state.
-  EXPECT_EQ(1, remote.automation_enabled_count_);
-  EXPECT_TRUE(remote.last_automation_enabled_);
-
-  // AXHostService assigned a tree id.
-  EXPECT_NE(ui::AXTreeIDUnknown(), remote.tree_id_);
-}
-
-TEST_F(AXHostServiceTest, PerformAction) {
-  AXHostService service(nullptr);
-  AXHostService::SetAutomationEnabled(true);
-
-  TestAXRemoteHost remote;
-  RegisterRemoteHost(&service, &remote);
-
-  // AXActionHandler was created.
-  ui::AXTreeID tree_id = remote.tree_id_;
-  ui::AXActionHandler* action_handler =
-      ui::AXTreeIDRegistry::GetInstance()->GetActionHandler(tree_id);
-  ASSERT_TRUE(action_handler);
-
-  // Trigger an action.
-  ui::AXActionData action;
-  action.action = ax::mojom::Action::kScrollUp;
-  action_handler->PerformAction(action);
-  service.FlushForTesting();
-
-  // Remote interface received the action.
-  EXPECT_EQ(1, remote.perform_action_count_);
-  EXPECT_EQ(ax::mojom::Action::kScrollUp, remote.last_action_.action);
-}
-
-TEST_F(AXHostServiceTest, MultipleRemoteHosts) {
-  AXHostService service(nullptr);
-  AXHostService::SetAutomationEnabled(true);
-
-  // Connect 2 remote hosts.
-  TestAXRemoteHost remote1;
-  RegisterRemoteHost(&service, &remote1);
-  TestAXRemoteHost remote2;
-  RegisterRemoteHost(&service, &remote2);
-
-  // Different tree ids were assigned.
-  EXPECT_NE(ui::AXTreeIDUnknown(), remote1.tree_id_);
-  EXPECT_NE(ui::AXTreeIDUnknown(), remote2.tree_id_);
-  EXPECT_NE(remote1.tree_id_, remote2.tree_id_);
-
-  // Trigger an action on the first remote.
-  ui::AXActionData action;
-  action.action = ax::mojom::Action::kScrollUp;
-  ui::AXActionHandler* action_handler =
-      ui::AXTreeIDRegistry::GetInstance()->GetActionHandler(remote1.tree_id_);
-  action_handler->PerformAction(action);
-  service.FlushForTesting();
-
-  // Remote 1 received the action.
-  EXPECT_EQ(1, remote1.perform_action_count_);
-  EXPECT_EQ(ax::mojom::Action::kScrollUp, remote1.last_action_.action);
-
-  // Remote 2 did not receive the action.
-  EXPECT_EQ(0, remote2.perform_action_count_);
-}
-
-TEST_F(AXHostServiceTest, RemoteHostDisconnect) {
-  AXHostService service(nullptr);
-  AXHostService::SetAutomationEnabled(true);
-
-  // Connect 2 remote hosts.
-  TestAXRemoteHost remote1;
-  RegisterRemoteHost(&service, &remote1);
-  TestAXRemoteHost remote2;
-  RegisterRemoteHost(&service, &remote2);
-
-  // Tree IDs exist for both.
-  auto* tree_id_registry = ui::AXTreeIDRegistry::GetInstance();
-  EXPECT_TRUE(tree_id_registry->GetActionHandler(remote1.tree_id_));
-  EXPECT_TRUE(tree_id_registry->GetActionHandler(remote2.tree_id_));
-
-  // Simulate remote 1 disconnecting.
-  service.OnRemoteHostDisconnected(remote1.tree_id_);
-
-  // Tree ID for remote 1 is gone.
-  EXPECT_FALSE(tree_id_registry->GetActionHandler(remote1.tree_id_));
-  EXPECT_TRUE(tree_id_registry->GetActionHandler(remote2.tree_id_));
-}
-
-}  // namespace
diff --git a/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.cc b/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.cc
deleted file mode 100644
index cc49e90..0000000
--- a/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/accessibility/ax_remote_host_delegate.h"
-
-#include "base/bind.h"
-#include "chrome/browser/chromeos/accessibility/ax_host_service.h"
-#include "chrome/common/extensions/chrome_extension_messages.h"
-#include "extensions/browser/api/automation_internal/automation_event_router.h"
-#include "ui/accessibility/ax_event.h"
-#include "ui/accessibility/ax_tree_update.h"
-#include "ui/aura/env.h"
-
-AXRemoteHostDelegate::AXRemoteHostDelegate(AXHostService* host_service,
-                                           ax::mojom::AXRemoteHostPtr ptr)
-    : host_service_(host_service), remote_host_ptr_(std::move(ptr)) {
-  DCHECK(host_service_);
-  DCHECK(remote_host_ptr_);
-
-  // AX tree ID is automatically assigned.
-  DCHECK_NE(ax_tree_id(), ui::AXTreeIDUnknown());
-
-  // Handle both clean and unclean shutdown of the remote app.
-  remote_host_ptr_.set_connection_error_handler(base::BindOnce(
-      &AXRemoteHostDelegate::OnRemoteHostDisconnected, base::Unretained(this)));
-}
-
-AXRemoteHostDelegate::~AXRemoteHostDelegate() = default;
-
-void AXRemoteHostDelegate::OnAutomationEnabled(bool enabled) {
-  remote_host_ptr_->OnAutomationEnabled(enabled);
-}
-
-void AXRemoteHostDelegate::HandleAccessibilityEvent(
-    const ui::AXTreeID& tree_id,
-    const std::vector<ui::AXTreeUpdate>& updates,
-    const ui::AXEvent& event) {
-  CHECK_EQ(tree_id, ax_tree_id());
-  ExtensionMsg_AccessibilityEventBundleParams event_bundle;
-  event_bundle.tree_id = tree_id;
-  for (const ui::AXTreeUpdate& update : updates)
-    event_bundle.updates.push_back(update);
-  event_bundle.events.push_back(event);
-  event_bundle.mouse_location = aura::Env::GetInstance()->last_mouse_location();
-
-  // Forward the tree updates and the event to the accessibility extension.
-  extensions::AutomationEventRouter::GetInstance()->DispatchAccessibilityEvents(
-      event_bundle);
-}
-
-void AXRemoteHostDelegate::PerformAction(const ui::AXActionData& data) {
-  // Send to remote host.
-  remote_host_ptr_->PerformAction(data);
-}
-
-void AXRemoteHostDelegate::FlushForTesting() {
-  remote_host_ptr_.FlushForTesting();
-}
-
-void AXRemoteHostDelegate::OnRemoteHostDisconnected() {
-  extensions::AutomationEventRouter::GetInstance()->DispatchTreeDestroyedEvent(
-      ax_tree_id(), nullptr /* browser_context */);
-  host_service_->OnRemoteHostDisconnected(ax_tree_id());
-  // This object is now deleted.
-}
diff --git a/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.h b/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.h
deleted file mode 100644
index c02a197..0000000
--- a/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_AX_REMOTE_HOST_DELEGATE_H_
-#define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_AX_REMOTE_HOST_DELEGATE_H_
-
-#include <vector>
-
-#include "mojo/public/cpp/bindings/interface_ptr.h"
-#include "ui/accessibility/ax_action_handler.h"
-#include "ui/accessibility/ax_tree_update.h"
-#include "ui/accessibility/mojom/ax_host.mojom.h"
-
-namespace ui {
-struct AXEvent;
-class AXTreeID;
-}  // namespace ui
-
-class AXHostService;
-
-// Forwards accessibility events from a remote process that uses aura and views
-// (e.g. the Chrome OS keyboard shortcut_viewer) to accessibility extensions.
-// Renderers, PDF, etc. use a different path. Created when the app connects over
-// mojo. Implements AXActionHandler to route actions over mojo to the remote
-// process.
-// TODO(jamescook): Rename to AXRemoteActionHandler.
-class AXRemoteHostDelegate : public ui::AXActionHandler {
- public:
-  // |host_service| owns this object. |remote_host_ptr| is the mojo interface
-  // for the remote app.
-  AXRemoteHostDelegate(AXHostService* host_service,
-                       ax::mojom::AXRemoteHostPtr remote_host_ptr);
-  ~AXRemoteHostDelegate() override;
-
-  // Requests AX node trees from remote clients and starts listening for remote
-  // AX events. Static because the mojo service_manager creates and owns the
-  // service object, but automation may be enabled before a client connects and
-  // the service starts.
-  void OnAutomationEnabled(bool enabled);
-
-  // Handles an accessibility event from a remote host.
-  void HandleAccessibilityEvent(const ui::AXTreeID& tree_id,
-                                const std::vector<ui::AXTreeUpdate>& updates,
-                                const ui::AXEvent& event);
-
-  // ui::AXActionHandler:
-  void PerformAction(const ui::AXActionData& data) override;
-
-  void FlushForTesting();
-
- private:
-  // Cleans up the extension's AX tree when the remote app disconnects.
-  void OnRemoteHostDisconnected();
-
-  // The owning AXHostService.
-  AXHostService* host_service_;
-
-  // Connection to the remote host.
-  mojo::InterfacePtr<ax::mojom::AXRemoteHost> remote_host_ptr_;
-
-  DISALLOW_COPY_AND_ASSIGN(AXRemoteHostDelegate);
-};
-
-#endif  // CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_AX_REMOTE_HOST_DELEGATE_H_
diff --git a/chrome/browser/chromeos/arc/arc_util_unittest.cc b/chrome/browser/chromeos/arc/arc_util_unittest.cc
index 5a6fed7..d2b2c8f 100644
--- a/chrome/browser/chromeos/arc/arc_util_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_util_unittest.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
@@ -976,7 +977,7 @@
   EXPECT_FALSE(IsArcOobeOptInActive());
   // ARC ToS wizard but not for new user.
   login_display_host()->StartWizard(
-      chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
+      chromeos::ArcTermsOfServiceScreenView::kScreenId);
   EXPECT_FALSE(IsArcOobeOptInActive());
 }
 
@@ -997,7 +998,7 @@
   DisableDBusForProfileManager();
   CreateLoginDisplayHost();
   login_display_host()->StartWizard(
-      chromeos::OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+      chromeos::DemoPreferencesScreenView::kScreenId);
   login_display_host()
       ->GetWizardController()
       ->SimulateDemoModeSetupForTesting();
@@ -1013,7 +1014,7 @@
   DisableDBusForProfileManager();
   CreateLoginDisplayHost();
   login_display_host()->StartWizard(
-      chromeos::OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+      chromeos::DemoPreferencesScreenView::kScreenId);
   login_display_host()
       ->GetWizardController()
       ->SimulateDemoModeSetupForTesting();
diff --git a/chrome/browser/chromeos/base/locale_util.cc b/chrome/browser/chromeos/base/locale_util.cc
index 9428e654..36873de 100644
--- a/chrome/browser/chromeos/base/locale_util.cc
+++ b/chrome/browser/chromeos/base/locale_util.cc
@@ -167,9 +167,7 @@
   std::string resolved_locale = locale;
 
   // The locale is a UI locale or can be converted to a UI locale.
-  if (base::FeatureList::IsEnabled(translate::kRegionalLocalesAsDisplayUI))
-    return language::ConvertToActualUILocale(&resolved_locale);
-  return language::ConvertToFallbackUILocale(&resolved_locale);
+  return language::ConvertToActualUILocale(&resolved_locale);
 }
 
 void RemoveDisallowedLanguagesFromPreferred(PrefService* prefs) {
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.cc
index 22614c9..f9a223f3 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.cc
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.h"
 
+#include <utility>
 #include <vector>
 
 #include "base/big_endian.h"
@@ -68,13 +69,23 @@
   DCHECK(clock_drift_tolerance_ <= kMaxClockDriftTolerance);
 }
 
-AccessCodeConfig::AccessCodeConfig(const AccessCodeConfig& rhs) = default;
+AccessCodeConfig::AccessCodeConfig(AccessCodeConfig&&) = default;
 
-AccessCodeConfig& AccessCodeConfig::operator=(const AccessCodeConfig& rhs) =
-    default;
+AccessCodeConfig& AccessCodeConfig::operator=(AccessCodeConfig&&) = default;
 
 AccessCodeConfig::~AccessCodeConfig() = default;
 
+base::Value AccessCodeConfig::ToDictionary() const {
+  base::Value config(base::Value::Type::DICTIONARY);
+  config.SetKey(kSharedSecretDictKey, base::Value(shared_secret_));
+  config.SetKey(kCodeValidityDictKey,
+                base::Value(static_cast<int>(code_validity_.InSeconds())));
+  config.SetKey(
+      kClockDriftDictKey,
+      base::Value(static_cast<int>(clock_drift_tolerance_.InSeconds())));
+  return config;
+}
+
 AccessCode::AccessCode(const std::string& code,
                        base::Time valid_from,
                        base::Time valid_to)
@@ -107,7 +118,8 @@
 // static
 constexpr base::TimeDelta Authenticator::kAccessCodeGranularity;
 
-Authenticator::Authenticator(const AccessCodeConfig& config) : config_(config) {
+Authenticator::Authenticator(AccessCodeConfig config)
+    : config_(std::move(config)) {
   bool result = hmac_.Init(config_.shared_secret());
   DCHECK(result);
 }
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.h b/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.h
index 3030e80..df9d3c4 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.h
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.h
@@ -12,10 +12,12 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "components/account_id/account_id.h"
 #include "crypto/hmac.h"
 
 namespace base {
 class DictionaryValue;
+class Value;
 }  // namespace base
 
 namespace chromeos {
@@ -39,8 +41,8 @@
   AccessCodeConfig(const std::string& shared_secret,
                    base::TimeDelta code_validity,
                    base::TimeDelta clock_drift_tolerance);
-  AccessCodeConfig(const AccessCodeConfig& rhs);
-  AccessCodeConfig& operator=(const AccessCodeConfig&);
+  AccessCodeConfig(AccessCodeConfig&&);
+  AccessCodeConfig& operator=(AccessCodeConfig&&);
   ~AccessCodeConfig();
 
   // Secret shared between child and parent devices.
@@ -54,10 +56,15 @@
     return clock_drift_tolerance_;
   }
 
+  // Converts the AccessCodeConfig object to its dictionary equivalent.
+  base::Value ToDictionary() const;
+
  private:
   std::string shared_secret_;
   base::TimeDelta code_validity_;
   base::TimeDelta clock_drift_tolerance_;
+
+  DISALLOW_COPY_AND_ASSIGN(AccessCodeConfig);
 };
 
 // Parent access code that can be used to authorize various actions on child
@@ -105,13 +112,12 @@
   static constexpr base::TimeDelta kAccessCodeGranularity =
       base::TimeDelta::FromMinutes(1);
 
-  explicit Authenticator(const AccessCodeConfig& config);
+  explicit Authenticator(AccessCodeConfig config);
   ~Authenticator();
 
   // Generates parent access code from the given |timestamp|. Returns the code
   // if generation was successful. |timestamp| needs to be greater or equal Unix
   // Epoch.
-
   base::Optional<AccessCode> Generate(base::Time timestamp) const;
 
   // Returns AccessCode structure with validity information, if |code| is
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator_unittest.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator_unittest.cc
index 7fe5cb8..ed01882 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator_unittest.cc
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/authenticator_unittest.cc
@@ -10,12 +10,17 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "chrome/browser/chromeos/child_accounts/parent_access_code/test_utils.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
 namespace parent_access {
 
+AccessCodeConfig GetZeroClockDriftConfig() {
+  return AccessCodeConfig(kTestSharedSecret, kDefaultCodeValidity,
+                          base::TimeDelta::FromMinutes(0));
+}
+
 class ParentAccessCodeAuthenticatorTest : public testing::Test {
  protected:
   ParentAccessCodeAuthenticatorTest() = default;
@@ -53,7 +58,7 @@
   ASSERT_TRUE(base::Time::FromString("14 Jan 2019 15:00:00 PST", &timestamp));
   const AccessCodeConfig config = GetDefaultTestConfig();
 
-  Authenticator gen(config);
+  Authenticator gen(GetDefaultTestConfig());
   base::Optional<AccessCode> first_code = gen.Generate(timestamp);
   ASSERT_NO_FATAL_FAILURE(Verify(first_code, timestamp));
 
@@ -101,11 +106,11 @@
   const AccessCodeConfig config = GetDefaultTestConfig();
   const base::Time timestamp = base::Time::Now();
 
-  Authenticator gen1(config);
+  Authenticator gen1(GetDefaultTestConfig());
   base::Optional<AccessCode> code1 = gen1.Generate(timestamp);
   ASSERT_NO_FATAL_FAILURE(Verify(code1, timestamp));
 
-  Authenticator gen2(config);
+  Authenticator gen2(GetDefaultTestConfig());
   base::Optional<AccessCode> code2 = gen2.Generate(timestamp);
   ASSERT_NO_FATAL_FAILURE(Verify(code2, timestamp));
 
@@ -184,10 +189,9 @@
   // Test validation against codes generated by separate
   // Authenticator object in and outside of the valid time
   // bucket.
-  const AccessCodeConfig config(kTestSharedSecret, kDefaultCodeValidity,
-                                base::TimeDelta::FromMinutes(0));
-  Authenticator generator(config);
-  Authenticator validator(config);
+  const AccessCodeConfig config(GetZeroClockDriftConfig());
+  Authenticator generator(GetZeroClockDriftConfig());
+  Authenticator validator(GetZeroClockDriftConfig());
 
   base::Time generation_timestamp;
   ASSERT_TRUE(base::Time::FromString("15 Jan 2019 00:00:00 PST",
@@ -223,9 +227,8 @@
        ValidationAndGenerationOnSameAuthenticator) {
   // Test generation and validation on the same Authenticator
   // object in and outside of the valid time bucket.
-  const AccessCodeConfig config(kTestSharedSecret, kDefaultCodeValidity,
-                                base::TimeDelta::FromMinutes(0));
-  Authenticator authenticator(config);
+  const AccessCodeConfig config(GetZeroClockDriftConfig());
+  Authenticator authenticator(GetZeroClockDriftConfig());
 
   base::Time generation_timestamp;
   ASSERT_TRUE(base::Time::FromString("15 Jan 2019 00:00:00 PST",
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/config_source.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/config_source.cc
index 06baaef..c90d839c 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/config_source.cc
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/config_source.cc
@@ -4,32 +4,88 @@
 
 #include "chrome/browser/chromeos/child_accounts/parent_access_code/config_source.h"
 
+#include <utility>
+
+#include "base/bind.h"
+#include "base/values.h"
+#include "chrome/common/pref_names.h"
+#include "components/account_id/account_id.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_manager/known_user.h"
+#include "components/user_manager/user_manager.h"
+
 namespace chromeos {
 namespace parent_access {
 
-ConfigSource::ConfigSet::ConfigSet() = default;
-ConfigSource::ConfigSet::~ConfigSet() = default;
-ConfigSource::ConfigSet::ConfigSet(ConfigSet&&) = default;
-ConfigSource::ConfigSet& ConfigSource::ConfigSet::operator=(ConfigSet&&) =
-    default;
+namespace {
 
-ConfigSource::Observer::Observer() = default;
-ConfigSource::Observer::~Observer() = default;
+// Dictionary keys for ParentAccessCodeConfig policy.
+constexpr char kFutureConfigDictKey[] = "future_config";
+constexpr char kCurrentConfigDictKey[] = "current_config";
+constexpr char kOldConfigsDictKey[] = "old_configs";
 
-ConfigSource::ConfigSource() = default;
+}  // namespace
+
+ConfigSource::ConfigSource() {
+  const user_manager::UserList& users =
+      user_manager::UserManager::Get()->GetUsers();
+  for (const user_manager::User* user : users) {
+    if (user->IsChild())
+      LoadConfigForUser(user);
+  }
+}
+
 ConfigSource::~ConfigSource() = default;
 
-void ConfigSource::AddObserver(Observer* observer) {
-  observers_.AddObserver(observer);
+void ConfigSource::LoadConfigForUser(const user_manager::User* user) {
+  DCHECK(user->IsChild());
+
+  const base::Value* dictionary = nullptr;
+  if (!user_manager::known_user::GetPref(
+          user->GetAccountId(), prefs::kKnownUserParentAccessCodeConfig,
+          &dictionary)) {
+    return;
+  }
+
+  // Clear old authenticators for that user.
+  config_map_[user->GetAccountId()].clear();
+
+  const base::Value* future_config_value = dictionary->FindKeyOfType(
+      kFutureConfigDictKey, base::Value::Type::DICTIONARY);
+  if (future_config_value) {
+    AddAuthenticator(*future_config_value, user);
+  } else {
+    LOG(WARNING) << "No future config for parent access code in the policy";
+  }
+
+  const base::Value* current_config_value = dictionary->FindKeyOfType(
+      kCurrentConfigDictKey, base::Value::Type::DICTIONARY);
+  if (current_config_value) {
+    AddAuthenticator(*current_config_value, user);
+  } else {
+    LOG(WARNING) << "No current config for parent access code in the policy";
+  }
+
+  const base::Value* old_configs_value =
+      dictionary->FindKeyOfType(kOldConfigsDictKey, base::Value::Type::LIST);
+  if (old_configs_value) {
+    for (const auto& config_value : old_configs_value->GetList())
+      AddAuthenticator(config_value, user);
+  }
 }
 
-void ConfigSource::RemoveObserver(Observer* observer) {
-  observers_.RemoveObserver(observer);
-}
+void ConfigSource::AddAuthenticator(const base::Value& dict,
+                                    const user_manager::User* user) {
+  if (!dict.is_dict())
+    return;
 
-void ConfigSource::NotifyConfigChanged(const ConfigSet& configs) {
-  for (auto& observer : observers_)
-    observer.OnConfigChanged(configs);
+  base::Optional<AccessCodeConfig> code_config =
+      AccessCodeConfig::FromDictionary(
+          static_cast<const base::DictionaryValue&>(dict));
+  if (code_config) {
+    config_map_[user->GetAccountId()].push_back(
+        std::make_unique<Authenticator>(std::move(code_config.value())));
+  }
 }
 
 }  // namespace parent_access
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/config_source.h b/chrome/browser/chromeos/child_accounts/parent_access_code/config_source.h
index f6331ddc..f29d9c5d9 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/config_source.h
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/config_source.h
@@ -5,72 +5,52 @@
 #ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_CONFIG_SOURCE_H_
 #define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_CONFIG_SOURCE_H_
 
+#include <map>
 #include <memory>
 #include <vector>
 
 #include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/observer_list_types.h"
 #include "base/optional.h"
 #include "chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.h"
 
+class AccountId;
+
+namespace base {
+class Value;
+}
+
+namespace user_manager {
+class User;
+}
+
 namespace chromeos {
 namespace parent_access {
 
-class AccessCodeConfig;
-
 // Base class for parent access code configuration providers.
 class ConfigSource {
  public:
-  // Set of parent access code configurations used for generation and validation
-  // of parent access code.
-  struct ConfigSet {
-    ConfigSet();
-    ConfigSet(ConfigSet&&);
-    ConfigSet& operator=(ConfigSet&&);
-    ~ConfigSet();
-
-    // Primary config used for validation of parent access code.
-    base::Optional<AccessCodeConfig> future_config;
-
-    // Primary config used for generation of parent access code.
-    // Should be used for validation only when access code cannot be validated
-    // with |future_config|.
-    base::Optional<AccessCodeConfig> current_config;
-
-    // These configs should be used for validation of parent access code only
-    // when it cannot be validated with |future_config| nor |current_config|.
-    std::vector<AccessCodeConfig> old_configs;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(ConfigSet);
-  };
-
-  // Observer interface for ConfigSource that gets notified when parent access
-  // code configuration changed.
-  class Observer : public base::CheckedObserver {
-   public:
-    Observer();
-    ~Observer() override;
-
-    // Called when parent access code configuration changed.
-    virtual void OnConfigChanged(const ConfigSet& configs) = 0;
-  };
+  // Map containing a list of Authenticators per child account logged in the
+  // device.
+  typedef std::map<AccountId, std::vector<std::unique_ptr<Authenticator>>>
+      AuthenticatorsMap;
 
   ConfigSource();
-  virtual ~ConfigSource();
+  ~ConfigSource();
 
-  // Returns current parent access code configurations.
-  virtual ConfigSet GetConfigSet() = 0;
+  const AuthenticatorsMap& config_map() const { return config_map_; }
 
-  void AddObserver(Observer* observer);
-  void RemoveObserver(Observer* observer);
-
- protected:
-  void NotifyConfigChanged(const ConfigSet& configs);
+  // Reloads the Parent Access Code config for that particular user.
+  void LoadConfigForUser(const user_manager::User* user);
 
  private:
-  base::ObserverList<Observer> observers_;
+  // Creates and adds an authenticator to the |config_map_|. |dict| corresponds
+  // to an AccessCodeConfig in its serialized format.
+  void AddAuthenticator(const base::Value& dict,
+                        const user_manager::User* user);
+
+  // Holds the Parent Access Code Authenticators for all children signed in this
+  // device.
+  AuthenticatorsMap config_map_;
 
   DISALLOW_COPY_AND_ASSIGN(ConfigSource);
 };
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
index 53a25f2..1265dcd 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
@@ -8,99 +8,71 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/no_destructor.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/timer/timer.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
+#include "components/user_manager/user_manager.h"
 
 namespace chromeos {
 namespace parent_access {
 
-ParentAccessService::Delegate::Delegate() = default;
-ParentAccessService::Delegate::~Delegate() = default;
-
 // static
 void ParentAccessService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterDictionaryPref(prefs::kParentAccessCodeConfig);
 }
 
-ParentAccessService::ParentAccessService(
-    std::unique_ptr<ConfigSource> config_source)
-    : config_source_(std::move(config_source)),
-      clock_(base::DefaultClock::GetInstance()) {
-  CreateValidators(config_source_->GetConfigSet());
-  DCHECK(LoginScreenClient::Get());
-  LoginScreenClient::Get()->SetParentAccessDelegate(this);
+// static
+ParentAccessService& ParentAccessService::Get() {
+  static base::NoDestructor<ParentAccessService> instance;
+  return *instance;
 }
 
-ParentAccessService::~ParentAccessService() {
-  if (LoginScreenClient::HasInstance())
-    LoginScreenClient::Get()->SetParentAccessDelegate(nullptr);
-}
+ParentAccessService::ParentAccessService()
+    : clock_(base::DefaultClock::GetInstance()) {}
 
-void ParentAccessService::SetDelegate(Delegate* delegate) {
-  DCHECK(!(delegate_ && delegate));
-  delegate_ = delegate;
-}
+ParentAccessService::~ParentAccessService() = default;
 
-void ParentAccessService::ValidateParentAccessCode(
-    const std::string& access_code,
-    ValidateParentAccessCodeCallback callback) {
+bool ParentAccessService::ValidateParentAccessCode(
+    base::Optional<AccountId> account_id,
+    const std::string& access_code) {
   bool validation_result = false;
-  for (auto& validator : access_code_validators_) {
-    if (validator->Validate(access_code, clock_->Now())) {
-      validation_result = true;
-      break;
+  for (const auto& map_entry : config_source_.config_map()) {
+    if (!account_id || account_id == map_entry.first) {
+      for (const auto& validator : map_entry.second) {
+        if (validator->Validate(access_code, clock_->Now())) {
+          validation_result = true;
+          break;
+        }
+      }
     }
+    if (validation_result)
+      break;
   }
 
-  if (delegate_)
-    delegate_->OnAccessCodeValidation(validation_result);
+  for (auto& observer : observers_)
+    observer.OnAccessCodeValidation(validation_result, account_id);
 
-  std::move(callback).Run(validation_result);
+  return validation_result;
 }
 
-void ParentAccessService::OnConfigChanged(
-    const ConfigSource::ConfigSet& configs) {
-  CreateValidators(configs);
+void ParentAccessService::LoadConfigForUser(const user_manager::User* user) {
+  config_source_.LoadConfigForUser(user);
+}
+
+void ParentAccessService::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ParentAccessService::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
 }
 
 void ParentAccessService::SetClockForTesting(base::Clock* clock) {
   clock_ = clock;
 }
 
-void ParentAccessService::CreateValidators(
-    const ConfigSource::ConfigSet& configs) {
-  access_code_validators_.clear();
-
-  // Validators are added to |access_code_validators_| in the order that
-  // optimizes validation process. Parent access codes will be validated
-  // starting from the front of the vector. The correct validation order:
-  // * future configuration
-  // * current configuration
-  // * old configurations
-  if (configs.future_config.has_value()) {
-    access_code_validators_.push_back(
-        std::make_unique<Authenticator>(configs.future_config.value()));
-  } else {
-    LOG(WARNING) << "No future config for parent access code in the policy";
-  }
-
-  if (configs.current_config.has_value()) {
-    access_code_validators_.push_back(
-        std::make_unique<Authenticator>(configs.current_config.value()));
-  } else {
-    LOG(WARNING) << "No current config for parent access code in the policy";
-  }
-
-  for (const auto& config : configs.old_configs) {
-    access_code_validators_.push_back(std::make_unique<Authenticator>(config));
-  }
-
-  if (access_code_validators_.empty())
-    LOG(ERROR) << "No config to validate parent access available";
-}
-
 }  // namespace parent_access
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
index 2bc9ec0..c637f01 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_PARENT_ACCESS_SERVICE_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/macros.h"
@@ -22,66 +23,57 @@
 namespace chromeos {
 namespace parent_access {
 
-class Authenticator;
-
 // Parent access code validation service.
-class ParentAccessService : public LoginScreenClient::ParentAccessDelegate,
-                            public ConfigSource::Observer {
+class ParentAccessService {
  public:
-  // Delegate that gets notified about attempts to validate parent access code.
-  class Delegate {
+  // Observer that gets notified about attempts to validate parent access code.
+  class Observer : public base::CheckedObserver {
    public:
-    Delegate();
-    virtual ~Delegate();
-
     // Called when access code validation was performed. |result| is true if
-    // validation finished with a success and false otherwise.
-    virtual void OnAccessCodeValidation(bool result) = 0;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Delegate);
+    // validation finished with a success and false otherwise. |account_id| is
+    // forwarded from the ValidateParentAccessCode method that triggered this
+    // event, when it is filled it means that the validation happened
+    // specifically to the account identified by the parameter.
+    virtual void OnAccessCodeValidation(
+        bool result,
+        base::Optional<AccountId> account_id) = 0;
   };
 
   // Registers preferences.
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
-  explicit ParentAccessService(std::unique_ptr<ConfigSource> config_source);
-  ~ParentAccessService() override;
+  // Gets the service singleton.
+  static ParentAccessService& Get();
 
-  void SetDelegate(Delegate* delegate);
+  // Checks if |access_code| is valid for the user identified by |account_id|.
+  // When account_id is empty, this method checks if the |access_code| is valid
+  // for any child that was added to this device.
+  bool ValidateParentAccessCode(base::Optional<AccountId> account_id,
+                                const std::string& access_code);
 
-  // LoginScreenClient::ParentAccessDelegate:
-  void ValidateParentAccessCode(
-      const std::string& access_code,
-      ValidateParentAccessCodeCallback callback) override;
+  // Reloads config for the provided user.
+  void LoadConfigForUser(const user_manager::User* user);
 
-  // ConfigSource::Observer:
-  void OnConfigChanged(const ConfigSource::ConfigSet& configs) override;
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
 
   // Allows to override the time for testing purposes.
   void SetClockForTesting(base::Clock* clock);
 
  private:
-  friend class ParentAccessServiceTest;
+  friend class base::NoDestructor<ParentAccessService>;
 
-  void CreateValidators(const ConfigSource::ConfigSet& configs);
-
-  // Delegate that will be notified about results of access code validation.
-  Delegate* delegate_ = nullptr;
+  ParentAccessService();
+  ~ParentAccessService();
 
   // Provides configurations to be used for validation of access codes.
-  std::unique_ptr<ConfigSource> config_source_;
-
-  // Authenticators used for validation of parent access code.
-  // There is one validator per active parent access code configuration.
-  // Validators should be used in the order they are stored in
-  // |access_code_validators_|. Validation is considered successful if any of
-  // validators returns success.
-  std::vector<std::unique_ptr<Authenticator>> access_code_validators_;
+  ConfigSource config_source_;
 
   // Points to the base::DefaultClock by default.
   const base::Clock* clock_;
 
+  base::ObserverList<Observer> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(ParentAccessService);
 };
 
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service_browsertest.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service_browsertest.cc
new file mode 100644
index 0000000..5e4781e
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service_browsertest.cc
@@ -0,0 +1,317 @@
+// 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 <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/json/json_writer.h"
+#include "base/macros.h"
+#include "base/test/simple_test_clock.h"
+#include "chrome/browser/chromeos/child_accounts/child_account_test_utils.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/config_source.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.h"
+#include "chrome/browser/chromeos/policy/login_policy_test_base.h"
+#include "chrome/browser/chromeos/policy/user_policy_test_helper.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/account_id/account_id.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
+#include "components/policy/policy_constants.h"
+#include "components/prefs/pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace parent_access {
+
+namespace {
+
+// Dictionary keys for ParentAccessCodeConfig policy.
+constexpr char kFutureConfigDictKey[] = "future_config";
+constexpr char kCurrentConfigDictKey[] = "current_config";
+constexpr char kOldConfigsDictKey[] = "old_configs";
+
+base::DictionaryValue PolicyFromConfigs(
+    const AccessCodeConfig& future_config,
+    const AccessCodeConfig& current_config,
+    const std::vector<AccessCodeConfig>& old_configs) {
+  base::DictionaryValue dict;
+  dict.SetKey(kFutureConfigDictKey, future_config.ToDictionary());
+  dict.SetKey(kCurrentConfigDictKey, current_config.ToDictionary());
+  base::Value old_configs_value(base::Value::Type::LIST);
+  for (const auto& config : old_configs)
+    old_configs_value.GetList().push_back(config.ToDictionary());
+  dict.SetKey(kOldConfigsDictKey, std::move(old_configs_value));
+  return dict;
+}
+
+}  // namespace
+
+// Stores information about results of the access code validation.
+struct CodeValidationResults {
+  // Number of successful access code validations.
+  int success_count = 0;
+
+  // Number of attempts when access code validation failed.
+  int failure_count = 0;
+};
+
+// ParentAccessServiceObserver implementation used for tests.
+class TestParentAccessServiceObserver : public ParentAccessService::Observer {
+ public:
+  explicit TestParentAccessServiceObserver(const AccountId& account_id)
+      : account_id_(account_id) {}
+  ~TestParentAccessServiceObserver() override = default;
+
+  void OnAccessCodeValidation(bool result,
+                              base::Optional<AccountId> account_id) override {
+    ASSERT_TRUE(account_id);
+    EXPECT_EQ(account_id_, account_id.value());
+    result ? ++validation_results_.success_count
+           : ++validation_results_.failure_count;
+  }
+
+  CodeValidationResults validation_results_;
+
+ private:
+  const AccountId account_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestParentAccessServiceObserver);
+};
+
+class ParentAccessServiceTest : public policy::LoginPolicyTestBase {
+ public:
+  ParentAccessServiceTest()
+      : test_observer_(
+            std::make_unique<TestParentAccessServiceObserver>(child_)) {}
+  ~ParentAccessServiceTest() override = default;
+
+  void SetUp() override {
+    // Recognize example.com (used by LoginPolicyTestBase) as non-enterprise
+    // account.
+    policy::BrowserPolicyConnector::SetNonEnterpriseDomainForTesting(
+        "example.com");
+
+    policy::LoginPolicyTestBase::SetUp();
+  }
+
+  void SetUpOnMainThread() override {
+    ASSERT_NO_FATAL_FAILURE(GetTestAccessCodeValues(&test_values_));
+    ParentAccessService::Get().AddObserver(test_observer_.get());
+    ParentAccessService::Get().SetClockForTesting(&test_clock_);
+    policy::LoginPolicyTestBase::SetUpOnMainThread();
+  }
+
+  void TearDownOnMainThread() override {
+    ParentAccessService::Get().RemoveObserver(test_observer_.get());
+    policy::LoginPolicyTestBase::TearDownOnMainThread();
+  }
+
+  std::string GetIdToken() const override {
+    return test::GetChildAccountOAuthIdToken();
+  }
+
+ protected:
+  void LogInChild() {
+    SkipToLoginScreen();
+    LogIn(kAccountId, kAccountPassword, test::kChildAccountServiceFlags);
+  }
+
+  // Updates the policy containing the Parent Access Code config.
+  void UpdatePolicy(const base::DictionaryValue& dict) {
+    const user_manager::UserManager* const user_manager =
+        user_manager::UserManager::Get();
+    EXPECT_TRUE(user_manager->GetActiveUser()->IsChild());
+    Profile* child_profile =
+        ProfileHelper::Get()->GetProfileByUser(user_manager->GetActiveUser());
+
+    std::string config_string;
+    base::JSONWriter::Write(dict, &config_string);
+
+    base::DictionaryValue policy;
+    policy.SetKey(policy::key::kParentAccessCodeConfig,
+                  base::Value(config_string));
+    user_policy_helper()->SetPolicyAndWait(
+        std::move(policy), base::DictionaryValue(), child_profile);
+  }
+
+  // Performs |code| validation on ParentAccessCode singleton and returns the
+  // result.
+  bool ValidateAccessCode(const std::string& code) {
+    return ParentAccessService::Get().ValidateParentAccessCode(child_, code);
+  }
+
+  // Checks if ParentAccessServiceObserver and ValidateParentAccessCodeCallback
+  // were called as intended. Expects |success_count| of successful access code
+  // validations and |failure_count| of failed validation attempts.
+  void ExpectResults(int success_count, int failure_count) {
+    EXPECT_EQ(success_count, test_observer_->validation_results_.success_count);
+    EXPECT_EQ(failure_count, test_observer_->validation_results_.failure_count);
+  }
+
+  const AccountId child_ = AccountId::FromUserEmail(kAccountId);
+  base::SimpleTestClock test_clock_;
+  AccessCodeValues test_values_;
+  std::unique_ptr<TestParentAccessServiceObserver> test_observer_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ParentAccessServiceTest);
+};
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, NoConfigAvailable) {
+  LogInChild();
+
+  auto test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  EXPECT_FALSE(ValidateAccessCode(test_value->second));
+
+  ExpectResults(0, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, NoValidConfigAvailable) {
+  LogInChild();
+
+  std::vector<AccessCodeConfig> old_configs;
+  old_configs.emplace_back(GetInvalidTestConfig());
+  UpdatePolicy(PolicyFromConfigs(GetInvalidTestConfig(), GetInvalidTestConfig(),
+                                 old_configs));
+
+  const AccessCodeValues::iterator test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  EXPECT_FALSE(ValidateAccessCode(test_value->second));
+
+  ExpectResults(0, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, ValidationWithFutureConfig) {
+  LogInChild();
+
+  std::vector<AccessCodeConfig> old_configs;
+  old_configs.emplace_back(GetInvalidTestConfig());
+  UpdatePolicy(PolicyFromConfigs(GetDefaultTestConfig(), GetInvalidTestConfig(),
+                                 old_configs));
+
+  const AccessCodeValues::iterator test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  EXPECT_TRUE(ValidateAccessCode(test_value->second));
+
+  ExpectResults(1, 0);
+}
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, ValidationWithCurrentConfig) {
+  LogInChild();
+
+  std::vector<AccessCodeConfig> old_configs;
+  old_configs.emplace_back(GetInvalidTestConfig());
+  UpdatePolicy(PolicyFromConfigs(GetInvalidTestConfig(), GetDefaultTestConfig(),
+                                 old_configs));
+
+  const AccessCodeValues::iterator test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  EXPECT_TRUE(ValidateAccessCode(test_value->second));
+
+  ExpectResults(1, 0);
+}
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, ValidationWithOldConfig) {
+  LogInChild();
+
+  std::vector<AccessCodeConfig> old_configs;
+  old_configs.emplace_back(GetInvalidTestConfig());
+  old_configs.emplace_back(GetDefaultTestConfig());
+  UpdatePolicy(PolicyFromConfigs(GetInvalidTestConfig(), GetInvalidTestConfig(),
+                                 old_configs));
+
+  const AccessCodeValues::iterator test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  EXPECT_TRUE(ValidateAccessCode(test_value->second));
+
+  ExpectResults(1, 0);
+}
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, MultipleValidationAttempts) {
+  LogInChild();
+
+  AccessCodeValues::iterator test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  // No config - validation should fail.
+  EXPECT_FALSE(ValidateAccessCode(test_value->second));
+
+  UpdatePolicy(
+      PolicyFromConfigs(GetInvalidTestConfig(), GetDefaultTestConfig(), {}));
+
+  // Valid config - validation should pass.
+  for (auto& value : test_values_) {
+    test_clock_.SetNow(value.first);
+    EXPECT_TRUE(ValidateAccessCode(value.second));
+  }
+
+  UpdatePolicy(
+      PolicyFromConfigs(GetInvalidTestConfig(), GetInvalidTestConfig(), {}));
+
+  // Invalid config - validation should fail.
+  test_clock_.SetNow(test_value->first);
+  EXPECT_FALSE(ValidateAccessCode(test_value->second));
+
+  ExpectResults(test_values_.size(), 2);
+}
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, NoObserver) {
+  LogInChild();
+
+  ParentAccessService::Get().RemoveObserver(test_observer_.get());
+
+  UpdatePolicy(
+      PolicyFromConfigs(GetInvalidTestConfig(), GetDefaultTestConfig(), {}));
+
+  AccessCodeValues::iterator test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  EXPECT_TRUE(ValidateAccessCode(test_value->second));
+
+  ExpectResults(0, 0);
+}
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, NoAccountId) {
+  LogInChild();
+
+  ParentAccessService::Get().RemoveObserver(test_observer_.get());
+
+  UpdatePolicy(
+      PolicyFromConfigs(GetInvalidTestConfig(), GetDefaultTestConfig(), {}));
+
+  auto test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  EXPECT_TRUE(ParentAccessService::Get().ValidateParentAccessCode(
+      base::nullopt, test_value->second));
+}
+
+IN_PROC_BROWSER_TEST_F(ParentAccessServiceTest, InvalidAccountId) {
+  LogInChild();
+
+  ParentAccessService::Get().RemoveObserver(test_observer_.get());
+
+  UpdatePolicy(
+      PolicyFromConfigs(GetInvalidTestConfig(), GetDefaultTestConfig(), {}));
+
+  auto test_value = test_values_.begin();
+  test_clock_.SetNow(test_value->first);
+
+  AccountId other_child = AccountId::FromUserEmail("other.child@gmail.com");
+  EXPECT_FALSE(ParentAccessService::Get().ValidateParentAccessCode(
+      other_child, test_value->second));
+}
+
+}  // namespace parent_access
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service_unittest.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service_unittest.cc
deleted file mode 100644
index 8cf7e18..0000000
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service_unittest.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h"
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/test/simple_test_clock.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.h"
-#include "chrome/browser/chromeos/child_accounts/parent_access_code/test_utils.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "components/session_manager/core/session_manager.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "content/public/test/test_service_manager_context.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromeos {
-namespace parent_access {
-
-// Stores information about results of the access code validation.
-struct CodeValidationResults {
-  // Number of successful access code validations.
-  int success_count = 0;
-
-  // Number of attempts whenaccess code validation failed.
-  int failure_count = 0;
-};
-
-// Config source implementation used for tests.
-class TestConfigSource : public ConfigSource {
- public:
-  TestConfigSource() = default;
-  ~TestConfigSource() override = default;
-
-  ConfigSet GetConfigSet() override { return ConfigSet(); }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestConfigSource);
-};
-
-// ParentAccessServiceDelegate implementation used for tests.
-class TestParentAccessServiceDelegate : public ParentAccessService::Delegate {
- public:
-  TestParentAccessServiceDelegate() = default;
-  ~TestParentAccessServiceDelegate() override = default;
-
-  void OnAccessCodeValidation(bool result) override {
-    result ? ++validation_results_.success_count
-           : ++validation_results_.failure_count;
-  }
-
-  CodeValidationResults validation_results_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestParentAccessServiceDelegate);
-};
-
-// Tests ParentAccessService.
-class ParentAccessServiceTest : public testing::Test {
- public:
-  // Parent access code validation callback.
-  void OnParentAccessCodeCallback(bool result) {
-    result ? ++validation_results_.success_count
-           : ++validation_results_.failure_count;
-  }
-
- protected:
-  ParentAccessServiceTest() = default;
-  ~ParentAccessServiceTest() override = default;
-
-  // testing::Test:
-  void SetUp() override {
-    DBusThreadManager::Initialize();
-
-    auto config_source = std::make_unique<TestConfigSource>();
-    parent_access_service_ =
-        std::make_unique<parent_access::ParentAccessService>(
-            std::move(config_source));
-
-    test_delegate_ = std::make_unique<TestParentAccessServiceDelegate>();
-    parent_access_service_->SetDelegate(test_delegate_.get());
-
-    parent_access_service_->SetClockForTesting(&test_clock_);
-
-    ASSERT_NO_FATAL_FAILURE(GetTestAccessCodeValues(&test_values_));
-  }
-
-  void TearDown() override {
-    parent_access_service_->SetDelegate(nullptr);
-    DBusThreadManager::Shutdown();
-  }
-
-  // Performs |code| validation on |parent_access_service_|.
-  void ValidateAccessCode(const std::string& code) {
-    parent_access_service_->ValidateParentAccessCode(
-        code,
-        base::BindOnce(&ParentAccessServiceTest::OnParentAccessCodeCallback,
-                       base::Unretained(this)));
-  }
-
-  // Checks if ParentAccessServiceDelegate and ValidateParentAccessCodeCallback
-  // were called as intended. Expects |success_count| of successful access code
-  // validations and |failure_count| of failed validation attempts.
-  void ExpectResults(int success_count, int failure_count) {
-    EXPECT_EQ(success_count, test_delegate_->validation_results_.success_count);
-    EXPECT_EQ(failure_count, test_delegate_->validation_results_.failure_count);
-    EXPECT_EQ(success_count, validation_results_.success_count);
-    EXPECT_EQ(failure_count, validation_results_.failure_count);
-  }
-
-  // ParentAccessService depends on LoginScreenClient and therefore requires
-  // objects in the following block to be initialized early (order matters).
-  content::TestBrowserThreadBundle thread_bundle_;
-  content::TestServiceManagerContext context_;
-  session_manager::SessionManager session_manager_;
-  LoginScreenClient login_screen_client_;
-
-  base::SimpleTestClock test_clock_;
-  AccessCodeValues test_values_;
-  CodeValidationResults validation_results_;
-
-  std::unique_ptr<TestParentAccessServiceDelegate> test_delegate_;
-  std::unique_ptr<ParentAccessService> parent_access_service_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ParentAccessServiceTest);
-};
-
-TEST_F(ParentAccessServiceTest, NoConfigAvailable) {
-  auto test_value = test_values_.begin();
-  test_clock_.SetNow(test_value->first);
-
-  ValidateAccessCode(test_value->second);
-
-  ExpectResults(0, 1);
-}
-
-TEST_F(ParentAccessServiceTest, NoValidConfigAvailable) {
-  ConfigSource::ConfigSet configs;
-  configs.future_config = GetInvalidTestConfig();
-  configs.current_config = GetInvalidTestConfig();
-  configs.old_configs.push_back(GetInvalidTestConfig());
-  parent_access_service_->OnConfigChanged(configs);
-
-  const AccessCodeValues::iterator test_value = test_values_.begin();
-  test_clock_.SetNow(test_value->first);
-
-  ValidateAccessCode(test_value->second);
-
-  ExpectResults(0, 1);
-}
-
-TEST_F(ParentAccessServiceTest, ValidationWithFutureConfig) {
-  ConfigSource::ConfigSet configs;
-  configs.future_config = GetDefaultTestConfig();
-  configs.current_config = GetInvalidTestConfig();
-  configs.old_configs.push_back(GetInvalidTestConfig());
-  parent_access_service_->OnConfigChanged(configs);
-
-  const AccessCodeValues::iterator test_value = test_values_.begin();
-  test_clock_.SetNow(test_value->first);
-
-  ValidateAccessCode(test_value->second);
-
-  ExpectResults(1, 0);
-}
-
-TEST_F(ParentAccessServiceTest, ValidationWithCurrentConfig) {
-  ConfigSource::ConfigSet configs;
-  configs.future_config = GetInvalidTestConfig();
-  configs.current_config = GetDefaultTestConfig();
-  configs.old_configs.push_back(GetInvalidTestConfig());
-  parent_access_service_->OnConfigChanged(configs);
-
-  const AccessCodeValues::iterator test_value = test_values_.begin();
-  test_clock_.SetNow(test_value->first);
-
-  ValidateAccessCode(test_value->second);
-
-  ExpectResults(1, 0);
-}
-
-TEST_F(ParentAccessServiceTest, ValidationWithOldConfig) {
-  ConfigSource::ConfigSet configs;
-  configs.future_config = GetInvalidTestConfig();
-  configs.current_config = GetInvalidTestConfig();
-  configs.old_configs.push_back(GetInvalidTestConfig());
-  configs.old_configs.push_back(GetDefaultTestConfig());
-  parent_access_service_->OnConfigChanged(configs);
-
-  const AccessCodeValues::iterator test_value = test_values_.begin();
-  test_clock_.SetNow(test_value->first);
-
-  ValidateAccessCode(test_value->second);
-
-  ExpectResults(1, 0);
-}
-
-TEST_F(ParentAccessServiceTest, MultipleValidationAttempts) {
-  AccessCodeValues::iterator test_value = test_values_.begin();
-  test_clock_.SetNow(test_value->first);
-
-  // No config - validation should fail.
-  ValidateAccessCode(test_value->second);
-
-  ConfigSource::ConfigSet configs;
-  configs.current_config = GetDefaultTestConfig();
-  parent_access_service_->OnConfigChanged(configs);
-
-  // Valid config - validation should pass.
-  for (auto& value : test_values_) {
-    test_clock_.SetNow(value.first);
-    ValidateAccessCode(value.second);
-  }
-
-  configs.current_config = GetInvalidTestConfig();
-  parent_access_service_->OnConfigChanged(configs);
-
-  // Invalid config - validation should fail.
-  test_clock_.SetNow(test_value->first);
-  ValidateAccessCode(test_value->second);
-
-  ExpectResults(test_values_.size(), 2);
-}
-
-TEST_F(ParentAccessServiceTest, NoDelegate) {
-  parent_access_service_->SetDelegate(nullptr);
-
-  ConfigSource::ConfigSet configs;
-  configs.current_config = GetDefaultTestConfig();
-  parent_access_service_->OnConfigChanged(configs);
-
-  AccessCodeValues::iterator test_value = test_values_.begin();
-  test_clock_.SetNow(test_value->first);
-
-  ValidateAccessCode(test_value->second);
-
-  EXPECT_EQ(0, test_delegate_->validation_results_.success_count);
-  EXPECT_EQ(0, test_delegate_->validation_results_.failure_count);
-  EXPECT_EQ(1, validation_results_.success_count);
-  EXPECT_EQ(0, validation_results_.failure_count);
-}
-
-}  // namespace parent_access
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/test_utils.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.cc
similarity index 97%
rename from chrome/browser/chromeos/child_accounts/parent_access_code/test_utils.cc
rename to chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.cc
index 10dbd2e8..cbeb168 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/test_utils.cc
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.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/chromeos/child_accounts/parent_access_code/test_utils.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/test_utils.h b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.h
similarity index 90%
rename from chrome/browser/chromeos/child_accounts/parent_access_code/test_utils.h
rename to chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.h
index 8c7a15a..5a014370 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/test_utils.h
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.h
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_TEST_UTILS_H_
-#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_TEST_UTILS_H_
+#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_PARENT_ACCESS_TEST_UTILS_H_
+#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_PARENT_ACCESS_TEST_UTILS_H_
 
 #include <map>
 #include <string>
 
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/child_accounts/parent_access_code/authenticator.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/config_source.h"
 
 namespace chromeos {
 namespace parent_access {
@@ -40,4 +41,4 @@
 }  // namespace parent_access
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_TEST_UTILS_H_
+#endif  // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_PARENT_ACCESS_TEST_UTILS_H_
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.cc
deleted file mode 100644
index 80641cb..0000000
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.h"
-
-#include "base/bind.h"
-#include "base/values.h"
-#include "chrome/common/pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-
-namespace chromeos {
-namespace parent_access {
-
-namespace {
-
-// Dictionary keys for ParentAccessCodeConfig policy.
-constexpr char kFutureConfigDictKey[] = "future_config";
-constexpr char kCurrentConfigDictKey[] = "current_config";
-constexpr char kOldConfigsDictKey[] = "old_configs";
-}  // namespace
-
-PolicyConfigSource::PolicyConfigSource(PrefService* pref_service)
-    : pref_service_(pref_service) {
-  DCHECK(pref_service_);
-
-  pref_change_registrar_.Init(pref_service_);
-  pref_change_registrar_.Add(
-      prefs::kParentAccessCodeConfig,
-      base::BindRepeating(&PolicyConfigSource::OnPolicyChanged,
-                          base::Unretained(this)));
-}
-
-PolicyConfigSource::~PolicyConfigSource() = default;
-
-ConfigSource::ConfigSet PolicyConfigSource::GetConfigSet() {
-  const base::DictionaryValue* dictionary =
-      pref_service_->GetDictionary(prefs::kParentAccessCodeConfig);
-
-  ConfigSet config_set;
-
-  const base::Value* future_config_value = dictionary->FindKeyOfType(
-      kFutureConfigDictKey, base::Value::Type::DICTIONARY);
-  if (future_config_value) {
-    config_set.future_config = AccessCodeConfig::FromDictionary(
-        static_cast<const base::DictionaryValue&>(*future_config_value));
-  } else {
-    LOG(WARNING) << "No future config for parent access code in the policy";
-  }
-
-  const base::Value* current_config_value = dictionary->FindKeyOfType(
-      kCurrentConfigDictKey, base::Value::Type::DICTIONARY);
-  if (current_config_value) {
-    config_set.current_config = AccessCodeConfig::FromDictionary(
-        static_cast<const base::DictionaryValue&>(*current_config_value));
-  } else {
-    LOG(WARNING) << "No current config for parent access code in the policy";
-  }
-
-  const base::Value* old_configs_value =
-      dictionary->FindKeyOfType(kOldConfigsDictKey, base::Value::Type::LIST);
-  if (old_configs_value) {
-    for (const auto& config_value : old_configs_value->GetList()) {
-      base::Optional<AccessCodeConfig> config =
-          AccessCodeConfig::FromDictionary(
-              static_cast<const base::DictionaryValue&>(config_value));
-      if (config)
-        config_set.old_configs.push_back(config.value());
-    }
-  }
-  return config_set;
-}
-
-void PolicyConfigSource::OnPolicyChanged() {
-  NotifyConfigChanged(GetConfigSet());
-}
-
-}  // namespace parent_access
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.h b/chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.h
deleted file mode 100644
index 6717173..0000000
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_POLICY_CONFIG_SOURCE_H_
-#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_POLICY_CONFIG_SOURCE_H_
-
-#include "base/macros.h"
-#include "chrome/browser/chromeos/child_accounts/parent_access_code/config_source.h"
-#include "components/prefs/pref_change_registrar.h"
-
-class PrefService;
-
-namespace chromeos {
-namespace parent_access {
-
-// Provides parent access code configuration from user policy.
-class PolicyConfigSource : public ConfigSource {
- public:
-  explicit PolicyConfigSource(PrefService* pref_service);
-  ~PolicyConfigSource() override;
-
-  ConfigSet GetConfigSet() override;
-
- private:
-  // Updates configuration when policy changes.
-  void OnPolicyChanged();
-
-  PrefService* pref_service_ = nullptr;
-
-  PrefChangeRegistrar pref_change_registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(PolicyConfigSource);
-};
-
-}  // namespace parent_access
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_POLICY_CONFIG_SOURCE_H_
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
index f43f841..ee6b8ba6 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
@@ -10,13 +10,11 @@
 
 #include "base/bind.h"
 #include "base/feature_list.h"
-#include "base/optional.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.h"
 #include "chrome/browser/chromeos/child_accounts/consumer_status_reporting_service_factory.h"
-#include "chrome/browser/chromeos/child_accounts/parent_access_code/policy_config_source.h"
 #include "chrome/browser/chromeos/child_accounts/time_limit_override.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -77,11 +75,14 @@
       prefs::kUsageTimeLimit,
       base::BindRepeating(&ScreenTimeController::OnPolicyChanged,
                           base::Unretained(this)));
+
+  if (base::FeatureList::IsEnabled(features::kParentAccessCode))
+    parent_access::ParentAccessService::Get().AddObserver(this);
 }
 
 ScreenTimeController::~ScreenTimeController() {
-  if (parent_access_service_)
-    parent_access_service_->SetDelegate(nullptr);
+  if (base::FeatureList::IsEnabled(features::kParentAccessCode))
+    parent_access::ParentAccessService::Get().RemoveObserver(this);
 
   session_manager::SessionManager::Get()->RemoveObserver(this);
   if (base::FeatureList::IsEnabled(features::kUsageTimeStateNotifier))
@@ -106,25 +107,6 @@
       ->GetChildScreenTime();
 }
 
-void ScreenTimeController::OnAccessCodeValidation(bool result) {
-  if (!result)
-    return;
-
-  if (!session_manager::SessionManager::Get()->IsScreenLocked())
-    return;
-
-  usage_time_limit::TimeLimitOverride local_override(
-      usage_time_limit::TimeLimitOverride::Action::kUnlock, clock_->Now(),
-      base::nullopt);
-  // Replace previous local override stored in pref, because PAC can only be
-  // entered if previous override is not active anymore.
-  pref_service_->Set(prefs::kTimeLimitLocalOverride,
-                     local_override.ToDictionary());
-  pref_service_->CommitPendingWrite();
-
-  CheckTimeLimit("OnAccessCodeValidation");
-}
-
 void ScreenTimeController::SetClocksForTesting(
     const base::Clock* clock,
     const base::TickClock* tick_clock,
@@ -245,6 +227,31 @@
   chromeos::SessionManagerClient::Get()->RequestLockScreen();
 }
 
+void ScreenTimeController::OnAccessCodeValidation(
+    bool result,
+    base::Optional<AccountId> account_id) {
+  AccountId current_user_id =
+      chromeos::ProfileHelper::Get()
+          ->GetUserByProfile(Profile::FromBrowserContext(context_))
+          ->GetAccountId();
+  if (!result || !account_id || account_id.value() != current_user_id)
+    return;
+
+  if (!session_manager::SessionManager::Get()->IsScreenLocked())
+    return;
+
+  usage_time_limit::TimeLimitOverride local_override(
+      usage_time_limit::TimeLimitOverride::Action::kUnlock, clock_->Now(),
+      base::nullopt);
+  // Replace previous local override stored in pref, because PAC can only be
+  // entered if previous override is not active anymore.
+  pref_service_->Set(prefs::kTimeLimitLocalOverride,
+                     local_override.ToDictionary());
+  pref_service_->CommitPendingWrite();
+
+  CheckTimeLimit("OnAccessCodeValidation");
+}
+
 void ScreenTimeController::OnScreenLockByPolicy(
     usage_time_limit::PolicyType active_policy,
     base::Time next_unlock_time) {
@@ -498,18 +505,6 @@
   }
 }
 
-void ScreenTimeController::InitializeParentAccessServiceIfNeeded() {
-  if (base::FeatureList::IsEnabled(features::kParentAccessCode) &&
-      !parent_access_service_) {
-    auto config_source =
-        std::make_unique<parent_access::PolicyConfigSource>(pref_service_);
-    parent_access_service_ =
-        std::make_unique<parent_access::ParentAccessService>(
-            std::move(config_source));
-    parent_access_service_->SetDelegate(this);
-  }
-}
-
 void ScreenTimeController::OnSessionStateChanged() {
   session_manager::SessionState session_state =
       session_manager::SessionManager::Get()->session_state();
@@ -517,7 +512,6 @@
     base::Optional<usage_time_limit::State> last_state = GetLastStateFromPref();
     if (session_state == session_manager::SessionState::LOCKED && last_state &&
         last_state->is_locked) {
-      InitializeParentAccessServiceIfNeeded();
       OnScreenLockByPolicy(last_state->active_policy,
                            last_state->next_unlock_time);
     }
@@ -525,7 +519,6 @@
   }
 
   if (session_state == session_manager::SessionState::LOCKED) {
-    InitializeParentAccessServiceIfNeeded();
     base::Optional<usage_time_limit::State> last_state = GetLastStateFromPref();
     if (last_state && last_state->is_locked) {
       OnScreenLockByPolicy(last_state->active_policy,
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.h b/chrome/browser/chromeos/child_accounts/screen_time_controller.h
index e03f4401..99c9c39 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.h
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.h
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
+#include "base/optional.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h"
 #include "chrome/browser/chromeos/child_accounts/time_limit_notifier.h"
@@ -44,7 +45,7 @@
 // Schedule notifications and lock/unlock screen based on the processor output.
 class ScreenTimeController
     : public KeyedService,
-      public parent_access::ParentAccessService::Delegate,
+      public parent_access::ParentAccessService::Observer,
       public session_manager::SessionManagerObserver,
       public UsageTimeStateNotifier::Observer,
       public system::TimezoneSettings::Observer,
@@ -67,9 +68,6 @@
   // used the device today (since the last reset).
   virtual base::TimeDelta GetScreenTimeDuration();
 
-  // parent_access::ParentAccessService::Delegate:
-  void OnAccessCodeValidation(bool result) override;
-
   // Method intended for testing purposes only.
   void SetClocksForTesting(
       const base::Clock* clock,
@@ -134,9 +132,9 @@
   base::Optional<TimeLimitNotifier::LimitType> ConvertPolicyType(
       usage_time_limit::PolicyType policy_type);
 
-  // Initializes parent access service if it does not already exist. It requires
-  // LoginScreenClient to be created.
-  void InitializeParentAccessServiceIfNeeded();
+  // parent_access::ParentAccessService::Observer:
+  void OnAccessCodeValidation(bool result,
+                              base::Optional<AccountId> account_id) override;
 
   // session_manager::SessionManagerObserver:
   void OnSessionStateChanged() override;
@@ -159,10 +157,6 @@
   // Points to the base::DefaultClock by default.
   const base::Clock* clock_;
 
-  // Validates parent access codes. Informs registered delegate about validation
-  // results.
-  std::unique_ptr<parent_access::ParentAccessService> parent_access_service_;
-
   // Timer scheduled for when the next lock screen state change event is
   // expected to happen, e.g. when bedtime is over or the usage limit ends.
   std::unique_ptr<base::OneShotTimer> next_state_timer_;
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index c40bb2af..78fec01 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -57,7 +57,6 @@
 #include "chrome/browser/chromeos/dbus/screen_lock_service_provider.h"
 #include "chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h"
 #include "chrome/browser/chromeos/dbus/vm_applications_service_provider.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.h"
 #include "chrome/browser/chromeos/display/quirks_manager_delegate_impl.h"
 #include "chrome/browser/chromeos/events/event_rewriter_delegate_impl.h"
 #include "chrome/browser/chromeos/extensions/default_app_order.h"
@@ -106,6 +105,7 @@
 #include "chrome/browser/chromeos/system/user_removal_manager.h"
 #include "chrome/browser/chromeos/ui/low_disk_notification.h"
 #include "chrome/browser/chromeos/usb/cros_usb_detector.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -704,7 +704,7 @@
 
   g_browser_process->platform_part()->InitializeChromeUserManager();
 
-  diagnosticsd_manager_ = std::make_unique<DiagnosticsdManager>();
+  wilco_dtc_supportd_manager_ = std::make_unique<WilcoDtcSupportdManager>();
 
   ScreenLocker::InitClass();
 
@@ -1111,10 +1111,10 @@
   user_activity_controller_.reset();
   adaptive_screen_brightness_manager_.reset();
   scheduler_configuration_manager_.reset();
-  diagnosticsd_manager_.reset();
   auto_screen_brightness_controller_.reset();
   dark_resume_controller_.reset();
   lock_to_single_user_manager_.reset();
+  wilco_dtc_supportd_manager_.reset();
 
   // Detach D-Bus clients before DBusThreadManager is shut down.
   idle_action_warning_observer_.reset();
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index b10e4ee1..c24b1a4 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -40,7 +40,6 @@
 class ArcKioskAppManager;
 class CrosUsbDetector;
 class DemoModeResourcesRemover;
-class DiagnosticsdManager;
 class DiscoverManager;
 class EventRewriterDelegateImpl;
 class FastTransitionObserver;
@@ -55,6 +54,7 @@
 class SessionTerminationManager;
 class ShutdownPolicyForwarder;
 class WakeOnWifiManager;
+class WilcoDtcSupportdManager;
 
 namespace default_app_order {
 class ExternalLoader;
@@ -165,13 +165,13 @@
       scheduler_configuration_manager_;
 
   std::unique_ptr<CrosUsbDetector> cros_usb_detector_;
-  std::unique_ptr<DiagnosticsdManager> diagnosticsd_manager_;
 
   std::unique_ptr<chromeos::system::DarkResumeController>
       dark_resume_controller_;
 
   std::unique_ptr<SessionTerminationManager> session_termination_manager_;
   std::unique_ptr<policy::LockToSingleUserManager> lock_to_single_user_manager_;
+  std::unique_ptr<WilcoDtcSupportdManager> wilco_dtc_supportd_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsChromeos);
 };
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.cc b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.cc
deleted file mode 100644
index bc6b7dc3..0000000
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.cc
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/shared_memory.h"
-#include "base/process/process_handle.h"
-#include "base/strings/string_piece.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.h"
-#include "chrome/browser/chromeos/diagnosticsd/mojo_utils.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/diagnosticsd_client.h"
-#include "mojo/public/cpp/bindings/interface_ptr_info.h"
-#include "mojo/public/cpp/platform/platform_channel.h"
-#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
-#include "mojo/public/cpp/platform/platform_handle.h"
-#include "mojo/public/cpp/system/invitation.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "third_party/cros_system_api/dbus/diagnosticsd/dbus-constants.h"
-
-namespace chromeos {
-
-namespace {
-
-// Interval used between successive connection attempts to the diagnosticsd.
-// This is a safety measure for avoiding busy loops when the diagnosticsd is
-// dysfunctional.
-constexpr base::TimeDelta kConnectionAttemptInterval =
-    base::TimeDelta::FromSeconds(1);
-// The maximum number of consecutive connection attempts to the diagnosticsd
-// before giving up. This is to prevent wasting system resources on hopeless
-// attempts to connect in cases when the diagnosticsd is dysfunctional.
-constexpr int kMaxConnectionAttemptCount = 10;
-
-DiagnosticsdBridge* g_diagnosticsd_bridge_instance = nullptr;
-
-// Real implementation of the DiagnosticsdBridge delegate.
-class DiagnosticsdBridgeDelegateImpl final
-    : public DiagnosticsdBridge::Delegate {
- public:
-  DiagnosticsdBridgeDelegateImpl();
-  ~DiagnosticsdBridgeDelegateImpl() override;
-
-  // Delegate overrides:
-  void CreateDiagnosticsdServiceFactoryMojoInvitation(
-      diagnosticsd::mojom::DiagnosticsdServiceFactoryPtr*
-          diagnosticsd_service_factory_mojo_ptr,
-      base::ScopedFD* remote_endpoint_fd) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdBridgeDelegateImpl);
-};
-
-DiagnosticsdBridgeDelegateImpl::DiagnosticsdBridgeDelegateImpl() = default;
-
-DiagnosticsdBridgeDelegateImpl::~DiagnosticsdBridgeDelegateImpl() = default;
-
-void DiagnosticsdBridgeDelegateImpl::
-    CreateDiagnosticsdServiceFactoryMojoInvitation(
-        diagnosticsd::mojom::DiagnosticsdServiceFactoryPtr*
-            diagnosticsd_service_factory_mojo_ptr,
-        base::ScopedFD* remote_endpoint_fd) {
-  mojo::OutgoingInvitation invitation;
-  mojo::PlatformChannel channel;
-  mojo::ScopedMessagePipeHandle server_pipe = invitation.AttachMessagePipe(
-      diagnostics::kDiagnosticsdMojoConnectionChannelToken);
-  mojo::OutgoingInvitation::Send(std::move(invitation),
-                                 base::kNullProcessHandle,
-                                 channel.TakeLocalEndpoint());
-  diagnosticsd_service_factory_mojo_ptr->Bind(
-      mojo::InterfacePtrInfo<diagnosticsd::mojom::DiagnosticsdServiceFactory>(
-          std::move(server_pipe), 0 /* version */));
-  *remote_endpoint_fd =
-      channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD();
-}
-
-}  // namespace
-
-DiagnosticsdBridge::Delegate::~Delegate() = default;
-
-// static
-DiagnosticsdBridge* DiagnosticsdBridge::Get() {
-  return g_diagnosticsd_bridge_instance;
-}
-
-// static
-base::TimeDelta DiagnosticsdBridge::connection_attempt_interval_for_testing() {
-  return kConnectionAttemptInterval;
-}
-
-// static
-int DiagnosticsdBridge::max_connection_attempt_count_for_testing() {
-  return kMaxConnectionAttemptCount;
-}
-
-DiagnosticsdBridge::DiagnosticsdBridge(
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
-    : DiagnosticsdBridge(std::make_unique<DiagnosticsdBridgeDelegateImpl>(),
-                         std::move(url_loader_factory)) {}
-
-DiagnosticsdBridge::DiagnosticsdBridge(
-    std::unique_ptr<Delegate> delegate,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
-    : delegate_(std::move(delegate)),
-      web_request_service_(std::move(url_loader_factory)) {
-  DCHECK(delegate_);
-  DCHECK(!g_diagnosticsd_bridge_instance);
-  g_diagnosticsd_bridge_instance = this;
-  WaitForDBusService();
-}
-
-DiagnosticsdBridge::~DiagnosticsdBridge() {
-  DCHECK_EQ(g_diagnosticsd_bridge_instance, this);
-  g_diagnosticsd_bridge_instance = nullptr;
-}
-
-void DiagnosticsdBridge::SetConfigurationData(const std::string* data) {
-  configuration_data_ = data;
-}
-
-const std::string& DiagnosticsdBridge::GetConfigurationDataForTesting() {
-  return configuration_data_ ? *configuration_data_ : base::EmptyString();
-}
-
-void DiagnosticsdBridge::WaitForDBusService() {
-  if (connection_attempt_ >= kMaxConnectionAttemptCount) {
-    DLOG(WARNING) << "Stopping attempts to connect to diagnosticsd - too many "
-                     "unsuccessful attempts in a row";
-    return;
-  }
-  ++connection_attempt_;
-
-  // Cancel any tasks previously created from WaitForDBusService() or
-  // ScheduleWaitingForDBusService().
-  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
-
-  DBusThreadManager::Get()
-      ->GetDiagnosticsdClient()
-      ->WaitForServiceToBeAvailable(
-          base::BindOnce(&DiagnosticsdBridge::OnWaitedForDBusService,
-                         dbus_waiting_weak_ptr_factory_.GetWeakPtr()));
-}
-
-void DiagnosticsdBridge::ScheduleWaitingForDBusService() {
-  // Cancel any tasks previously created from WaitForDBusService() or
-  // ScheduleWaitingForDBusService().
-  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
-
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&DiagnosticsdBridge::WaitForDBusService,
-                     dbus_waiting_weak_ptr_factory_.GetWeakPtr()),
-      kConnectionAttemptInterval);
-}
-
-void DiagnosticsdBridge::OnWaitedForDBusService(bool service_is_available) {
-  if (!service_is_available) {
-    DLOG(WARNING) << "The diagnosticsd D-Bus service is unavailable";
-    return;
-  }
-
-  // Cancel any tasks previously created from WaitForDBusService() or
-  // ScheduleWaitingForDBusService().
-  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
-
-  BootstrapMojoConnection();
-}
-
-void DiagnosticsdBridge::BootstrapMojoConnection() {
-  DCHECK(!diagnosticsd_service_factory_mojo_ptr_);
-
-  // Create a Mojo message pipe and attach
-  // |diagnosticsd_service_factory_mojo_ptr_| to its local endpoint.
-  base::ScopedFD remote_endpoint_fd;
-  delegate_->CreateDiagnosticsdServiceFactoryMojoInvitation(
-      &diagnosticsd_service_factory_mojo_ptr_, &remote_endpoint_fd);
-  DCHECK(diagnosticsd_service_factory_mojo_ptr_);
-  DCHECK(remote_endpoint_fd.is_valid());
-  diagnosticsd_service_factory_mojo_ptr_.set_connection_error_handler(
-      base::BindOnce(&DiagnosticsdBridge::OnMojoConnectionError,
-                     weak_ptr_factory_.GetWeakPtr()));
-
-  // Queue a call that would establish full-duplex Mojo communication with the
-  // diagnosticsd daemon by sending an interface pointer to the self instance.
-  mojo_self_binding_.Close();
-  diagnosticsd::mojom::DiagnosticsdClientPtr self_proxy;
-  mojo_self_binding_.Bind(mojo::MakeRequest(&self_proxy));
-  diagnosticsd_service_factory_mojo_ptr_->GetService(
-      mojo::MakeRequest(&diagnosticsd_service_mojo_ptr_), std::move(self_proxy),
-      base::BindOnce(&DiagnosticsdBridge::OnMojoGetServiceCompleted,
-                     weak_ptr_factory_.GetWeakPtr()));
-
-  // Send the file descriptor with the Mojo message pipe's remote endpoint to
-  // the diagnosticsd daemon via the D-Bus.
-  DBusThreadManager::Get()->GetDiagnosticsdClient()->BootstrapMojoConnection(
-      std::move(remote_endpoint_fd),
-      base::BindOnce(&DiagnosticsdBridge::OnBootstrappedMojoConnection,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void DiagnosticsdBridge::OnBootstrappedMojoConnection(bool success) {
-  if (success)
-    return;
-  DLOG(ERROR) << "Failed to establish Mojo connection to diagnosticsd";
-  diagnosticsd_service_factory_mojo_ptr_.reset();
-  diagnosticsd_service_mojo_ptr_.reset();
-  ScheduleWaitingForDBusService();
-}
-
-void DiagnosticsdBridge::OnMojoGetServiceCompleted() {
-  DCHECK(diagnosticsd_service_mojo_ptr_);
-  DVLOG(0) << "Established Mojo communication with diagnosticsd";
-  // Reset the current connection attempt counter, since a successful
-  // initialization of Mojo communication has completed.
-  connection_attempt_ = 0;
-}
-
-void DiagnosticsdBridge::OnMojoConnectionError() {
-  DLOG(WARNING) << "Mojo connection to the diagnosticsd daemon got shut down";
-  diagnosticsd_service_factory_mojo_ptr_.reset();
-  diagnosticsd_service_mojo_ptr_.reset();
-  ScheduleWaitingForDBusService();
-}
-
-void DiagnosticsdBridge::PerformWebRequest(
-    diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod http_method,
-    mojo::ScopedHandle url,
-    std::vector<mojo::ScopedHandle> headers,
-    mojo::ScopedHandle request_body,
-    PerformWebRequestCallback callback) {
-  // Extract a GURL value from a ScopedHandle.
-  GURL gurl;
-  if (url.is_valid()) {
-    std::unique_ptr<base::SharedMemory> shared_memory;
-    gurl = GURL(GetStringPieceFromMojoHandle(std::move(url), &shared_memory));
-    if (!shared_memory) {
-      LOG(ERROR) << "Failed to read data from mojo handle";
-      std::move(callback).Run(
-          diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-          0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-      return;
-    }
-  }
-
-  // Extract headers from ScopedHandle's.
-  std::vector<base::StringPiece> header_contents;
-  std::vector<std::unique_ptr<base::SharedMemory>> shared_memories;
-  for (auto& header : headers) {
-    if (!header.is_valid()) {
-      header_contents.push_back("");
-      continue;
-    }
-    shared_memories.push_back(nullptr);
-    header_contents.push_back(GetStringPieceFromMojoHandle(
-        std::move(header), &shared_memories.back()));
-    if (!shared_memories.back()) {
-      LOG(ERROR) << "Failed to read data from mojo handle";
-      std::move(callback).Run(
-          diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-          0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-      return;
-    }
-  }
-
-  // Extract a string value from a ScopedHandle.
-  std::string request_body_content;
-  if (request_body.is_valid()) {
-    std::unique_ptr<base::SharedMemory> shared_memory;
-    request_body_content = std::string(
-        GetStringPieceFromMojoHandle(std::move(request_body), &shared_memory));
-    if (!shared_memory) {
-      LOG(ERROR) << "Failed to read data from mojo handle";
-      std::move(callback).Run(
-          diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-          0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-      return;
-    }
-  }
-
-  web_request_service_.PerformRequest(
-      http_method, std::move(gurl), std::move(header_contents),
-      std::move(request_body_content), std::move(callback));
-}
-
-void DiagnosticsdBridge::GetConfigurationData(
-    GetConfigurationDataCallback callback) {
-  std::move(callback).Run(configuration_data_ ? *configuration_data_
-                                              : std::string());
-}
-
-void DiagnosticsdBridge::SendDiagnosticsProcessorMessageToUi(
-    mojo::ScopedHandle json_message,
-    SendDiagnosticsProcessorMessageToUiCallback callback) {
-  // Extract the string value of the received message.
-  DCHECK(json_message);
-  std::unique_ptr<base::SharedMemory> json_message_shared_memory;
-  base::StringPiece json_message_string = GetStringPieceFromMojoHandle(
-      std::move(json_message), &json_message_shared_memory);
-  if (json_message_string.empty()) {
-    LOG(ERROR) << "Failed to read data from mojo handle";
-    std::move(callback).Run(mojo::ScopedHandle() /* response_json_message */);
-    return;
-  }
-
-  DeliverDiagnosticsdUiMessageToExtensions(
-      json_message_string.as_string(),
-      base::BindOnce(
-          [](SendDiagnosticsProcessorMessageToUiCallback callback,
-             const std::string& response) {
-            mojo::ScopedHandle response_mojo_handle;
-            if (!response.empty()) {
-              response_mojo_handle =
-                  CreateReadOnlySharedMemoryMojoHandle(response);
-              if (!response_mojo_handle)
-                LOG(ERROR) << "Failed to create mojo handle for string";
-            }
-            std::move(callback).Run(std::move(response_mojo_handle));
-          },
-          std::move(callback)));
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h
deleted file mode 100644
index 33ff8c6..0000000
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_BRIDGE_H_
-#define CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_BRIDGE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/files/scoped_file.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.h"
-#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/system/buffer.h"
-
-namespace network {
-class SharedURLLoaderFactory;
-}  // namespace network
-
-namespace chromeos {
-
-// Establishes Mojo communication to the diagnosticsd daemon. The Mojo pipe gets
-// bootstrapped via D-Bus, and the class takes care of waiting until the
-// diagnosticsd D-Bus service gets started and of repeating the bootstrapping
-// after the daemon gets restarted.
-class DiagnosticsdBridge final
-    : public diagnosticsd::mojom::DiagnosticsdClient {
- public:
-  // Delegate class, allowing to stub out unwanted operations in unit tests.
-  class Delegate {
-   public:
-    virtual ~Delegate();
-
-    // Creates a Mojo invitation that requests the remote implementation of the
-    // DiagnosticsdServiceFactory interface.
-    // Returns |diagnosticsd_service_factory_mojo_ptr| - interface pointer that
-    // points to the remote implementation of the interface,
-    // |remote_endpoint_fd| - file descriptor of the remote endpoint to be sent.
-    virtual void CreateDiagnosticsdServiceFactoryMojoInvitation(
-        diagnosticsd::mojom::DiagnosticsdServiceFactoryPtr*
-            diagnosticsd_service_factory_mojo_ptr,
-        base::ScopedFD* remote_endpoint_fd) = 0;
-  };
-
-  // Returns the global singleton instance.
-  static DiagnosticsdBridge* Get();
-
-  static base::TimeDelta connection_attempt_interval_for_testing();
-  static int max_connection_attempt_count_for_testing();
-
-  explicit DiagnosticsdBridge(
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
-  // For use in tests.
-  DiagnosticsdBridge(
-      std::unique_ptr<Delegate> delegate,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
-
-  ~DiagnosticsdBridge() override;
-
-  // Sets the Wilco DTC configuration data, passed and owned by the
-  // |DiagnosticsdManager| from the device policy.
-  // The nullptr should be passed to clear it.
-  void SetConfigurationData(const std::string* data);
-  const std::string& GetConfigurationDataForTesting();
-
-  // Mojo proxy to the DiagnosticsdService implementation in the diagnosticsd
-  // daemon. Returns null when bootstrapping of Mojo connection hasn't started
-  // yet. Note that, however, non-null is already returned before the
-  // bootstrapping fully completes.
-  diagnosticsd::mojom::DiagnosticsdServiceProxy*
-  diagnosticsd_service_mojo_proxy() {
-    return diagnosticsd_service_mojo_ptr_ ? diagnosticsd_service_mojo_ptr_.get()
-                                          : nullptr;
-  }
-
- private:
-  // Starts waiting until the diagnosticsd D-Bus service becomes available (or
-  // until this waiting fails).
-  void WaitForDBusService();
-  // Schedules a postponed execution of WaitForDBusService().
-  void ScheduleWaitingForDBusService();
-  // Called once waiting for the D-Bus service, started by WaitForDBusService(),
-  // finishes.
-  void OnWaitedForDBusService(bool service_is_available);
-  // Triggers Mojo bootstrapping via a D-Bus to the diagnosticsd daemon.
-  void BootstrapMojoConnection();
-  // Called once the result of the D-Bus call, made from
-  // BootstrapMojoConnection(), arrives.
-  void OnBootstrappedMojoConnection(bool success);
-  // Called once the GetService() Mojo request completes.
-  void OnMojoGetServiceCompleted();
-  // Called when Mojo signals a connection error.
-  void OnMojoConnectionError();
-
-  // diagnosticsd::mojom::DiagnosticsdClient overrides.
-  void PerformWebRequest(
-      diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod http_method,
-      mojo::ScopedHandle url,
-      std::vector<mojo::ScopedHandle> headers,
-      mojo::ScopedHandle request_body,
-      PerformWebRequestCallback callback) override;
-  void SendDiagnosticsProcessorMessageToUi(
-      mojo::ScopedHandle json_message,
-      SendDiagnosticsProcessorMessageToUiCallback callback) override;
-  void GetConfigurationData(GetConfigurationDataCallback callback) override;
-
-  std::unique_ptr<Delegate> delegate_;
-
-  // Mojo binding that binds |this| as an implementation of the
-  // DiagnosticsdClient Mojo interface.
-  mojo::Binding<diagnosticsd::mojom::DiagnosticsdClient> mojo_self_binding_{
-      this};
-
-  // Current consecutive connection attempt number.
-  int connection_attempt_ = 0;
-
-  // Interface pointers to the Mojo services exposed by the diagnosticsd daemon.
-  diagnosticsd::mojom::DiagnosticsdServiceFactoryPtr
-      diagnosticsd_service_factory_mojo_ptr_;
-  diagnosticsd::mojom::DiagnosticsdServicePtr diagnosticsd_service_mojo_ptr_;
-
-  // The service to perform diagnostics_processor's web requests.
-  DiagnosticsdWebRequestService web_request_service_;
-
-  // The Wilco DTC configuration data blob, passed from the device policy, is
-  // stored and owned by |DiagnosticsdManager|.
-  // nullptr if there is no available configuration data for the Wilco DTC.
-  const std::string* configuration_data_ = nullptr;
-
-  // These weak pointer factories must be the last members:
-
-  // Used for cancelling previously posted tasks that wait for the D-Bus service
-  // availability.
-  base::WeakPtrFactory<DiagnosticsdBridge> dbus_waiting_weak_ptr_factory_{this};
-  base::WeakPtrFactory<DiagnosticsdBridge> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdBridge);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_BRIDGE_H_
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge_unittest.cc b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge_unittest.cc
deleted file mode 100644
index 88c8368..0000000
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge_unittest.cc
+++ /dev/null
@@ -1,396 +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 <unistd.h>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/optional.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/test/scoped_task_environment.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h"
-#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_diagnosticsd_client.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/system/handle.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromeos {
-
-namespace {
-
-class MockMojoDiagnosticsdService
-    : public diagnosticsd::mojom::DiagnosticsdService {
- public:
-  MOCK_METHOD2(SendUiMessageToDiagnosticsProcessor,
-               void(mojo::ScopedHandle,
-                    SendUiMessageToDiagnosticsProcessorCallback));
-  MOCK_METHOD0(NotifyConfigurationDataChanged, void());
-};
-
-// Fake implementation of the DiagnosticsdServiceFactory Mojo interface that
-// holds up method calls and allows to complete them afterwards.
-class FakeMojoDiagnosticsdServiceFactory final
-    : public diagnosticsd::mojom::DiagnosticsdServiceFactory {
- public:
-  // DiagnosticsdServiceFactory overrides:
-
-  void GetService(diagnosticsd::mojom::DiagnosticsdServiceRequest service,
-                  diagnosticsd::mojom::DiagnosticsdClientPtr client,
-                  GetServiceCallback callback) override {
-    EXPECT_FALSE(pending_get_service_call_);
-    pending_get_service_call_ = PendingGetServiceCall{
-        std::move(service), std::move(client), std::move(callback)};
-  }
-
-  // Completes the Mojo binding of this instance to the given Mojo interface
-  // request.
-  void Bind(diagnosticsd::mojom::DiagnosticsdServiceFactoryRequest request) {
-    // Close the Mojo binding in case it was previously completed, to allow
-    // calling this method multiple times.
-    self_binding_.Close();
-
-    self_binding_.Bind(std::move(request));
-
-    self_binding_.set_connection_error_handler(
-        base::BindOnce(&FakeMojoDiagnosticsdServiceFactory::OnBindingError,
-                       base::Unretained(this)));
-  }
-
-  // Closes the Mojo binding of this instance.
-  void CloseBinding() {
-    self_binding_.Close();
-
-    // Drop the current pending GetService call, if there was any, to allow our
-    // instance to be used for new GetService calls after this instance gets
-    // bound again.
-    pending_get_service_call_.reset();
-  }
-
-  // Whether there's a pending GetService call.
-  bool is_get_service_call_in_flight() const {
-    return pending_get_service_call_.has_value();
-  }
-
-  // Respond to the current pending GetService call.
-  diagnosticsd::mojom::DiagnosticsdClientPtr RespondToGetServiceCall(
-      mojo::Binding<diagnosticsd::mojom::DiagnosticsdService>*
-          mojo_diagnosticsd_service_binding) {
-    DCHECK(pending_get_service_call_);
-    PendingGetServiceCall pending_call = std::move(*pending_get_service_call_);
-    pending_get_service_call_.reset();
-    mojo_diagnosticsd_service_binding->Bind(std::move(pending_call.service));
-    std::move(pending_call.callback).Run();
-    return std::move(pending_call.client);
-  }
-
- private:
-  struct PendingGetServiceCall {
-    diagnosticsd::mojom::DiagnosticsdServiceRequest service;
-    diagnosticsd::mojom::DiagnosticsdClientPtr client;
-    GetServiceCallback callback;
-  };
-
-  void OnBindingError() {
-    // Drop the current pending GetService call, if there was any, to allow our
-    // instance to be used for new GetService calls after this instance gets
-    // bound again.
-    pending_get_service_call_.reset();
-  }
-
-  mojo::Binding<diagnosticsd::mojom::DiagnosticsdServiceFactory> self_binding_{
-      this};
-
-  base::Optional<PendingGetServiceCall> pending_get_service_call_;
-};
-
-// Fake implementation of the DiagnosticsdBridge delegate that simulates Mojo
-// operations that are impossible in the unit test.
-class FakeDiagnosticsdBridgeDelegate final
-    : public DiagnosticsdBridge::Delegate {
- public:
-  explicit FakeDiagnosticsdBridgeDelegate(
-      FakeMojoDiagnosticsdServiceFactory* mojo_diagnosticsd_service_factory)
-      : mojo_diagnosticsd_service_factory_(mojo_diagnosticsd_service_factory) {}
-
-  void CreateDiagnosticsdServiceFactoryMojoInvitation(
-      diagnosticsd::mojom::DiagnosticsdServiceFactoryPtr*
-          diagnosticsd_service_factory_mojo_ptr,
-      base::ScopedFD* remote_endpoint_fd) override {
-    // Bind the Mojo pointer passed to the bridge with the
-    // FakeMojoDiagnosticsdServiceFactory implementation.
-    mojo_diagnosticsd_service_factory_->Bind(
-        mojo::MakeRequest(diagnosticsd_service_factory_mojo_ptr));
-
-    // Return a fake file descriptor - its value is not used in the unit test
-    // environment for anything except comparing with zero.
-    remote_endpoint_fd->reset(HANDLE_EINTR(dup(STDIN_FILENO)));
-    DCHECK(remote_endpoint_fd->is_valid());
-  }
-
- private:
-  FakeMojoDiagnosticsdServiceFactory* const mojo_diagnosticsd_service_factory_;
-};
-
-// Tests for the DiagnosticsdBridge class.
-class DiagnosticsdBridgeTest : public testing::Test {
- protected:
-  DiagnosticsdBridgeTest() {
-    DBusThreadManager::Initialize();
-    CHECK(DBusThreadManager::Get()->IsUsingFakes());
-
-    diagnosticsd_bridge_ = std::make_unique<DiagnosticsdBridge>(
-        std::make_unique<FakeDiagnosticsdBridgeDelegate>(
-            &mojo_diagnosticsd_service_factory_),
-        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-            &test_url_loader_factory_));
-  }
-
-  ~DiagnosticsdBridgeTest() override {
-    diagnosticsd_bridge_.reset();
-    DBusThreadManager::Shutdown();
-  }
-
-  DiagnosticsdBridge* diagnosticsd_bridge() {
-    return diagnosticsd_bridge_.get();
-  }
-
-  FakeDiagnosticsdClient* diagnosticsd_dbus_client() {
-    DiagnosticsdClient* const diagnosticsd_client =
-        DBusThreadManager::Get()->GetDiagnosticsdClient();
-    DCHECK(diagnosticsd_client);
-    return static_cast<FakeDiagnosticsdClient*>(diagnosticsd_client);
-  }
-
-  // Whether there's a pending GetService Mojo call held up by the fake.
-  bool is_mojo_factory_get_service_call_in_flight() const {
-    return mojo_diagnosticsd_service_factory_.is_get_service_call_in_flight();
-  }
-
-  // Reply to the pending GetService Mojo call held up by the fake.
-  void RespondToMojoFactoryGetServiceCall() {
-    // Close the binding, if it was completed, to allow calling this method
-    // multiple times.
-    mojo_diagnosticsd_service_binding_.Close();
-
-    mojo_diagnosticsd_client_ =
-        mojo_diagnosticsd_service_factory_.RespondToGetServiceCall(
-            &mojo_diagnosticsd_service_binding_);
-  }
-
-  // Simulates Mojo connection error.
-  void AbortMojoConnection() {
-    mojo_diagnosticsd_service_factory_.CloseBinding();
-  }
-
-  base::test::ScopedTaskEnvironment scoped_task_environment_{
-      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
-
- private:
-  FakeMojoDiagnosticsdServiceFactory mojo_diagnosticsd_service_factory_;
-
-  MockMojoDiagnosticsdService mojo_diagnosticsd_service_;
-  mojo::Binding<diagnosticsd::mojom::DiagnosticsdService>
-      mojo_diagnosticsd_service_binding_{&mojo_diagnosticsd_service_};
-
-  std::unique_ptr<DiagnosticsdBridge> diagnosticsd_bridge_;
-
-  diagnosticsd::mojom::DiagnosticsdClientPtr mojo_diagnosticsd_client_;
-  network::TestURLLoaderFactory test_url_loader_factory_;
-};
-
-}  // namespace
-
-// Test successful Mojo bootstrapping scenario.
-TEST_F(DiagnosticsdBridgeTest, SuccessfulBootstrap) {
-  // Initially the bridge is blocked on the WaitForServiceToBeAvailable call.
-  EXPECT_EQ(1, diagnosticsd_dbus_client()
-                   ->wait_for_service_to_be_available_in_flight_call_count());
-  EXPECT_FALSE(diagnosticsd_dbus_client()
-                   ->bootstrap_mojo_connection_in_flight_call_count());
-
-  // Resolve the pending WaitForServiceToBeAvailable call. Verify the bridge
-  // makes the BootstrapMojoConnection D-Bus call.
-  diagnosticsd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
-  EXPECT_EQ(1, diagnosticsd_dbus_client()
-                   ->bootstrap_mojo_connection_in_flight_call_count());
-
-  // Resolve the pending BootstrapMojoConnection D-Bus call (but then revert the
-  // fake in order to hold up its subsequent calls). Verify the bridge makes the
-  // GetService Mojo call on the DiagnosticsdServiceFactory interface.
-  diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(true);
-  diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(base::nullopt);
-  scoped_task_environment_.RunUntilIdle();
-  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
-
-  // Resolve the pending GetService Mojo call. Verify the bridge exposes the
-  // obtained DiagnosticsdService Mojo interface pointer.
-  RespondToMojoFactoryGetServiceCall();
-  scoped_task_environment_.RunUntilIdle();
-  EXPECT_TRUE(diagnosticsd_bridge()->diagnosticsd_service_mojo_proxy());
-
-  // Verify that no extra D-Bus or Mojo calls are made.
-  EXPECT_FALSE(diagnosticsd_dbus_client()
-                   ->bootstrap_mojo_connection_in_flight_call_count());
-  EXPECT_FALSE(is_mojo_factory_get_service_call_in_flight());
-}
-
-// Test the case when the D-Bus service is permanently unavailable - the bridge
-// should be just blocked on a single WaitForServiceToBeAvailable call.
-TEST_F(DiagnosticsdBridgeTest, DBusServiceNotBringingUpError) {
-  EXPECT_EQ(1, diagnosticsd_dbus_client()
-                   ->wait_for_service_to_be_available_in_flight_call_count());
-
-  // Verify that no extra WaitForServiceToBeAvailable calls are made.
-  scoped_task_environment_.FastForwardBy(
-      DiagnosticsdBridge::connection_attempt_interval_for_testing());
-  EXPECT_EQ(1, diagnosticsd_dbus_client()
-                   ->wait_for_service_to_be_available_in_flight_call_count());
-}
-
-// Test the case when the BootstrapMojoConnection D-Bus method fails
-// permanently - the bridge should give up making attempts after a few retries.
-TEST_F(DiagnosticsdBridgeTest, DBusBootstrapMojoConnectionError) {
-  diagnosticsd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
-
-  for (int attempt_number = 0;
-       attempt_number <
-       DiagnosticsdBridge::max_connection_attempt_count_for_testing();
-       ++attempt_number) {
-    // Fail the pending BootstrapMojoConnection call, but then revert the fake
-    // in order to hold up its subsequent calls.
-    EXPECT_EQ(1, diagnosticsd_dbus_client()
-                     ->bootstrap_mojo_connection_in_flight_call_count());
-    diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(false);
-    diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(base::nullopt);
-    scoped_task_environment_.RunUntilIdle();
-
-    // Verify that no new BootstrapMojoConnection call is made immediately after
-    // the previous one failed.
-    EXPECT_FALSE(diagnosticsd_dbus_client()
-                     ->bootstrap_mojo_connection_in_flight_call_count());
-
-    // Fast forward the clock till the next attempt should occur.
-    scoped_task_environment_.FastForwardBy(
-        DiagnosticsdBridge::connection_attempt_interval_for_testing());
-  }
-
-  // No new BootstrapMojoConnection calls are made after the retry limit
-  // exceeded.
-  EXPECT_FALSE(diagnosticsd_dbus_client()
-                   ->bootstrap_mojo_connection_in_flight_call_count());
-}
-
-// Test the case when the Mojo connection gets aborted before the first Mojo
-// call (GetService on the DiagnosticsdServiceFactory interface) completes - the
-// bridge should give up making attempts after a few retries.
-TEST_F(DiagnosticsdBridgeTest, ImmediateMojoDisconnectionError) {
-  diagnosticsd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
-  diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(true);
-  scoped_task_environment_.RunUntilIdle();
-
-  for (int attempt_number = 0;
-       attempt_number <
-       DiagnosticsdBridge::max_connection_attempt_count_for_testing();
-       ++attempt_number) {
-    // Verify that the bridge made the GetService Mojo call (on the
-    // DiagnosticsdServiceFactory interface). Abort the Mojo binding without
-    // responding to the call. Verify that no new call happens immediately.
-    EXPECT_TRUE(is_mojo_factory_get_service_call_in_flight());
-    AbortMojoConnection();
-    scoped_task_environment_.RunUntilIdle();
-    EXPECT_FALSE(is_mojo_factory_get_service_call_in_flight());
-
-    // Fast forward the clock till the next attempt should occur.
-    scoped_task_environment_.FastForwardBy(
-        DiagnosticsdBridge::connection_attempt_interval_for_testing());
-  }
-
-  // No new connection attempts are made after the retry limit exceeded.
-  EXPECT_FALSE(is_mojo_factory_get_service_call_in_flight());
-}
-
-// Test that the Mojo connection gets bootstrapped again after the previous one
-// got aborted.
-TEST_F(DiagnosticsdBridgeTest, Reestablishing) {
-  // Let the bootstrapping succeed on the first attempt.
-  diagnosticsd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
-  diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(true);
-  scoped_task_environment_.RunUntilIdle();
-  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
-  RespondToMojoFactoryGetServiceCall();
-  scoped_task_environment_.RunUntilIdle();
-  EXPECT_TRUE(diagnosticsd_bridge()->diagnosticsd_service_mojo_proxy());
-
-  // Abort the Mojo binding. Verify that no new connection attempt happens
-  // immediately.
-  AbortMojoConnection();
-  scoped_task_environment_.RunUntilIdle();
-  EXPECT_FALSE(diagnosticsd_bridge()->diagnosticsd_service_mojo_proxy());
-  EXPECT_FALSE(is_mojo_factory_get_service_call_in_flight());
-
-  // Fast forward the clock till the next connection attempt.
-  scoped_task_environment_.FastForwardBy(
-      DiagnosticsdBridge::connection_attempt_interval_for_testing());
-
-  // Let the bootstrapping succeed again.
-  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
-  RespondToMojoFactoryGetServiceCall();
-  scoped_task_environment_.RunUntilIdle();
-  EXPECT_TRUE(diagnosticsd_bridge()->diagnosticsd_service_mojo_proxy());
-}
-
-// Test that the bridge resets its retry counter after a successful
-// bootstrapping takes place.
-TEST_F(DiagnosticsdBridgeTest, RetryCounterReset) {
-  diagnosticsd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
-
-  // Fail the first few connection attempts, leaving only one attempt left.
-  diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(false);
-  scoped_task_environment_.FastForwardBy(
-      DiagnosticsdBridge::connection_attempt_interval_for_testing() *
-      (DiagnosticsdBridge::max_connection_attempt_count_for_testing() - 2));
-
-  // Let the bootstrapping succeed on the new attempt (the last allowed one in
-  // this serie).
-  diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(true);
-  scoped_task_environment_.FastForwardBy(
-      DiagnosticsdBridge::connection_attempt_interval_for_testing());
-  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
-  RespondToMojoFactoryGetServiceCall();
-  scoped_task_environment_.RunUntilIdle();
-  EXPECT_TRUE(diagnosticsd_bridge()->diagnosticsd_service_mojo_proxy());
-
-  // Abort the Mojo binding.
-  AbortMojoConnection();
-  scoped_task_environment_.RunUntilIdle();
-  EXPECT_FALSE(diagnosticsd_bridge()->diagnosticsd_service_mojo_proxy());
-
-  // Fail again a few attempts as before.
-  diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(false);
-  scoped_task_environment_.FastForwardBy(
-      DiagnosticsdBridge::connection_attempt_interval_for_testing() *
-      (DiagnosticsdBridge::max_connection_attempt_count_for_testing() - 1));
-
-  // Let the bootstrapping succeed again as before. Note that this verifies that
-  // the retry attempts made before the previous successful bootstrap were
-  // ignored.
-  diagnosticsd_dbus_client()->SetBootstrapMojoConnectionResult(true);
-  scoped_task_environment_.FastForwardBy(
-      DiagnosticsdBridge::connection_attempt_interval_for_testing());
-  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
-  RespondToMojoFactoryGetServiceCall();
-  scoped_task_environment_.RunUntilIdle();
-  EXPECT_TRUE(diagnosticsd_bridge()->diagnosticsd_service_mojo_proxy());
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.cc b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.cc
deleted file mode 100644
index 755a11c..0000000
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h"
-#include "chrome/browser/net/system_network_context_manager.h"
-#include "chromeos/dbus/upstart/upstart_client.h"
-#include "components/session_manager/core/session_manager.h"
-#include "components/session_manager/session_manager_types.h"
-#include "components/user_manager/user.h"
-#include "components/user_manager/user_manager.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-
-namespace chromeos {
-
-namespace {
-
-DiagnosticsdManager* g_diagnosticsd_manager_instance = nullptr;
-
-class DiagnosticsdManagerDelegateImpl final
-    : public DiagnosticsdManager::Delegate {
- public:
-  DiagnosticsdManagerDelegateImpl();
-  ~DiagnosticsdManagerDelegateImpl() override;
-
-  // Delegate overrides:
-  std::unique_ptr<DiagnosticsdBridge> CreateDiagnosticsdBridge() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdManagerDelegateImpl);
-};
-
-DiagnosticsdManagerDelegateImpl::DiagnosticsdManagerDelegateImpl() = default;
-
-DiagnosticsdManagerDelegateImpl::~DiagnosticsdManagerDelegateImpl() = default;
-
-std::unique_ptr<DiagnosticsdBridge>
-DiagnosticsdManagerDelegateImpl::CreateDiagnosticsdBridge() {
-  return std::make_unique<DiagnosticsdBridge>(
-      g_browser_process->system_network_context_manager()
-          ->GetSharedURLLoaderFactory());
-}
-
-// Returns true if only affiliated users are logged-in.
-bool AreOnlyAffiliatedUsersLoggedIn() {
-  const user_manager::UserList logged_in_users =
-      user_manager::UserManager::Get()->GetLoggedInUsers();
-  for (user_manager::User* user : logged_in_users) {
-    if (!user->IsAffiliated()) {
-      return false;
-    }
-  }
-  return true;
-}
-
-}  // namespace
-
-DiagnosticsdManager::Delegate::~Delegate() = default;
-
-// static
-DiagnosticsdManager* DiagnosticsdManager::Get() {
-  return g_diagnosticsd_manager_instance;
-}
-
-DiagnosticsdManager::DiagnosticsdManager()
-    : DiagnosticsdManager(std::make_unique<DiagnosticsdManagerDelegateImpl>()) {
-}
-
-DiagnosticsdManager::DiagnosticsdManager(std::unique_ptr<Delegate> delegate)
-    : delegate_(std::move(delegate)),
-      callback_weak_ptr_factory_(this),
-      weak_ptr_factory_(this) {
-  DCHECK(delegate_);
-  DCHECK(!g_diagnosticsd_manager_instance);
-  g_diagnosticsd_manager_instance = this;
-  wilco_dtc_allowed_observer_ = CrosSettings::Get()->AddSettingsObserver(
-      kDeviceWilcoDtcAllowed,
-      base::BindRepeating(&DiagnosticsdManager::StartOrStopWilcoDtc,
-                          weak_ptr_factory_.GetWeakPtr()));
-
-  session_manager::SessionManager::Get()->AddObserver(this);
-
-  StartOrStopWilcoDtc();
-}
-
-DiagnosticsdManager::~DiagnosticsdManager() {
-  DCHECK_EQ(g_diagnosticsd_manager_instance, this);
-  g_diagnosticsd_manager_instance = nullptr;
-
-  // The destruction may mean that non-affiliated user is logging out.
-  StartOrStopWilcoDtc();
-
-  session_manager::SessionManager::Get()->RemoveObserver(this);
-}
-
-void DiagnosticsdManager::SetConfigurationData(
-    std::unique_ptr<std::string> data) {
-  configuration_data_ = std::move(data);
-
-  if (!diagnosticsd_bridge_) {
-    VLOG(0) << "Cannot send notification - no bridge to the daemon";
-    return;
-  }
-  diagnosticsd_bridge_->SetConfigurationData(configuration_data_.get());
-
-  diagnosticsd::mojom::DiagnosticsdServiceProxy* const diagnosticsd_mojo_proxy =
-      diagnosticsd_bridge_->diagnosticsd_service_mojo_proxy();
-  if (!diagnosticsd_mojo_proxy) {
-    VLOG(0) << "Cannot send message - Mojo connection to the daemon isn't "
-               "bootstrapped yet";
-    return;
-  }
-  diagnosticsd_mojo_proxy->NotifyConfigurationDataChanged();
-}
-
-void DiagnosticsdManager::OnSessionStateChanged() {
-  session_manager::SessionState session_state =
-      session_manager::SessionManager::Get()->session_state();
-  // The user is logged-in and the affiliation is set.
-  if (session_state == session_manager::SessionState::ACTIVE)
-    StartOrStopWilcoDtc();
-}
-
-void DiagnosticsdManager::StartOrStopWilcoDtc() {
-  callback_weak_ptr_factory_.InvalidateWeakPtrs();
-  bool wilco_dtc_allowed;
-  // Start wilco DTC support services only if logged-in users are affiliated
-  // and the wilco DTC is allowed by policy.
-  if (CrosSettings::Get()->GetBoolean(kDeviceWilcoDtcAllowed,
-                                      &wilco_dtc_allowed) &&
-      wilco_dtc_allowed && AreOnlyAffiliatedUsersLoggedIn()) {
-    StartWilcoDtc(base::BindOnce(&DiagnosticsdManager::OnStartWilcoDtc,
-                                 callback_weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    StopWilcoDtc(base::BindOnce(&DiagnosticsdManager::OnStopWilcoDtc,
-                                callback_weak_ptr_factory_.GetWeakPtr()));
-  }
-}
-
-void DiagnosticsdManager::StartWilcoDtc(WilcoDtcCallback callback) {
-  VLOG(1) << "Starting wilco DTC";
-  UpstartClient::Get()->StartWilcoDtcService(std::move(callback));
-}
-
-void DiagnosticsdManager::StopWilcoDtc(WilcoDtcCallback callback) {
-  VLOG(1) << "Stopping wilco DTC";
-  UpstartClient::Get()->StopWilcoDtcService(std::move(callback));
-}
-
-void DiagnosticsdManager::OnStartWilcoDtc(bool success) {
-  if (!success) {
-    DLOG(ERROR) << "Failed to start the wilco DTC";
-  } else {
-    VLOG(1) << "Wilco DTC started";
-    if (!diagnosticsd_bridge_)
-      diagnosticsd_bridge_ = delegate_->CreateDiagnosticsdBridge();
-    DCHECK(diagnosticsd_bridge_);
-
-    // Once the bridge is created, notify it about an available configuration
-    // data blob.
-    diagnosticsd_bridge_->SetConfigurationData(configuration_data_.get());
-  }
-}
-
-void DiagnosticsdManager::OnStopWilcoDtc(bool success) {
-  if (!success) {
-    DLOG(ERROR) << "Failed to stop wilco DTC";
-  } else {
-    VLOG(1) << "Wilco DTC stopped";
-    diagnosticsd_bridge_.reset();
-  }
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager_unittest.cc b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager_unittest.cc
deleted file mode 100644
index 2c0ab740..0000000
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager_unittest.cc
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.h"
-
-#include "base/barrier_closure.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.h"
-#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
-#include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
-#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
-#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/upstart/fake_upstart_client.h"
-#include "components/session_manager/core/session_manager.h"
-#include "components/session_manager/session_manager_types.h"
-#include "components/user_manager/scoped_user_manager.h"
-#include "components/user_manager/user_names.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::Invoke;
-using testing::StrictMock;
-
-namespace chromeos {
-
-namespace {
-
-// An implementation of Upstart Client that fakes a start/ stop of wilco DTC
-// services on StartWilcoDtcService() / StopWilcoDtcService() calls.
-class TestUpstartClient final : public FakeUpstartClient {
- public:
-  // FakeUpstartClient overrides:
-  void StartWilcoDtcService(
-      chromeos::VoidDBusMethodCallback callback) override {
-    std::move(callback).Run(true /* success */);
-  }
-
-  void StopWilcoDtcService(chromeos::VoidDBusMethodCallback callback) override {
-    std::move(callback).Run(true /* success */);
-  }
-};
-
-class MockMojoDiagnosticsdService
-    : public diagnosticsd::mojom::DiagnosticsdService {
- public:
-  MOCK_METHOD2(SendUiMessageToDiagnosticsProcessor,
-               void(mojo::ScopedHandle,
-                    SendUiMessageToDiagnosticsProcessorCallback));
-
-  MOCK_METHOD0(NotifyConfigurationDataChanged, void());
-};
-
-// An implementation of the DiagnosticsdManager::Delegate that owns the testing
-// instance of the DiagnosticsdBridge.
-class FakeDiagnosticsdManagerDelegate final
-    : public DiagnosticsdManager::Delegate {
- public:
-  FakeDiagnosticsdManagerDelegate(
-      MockMojoDiagnosticsdService* mojo_diagnosticsd_service)
-      : mojo_diagnosticsd_service_(mojo_diagnosticsd_service) {}
-
-  // DiagnosticsdManager::Delegate overrides:
-  std::unique_ptr<DiagnosticsdBridge> CreateDiagnosticsdBridge() override {
-    std::unique_ptr<DiagnosticsdBridge> diagnosticsd_bridge;
-    testing_diagnosticsd_bridge_wrapper_ =
-        TestingDiagnosticsdBridgeWrapper::Create(
-            mojo_diagnosticsd_service_,
-            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-                &test_url_loader_factory_),
-            &diagnosticsd_bridge);
-    DCHECK(diagnosticsd_bridge);
-    testing_diagnosticsd_bridge_wrapper_->EstablishFakeMojoConnection();
-    return diagnosticsd_bridge;
-  }
-
- private:
-  network::TestURLLoaderFactory test_url_loader_factory_;
-  std::unique_ptr<TestingDiagnosticsdBridgeWrapper>
-      testing_diagnosticsd_bridge_wrapper_;
-  MockMojoDiagnosticsdService* mojo_diagnosticsd_service_;
-};
-
-// Tests DiagnosticsdManager class instance.
-class DiagnosticsdManagerTest : public testing::Test {
- protected:
-  DiagnosticsdManagerTest() {
-    DBusThreadManager::Initialize();
-    upstart_client_ = std::make_unique<TestUpstartClient>();
-  }
-
-  ~DiagnosticsdManagerTest() override { DBusThreadManager::Shutdown(); }
-
-  std::unique_ptr<DiagnosticsdManager::Delegate> CreateDelegate() {
-    return std::make_unique<FakeDiagnosticsdManagerDelegate>(
-        &mojo_diagnosticsd_service_);
-  }
-
-  void SetWilcoDtcAllowedPolicy(bool wilco_dtc_allowed) {
-    scoped_testing_cros_settings_.device_settings()->SetBoolean(
-        kDeviceWilcoDtcAllowed, wilco_dtc_allowed);
-  }
-
-  void LogInUser(bool is_affiliated) {
-    AccountId account_id =
-        AccountId::FromUserEmail(user_manager::kStubUserEmail);
-    fake_user_manager_->AddUserWithAffiliation(account_id, is_affiliated);
-    fake_user_manager_->LoginUser(account_id);
-    session_manager_.SetSessionState(session_manager::SessionState::ACTIVE);
-  }
-
-  MockMojoDiagnosticsdService* mojo_diagnosticsd_service() {
-    return &mojo_diagnosticsd_service_;
-  }
-
- private:
-  base::MessageLoop message_loop_;
-  ScopedTestingCrosSettings scoped_testing_cros_settings_;
-  std::unique_ptr<TestUpstartClient> upstart_client_;
-  FakeChromeUserManager* fake_user_manager_{new FakeChromeUserManager()};
-  user_manager::ScopedUserManager scoped_user_manager_{
-      base::WrapUnique(fake_user_manager_)};
-  session_manager::SessionManager session_manager_;
-  StrictMock<MockMojoDiagnosticsdService> mojo_diagnosticsd_service_;
-};
-
-// Test that wilco DTC support services are not started on enterprise enrolled
-// devices with a certain device policy unset.
-TEST_F(DiagnosticsdManagerTest, EnterpriseiWilcoDtcBasic) {
-  DiagnosticsdManager diagnosticsd_manager(CreateDelegate());
-  EXPECT_FALSE(DiagnosticsdBridge::Get());
-}
-
-// Test that wilco DTC support services are not started if disabled by device
-// policy.
-TEST_F(DiagnosticsdManagerTest, EnterpriseWilcoDtcDisabled) {
-  DiagnosticsdManager diagnosticsd_manager(CreateDelegate());
-  EXPECT_FALSE(DiagnosticsdBridge::Get());
-
-  SetWilcoDtcAllowedPolicy(false);
-  EXPECT_FALSE(DiagnosticsdBridge::Get());
-}
-
-// Test that wilco DTC support services are started if enabled by policy.
-TEST_F(DiagnosticsdManagerTest, EnterpriseWilcoDtcAllowed) {
-  SetWilcoDtcAllowedPolicy(true);
-  DiagnosticsdManager diagnosticsd_manager(CreateDelegate());
-  EXPECT_TRUE(DiagnosticsdBridge::Get());
-}
-
-// Test that wilco DTC support services are not started if non-affiliated user
-// is logged-in.
-TEST_F(DiagnosticsdManagerTest, EnterpriseNonAffiliatedUserLoggedIn) {
-  DiagnosticsdManager diagnosticsd_manager(CreateDelegate());
-  EXPECT_FALSE(DiagnosticsdBridge::Get());
-
-  SetWilcoDtcAllowedPolicy(true);
-  EXPECT_TRUE(DiagnosticsdBridge::Get());
-
-  LogInUser(false);
-  EXPECT_FALSE(DiagnosticsdBridge::Get());
-}
-
-// Test that wilco DTC support services are started if enabled by device policy
-// and affiliated user is logged-in.
-TEST_F(DiagnosticsdManagerTest, EnterpriseAffiliatedUserLoggedIn) {
-  SetWilcoDtcAllowedPolicy(true);
-  DiagnosticsdManager diagnosticsd_manager(CreateDelegate());
-  EXPECT_TRUE(DiagnosticsdBridge::Get());
-
-  LogInUser(true);
-  EXPECT_TRUE(DiagnosticsdBridge::Get());
-}
-
-// Test that wilco DTC support services are not started if non-affiliated user
-// is logged-in before the construction.
-TEST_F(DiagnosticsdManagerTest, EnterpriseNonAffiliatedUserLoggedInBefore) {
-  SetWilcoDtcAllowedPolicy(true);
-  LogInUser(false);
-  DiagnosticsdManager diagnosticsd_manager(CreateDelegate());
-
-  EXPECT_FALSE(DiagnosticsdBridge::Get());
-}
-
-// Test that wilco DTC support services are properly notified about the changes
-// of configuration data.
-TEST_F(DiagnosticsdManagerTest, ConfigurationData) {
-  constexpr char kFakeConfigurationData[] =
-      "{\"fake-message\": \"Fake JSON configuration data\"}";
-
-  DiagnosticsdManager diagnosticsd_manager(CreateDelegate());
-  EXPECT_FALSE(DiagnosticsdBridge::Get());
-
-  SetWilcoDtcAllowedPolicy(true);
-  EXPECT_TRUE(DiagnosticsdBridge::Get());
-  // An empty configuration data by default.
-  EXPECT_TRUE(
-      DiagnosticsdBridge::Get()->GetConfigurationDataForTesting().empty());
-
-  // Set a non-empty configuration data.
-  {
-    base::RunLoop run_loop;
-    EXPECT_CALL(*mojo_diagnosticsd_service(), NotifyConfigurationDataChanged())
-        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
-
-    diagnosticsd_manager.SetConfigurationData(
-        std::make_unique<std::string>(kFakeConfigurationData));
-    EXPECT_EQ(kFakeConfigurationData,
-              DiagnosticsdBridge::Get()->GetConfigurationDataForTesting());
-    run_loop.Run();
-  }
-
-  // Restart the bridge.
-  SetWilcoDtcAllowedPolicy(false);
-  EXPECT_FALSE(DiagnosticsdBridge::Get());
-  SetWilcoDtcAllowedPolicy(true);
-  EXPECT_TRUE(DiagnosticsdBridge::Get());
-
-  // The configuration data has not been changed.
-  EXPECT_EQ(kFakeConfigurationData,
-            DiagnosticsdBridge::Get()->GetConfigurationDataForTesting());
-
-  // Clear the configuration data.
-  {
-    base::RunLoop run_loop;
-    EXPECT_CALL(*mojo_diagnosticsd_service(), NotifyConfigurationDataChanged())
-        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
-    diagnosticsd_manager.SetConfigurationData(nullptr);
-    EXPECT_TRUE(
-        DiagnosticsdBridge::Get()->GetConfigurationDataForTesting().empty());
-    run_loop.Run();
-  }
-}
-
-}  // namespace
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.cc b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.cc
deleted file mode 100644
index 339a175..0000000
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.cc
+++ /dev/null
@@ -1,255 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/logging.h"
-#include "chrome/browser/chromeos/diagnosticsd/mojo_utils.h"
-#include "mojo/public/cpp/system/buffer.h"
-#include "net/base/load_flags.h"
-#include "net/base/net_errors.h"
-#include "net/base/url_util.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-#include "url/url_constants.h"
-
-namespace chromeos {
-
-// Maximum size of the |request_queue_|.
-const int kDiagnosticsdWebRequestQueueMaxSize = 10;
-
-// Maximum size of the web response body.
-const int kDiagnosticsdWebResponseMaxSizeInBytes = 1000000;
-
-namespace {
-
-// Converts mojo HTTP method into string.
-std::string GetHttpMethod(
-    diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod http_method) {
-  switch (http_method) {
-    case diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kGet:
-      return "GET";
-    case diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kHead:
-      return "HEAD";
-    case diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPost:
-      return "POST";
-    case diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPut:
-      return "PUT";
-  }
-}
-
-// Returns true in case of non-error 2xx HTTP status code.
-bool IsHttpOkCode(int code) {
-  return 200 <= code && code < 300;
-}
-
-}  //  namespace
-
-DiagnosticsdWebRequestService::DiagnosticsdWebRequestService(
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
-    : url_loader_factory_(std::move(url_loader_factory)) {
-  DCHECK(url_loader_factory_);
-}
-
-DiagnosticsdWebRequestService::~DiagnosticsdWebRequestService() {
-  if (active_request_) {
-    std::move(active_request_->callback)
-        .Run(diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-             0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-    active_request_.reset();
-  }
-  while (!request_queue_.empty()) {
-    auto request = std::move(request_queue_.front());
-    request_queue_.pop();
-    std::move(request->callback)
-        .Run(diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-             0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-  }
-  DCHECK(!active_request_);
-}
-
-void DiagnosticsdWebRequestService::PerformRequest(
-    diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod http_method,
-    GURL url,
-    std::vector<base::StringPiece> headers,
-    std::string request_body,
-    PerformWebRequestCallback callback) {
-  // Fail with the kNetworkError if the queue overflows.
-  if (request_queue_.size() == kDiagnosticsdWebRequestQueueMaxSize) {
-    LOG(ERROR) << "Too many incomplete requests in the diagnosticsd web request"
-               << " queue.";
-    std::move(callback).Run(
-        diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-        0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-    return;
-  }
-
-  // Fail with kNetworkError if the |url| is invalid.
-  if (!url.is_valid()) {
-    LOG(ERROR) << "Diagnosticsd web request URL is invalid.";
-    std::move(callback).Run(
-        diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-        0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-    return;
-  }
-
-  // Fail with kNetworkError for non-HTTPs URL.
-  if (!url.SchemeIs(url::kHttpsScheme)) {
-    LOG(ERROR) << "Diagnosticsd web request URL must have a HTTPS scheme.";
-    std::move(callback).Run(
-        diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-        0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-    return;
-  }
-
-  // request_body must be empty for GET and HEAD HTTP methods.
-  if (!request_body.empty() &&
-      (http_method ==
-           diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kGet ||
-       http_method ==
-           diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kHead)) {
-    LOG(ERROR) << "Incorrect diagnosticsd web request format: require an empty "
-               << "request body for GET and HEAD HTTP methods.";
-    std::move(callback).Run(
-        diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-        0 /* http_status */, mojo::ScopedHandle() /*response_body */);
-    return;
-  }
-
-  // Do not allow local requests.
-  if (net::IsLocalhost(url)) {
-    LOG(ERROR) << "Local requests are not allowed.";
-    std::move(callback).Run(
-        diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-        0 /* http_status */, mojo::ScopedHandle() /*response_body */);
-    return;
-  }
-
-  // Create a web request.
-  auto request = std::make_unique<WebRequest>();
-  request->request = std::make_unique<network::ResourceRequest>();
-  request->request->method = GetHttpMethod(http_method);
-  request->request->url = std::move(url);
-  request->request->allow_credentials = false;
-  request->request->load_flags = net::LOAD_DISABLE_CACHE;
-  for (auto header : headers) {
-    request->request->headers.AddHeaderFromString(header);
-  }
-
-  request->request_body = std::move(request_body);
-  request->callback = std::move(callback);
-
-  request_queue_.push(std::move(request));
-  MaybeStartNextRequest();
-}
-
-DiagnosticsdWebRequestService::WebRequest::WebRequest() = default;
-
-DiagnosticsdWebRequestService::WebRequest::~WebRequest() = default;
-
-void DiagnosticsdWebRequestService::MaybeStartNextRequest() {
-  // Starts the next web requests only if there is nothing pending.
-  if (active_request_ || request_queue_.empty())
-    return;
-
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("diagnosticsd", R"(
-          semantics {
-            sender: "Diagnosticsd"
-            description: "Perform a web request."
-            trigger:
-                "diagnostics_processor performs a web request to their server."
-            data:
-                "diagnostics_processor's proprietary data."
-            destination: OTHER
-          }
-          policy {
-            cookies_allowed: NO
-          }
-      )");
-
-  // Start new web request.
-  active_request_ = std::move(request_queue_.front());
-  request_queue_.pop();
-
-  url_loader_ = network::SimpleURLLoader::Create(
-      std::move(active_request_->request), traffic_annotation);
-  // Allows non-empty response body in case of HTTP errors.
-  url_loader_->SetAllowHttpErrorResults(true /* allow */);
-
-  if (!active_request_->request_body.empty()) {
-    url_loader_->AttachStringForUpload(active_request_->request_body,
-                                       "text/plain");
-  }
-  // Do not retry.
-  url_loader_->SetRetryOptions(0, network::SimpleURLLoader::RETRY_NEVER);
-  url_loader_->DownloadToString(
-      url_loader_factory_.get(),
-      base::BindOnce(&DiagnosticsdWebRequestService::OnRequestComplete,
-                     base::Unretained(this)),
-      kDiagnosticsdWebResponseMaxSizeInBytes);
-}
-
-void DiagnosticsdWebRequestService::OnRequestComplete(
-    std::unique_ptr<std::string> response_body) {
-  DCHECK(active_request_);
-
-  int response_code = -1;
-  if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
-    response_code = url_loader_->ResponseInfo()->headers->response_code();
-  }
-
-  int net_error = url_loader_->NetError();
-  // Got a network error.
-  if (net_error != net::OK &&
-      (response_code == -1 || IsHttpOkCode(response_code))) {
-    DVLOG(0) << "Web request failed with error: " << net_error
-             << net::ErrorToString(net_error);
-    std::move(active_request_->callback)
-        .Run(diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError,
-             0 /* http_status */, mojo::ScopedHandle() /* response_body */);
-    active_request_.reset();
-    MaybeStartNextRequest();
-    return;
-  }
-
-  // The response_code cannot be parsed from the web response.
-  if (response_code == -1) {
-    LOG(ERROR) << "Web request response cannot be parsed.";
-    response_code = net::HTTP_INTERNAL_SERVER_ERROR;
-  }
-
-  DCHECK(!response_body ||
-         response_body->size() <= kDiagnosticsdWebResponseMaxSizeInBytes);
-
-  mojo::ScopedHandle response_body_handle;
-  if (response_body)
-    response_body_handle = CreateReadOnlySharedMemoryMojoHandle(*response_body);
-
-  // Got an HTTP error.
-  if (!IsHttpOkCode(response_code)) {
-    std::move(active_request_->callback)
-        .Run(diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kHttpError,
-             response_code, std::move(response_body_handle));
-    active_request_.reset();
-    MaybeStartNextRequest();
-    return;
-  }
-
-  // The web request is completed successfully.
-  std::move(active_request_->callback)
-      .Run(diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kOk,
-           response_code, std::move(response_body_handle));
-  active_request_.reset();
-  MaybeStartNextRequest();
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.cc b/chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.cc
deleted file mode 100644
index 745854c..0000000
--- a/chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.h"
-
-#include <unistd.h>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/files/scoped_file.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/diagnosticsd_client.h"
-#include "chromeos/dbus/fake_diagnosticsd_client.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-
-namespace chromeos {
-
-namespace {
-
-// Testing implementation of the DiagnosticsdServiceFactory Mojo service that
-// allows to stub out the GetService Mojo method and tie it with the testing
-// implementation instead.
-class TestingMojoDiagnosticsdServiceFactory final
-    : public diagnosticsd::mojom::DiagnosticsdServiceFactory {
- public:
-  // |get_service_handler_callback| is the callback that will be run when
-  // GetService() is called.
-  explicit TestingMojoDiagnosticsdServiceFactory(
-      base::RepeatingCallback<void(
-          diagnosticsd::mojom::DiagnosticsdServiceRequest
-              mojo_diagnosticsd_service_request,
-          diagnosticsd::mojom::DiagnosticsdClientPtr mojo_diagnosticsd_client)>
-          get_service_handler_callback)
-      : get_service_handler_callback_(std::move(get_service_handler_callback)) {
-  }
-
-  // Completes the Mojo binding of |this| to the given Mojo interface request.
-  // This method allows to redirect to |this| the calls on the
-  // DiagnosticsdServiceFactory interface that are made by the
-  // DiagnosticsdBridge.
-  void Bind(diagnosticsd::mojom::DiagnosticsdServiceFactoryRequest
-                mojo_diagnosticsd_service_factory_request) {
-    // First close the Mojo binding in case it was previously completed, to
-    // allow calling this method multiple times.
-    self_binding_.Close();
-    self_binding_.Bind(std::move(mojo_diagnosticsd_service_factory_request));
-  }
-
-  // DiagnosticsdServiceFactory overrides:
-
-  void GetService(diagnosticsd::mojom::DiagnosticsdServiceRequest service,
-                  diagnosticsd::mojom::DiagnosticsdClientPtr client,
-                  GetServiceCallback callback) override {
-    DCHECK(service);
-    DCHECK(client);
-    // Redirect to |get_service_handler_callback_| to let
-    // TestingDiagnosticsdBridgeWrapper capture |client| (which points to the
-    // production implementation in DiagnosticsdBridge) and fulfill |service|
-    // (to make it point to the stub implementation of the DiagnosticsdService
-    // Mojo service that was passed to TestingDiagnosticsdBridgeWrapper).
-    get_service_handler_callback_.Run(std::move(service), std::move(client));
-    std::move(callback).Run();
-  }
-
- private:
-  // Mojo binding that binds |this| as an implementation of the
-  // DiagnosticsdClient Mojo interface.
-  mojo::Binding<diagnosticsd::mojom::DiagnosticsdServiceFactory> self_binding_{
-      this};
-  // The callback to be run when GetService() is called.
-  base::RepeatingCallback<void(
-      diagnosticsd::mojom::DiagnosticsdServiceRequest
-          mojo_diagnosticsd_service_request,
-      diagnosticsd::mojom::DiagnosticsdClientPtr mojo_diagnosticsd_client)>
-      get_service_handler_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestingMojoDiagnosticsdServiceFactory);
-};
-
-// Testing implementation of the DiagnosticsdBridge delegate that stubs out the
-// process of generating the Mojo invitation and tie it with
-// TestingMojoDiagnosticsdServiceFactory instead.
-class TestingDiagnosticsdBridgeWrapperDelegate final
-    : public DiagnosticsdBridge::Delegate {
- public:
-  explicit TestingDiagnosticsdBridgeWrapperDelegate(
-      std::unique_ptr<TestingMojoDiagnosticsdServiceFactory>
-          mojo_diagnosticsd_service_factory)
-      : mojo_diagnosticsd_service_factory_(
-            std::move(mojo_diagnosticsd_service_factory)) {}
-
-  // DiagnosticsdBridge::Delegate overrides:
-
-  void CreateDiagnosticsdServiceFactoryMojoInvitation(
-      diagnosticsd::mojom::DiagnosticsdServiceFactoryPtr*
-          diagnosticsd_service_factory_mojo_ptr,
-      base::ScopedFD* remote_endpoint_fd) override {
-    // Bind the Mojo pointer passed to the bridge with the
-    // TestingMojoDiagnosticsdServiceFactory implementation.
-    mojo_diagnosticsd_service_factory_->Bind(
-        mojo::MakeRequest(diagnosticsd_service_factory_mojo_ptr));
-
-    // Return a fake file descriptor - its value is not used in the unit test
-    // environment for anything except comparing with zero.
-    remote_endpoint_fd->reset(HANDLE_EINTR(dup(STDIN_FILENO)));
-    DCHECK(remote_endpoint_fd->is_valid());
-  }
-
- private:
-  std::unique_ptr<TestingMojoDiagnosticsdServiceFactory>
-      mojo_diagnosticsd_service_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestingDiagnosticsdBridgeWrapperDelegate);
-};
-
-FakeDiagnosticsdClient* GetFakeDbusDiagnosticsdClient() {
-  DCHECK(DBusThreadManager::Get()->IsUsingFakes());
-  DiagnosticsdClient* const diagnosticsd_client =
-      DBusThreadManager::Get()->GetDiagnosticsdClient();
-  DCHECK(diagnosticsd_client);
-  return static_cast<FakeDiagnosticsdClient*>(diagnosticsd_client);
-}
-
-}  // namespace
-
-// static
-std::unique_ptr<TestingDiagnosticsdBridgeWrapper>
-TestingDiagnosticsdBridgeWrapper::Create(
-    diagnosticsd::mojom::DiagnosticsdService* mojo_diagnosticsd_service,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    std::unique_ptr<DiagnosticsdBridge>* bridge) {
-  return base::WrapUnique(new TestingDiagnosticsdBridgeWrapper(
-      mojo_diagnosticsd_service, std::move(url_loader_factory), bridge));
-}
-
-TestingDiagnosticsdBridgeWrapper::~TestingDiagnosticsdBridgeWrapper() = default;
-
-void TestingDiagnosticsdBridgeWrapper::EstablishFakeMojoConnection() {
-  DCHECK(!mojo_diagnosticsd_client_);
-  DCHECK(!mojo_get_service_handler_);
-
-  // Set up the callback that will handle the GetService Mojo method called
-  // during the bootstrap.
-  base::RunLoop run_loop;
-  diagnosticsd::mojom::DiagnosticsdServiceRequest
-      intercepted_mojo_diagnosticsd_service_request;
-  mojo_get_service_handler_ = base::BindLambdaForTesting(
-      [&run_loop, &intercepted_mojo_diagnosticsd_service_request](
-          diagnosticsd::mojom::DiagnosticsdServiceRequest
-              mojo_diagnosticsd_service_request) {
-        intercepted_mojo_diagnosticsd_service_request =
-            std::move(mojo_diagnosticsd_service_request);
-        run_loop.Quit();
-      });
-
-  // Trigger the Mojo bootstrapping process by unblocking the corresponding
-  // D-Bus operations.
-  FakeDiagnosticsdClient* const fake_dbus_diagnosticsd_client =
-      GetFakeDbusDiagnosticsdClient();
-  fake_dbus_diagnosticsd_client->SetWaitForServiceToBeAvailableResult(true);
-  fake_dbus_diagnosticsd_client->SetBootstrapMojoConnectionResult(true);
-
-  // Wait till the GetService Mojo method call completes.
-  run_loop.Run();
-  DCHECK(intercepted_mojo_diagnosticsd_service_request);
-  DCHECK(mojo_diagnosticsd_client_);
-
-  // First close the Mojo binding in case it was previously completed, to allow
-  // calling this method multiple times.
-  mojo_diagnosticsd_service_binding_.Close();
-  mojo_diagnosticsd_service_binding_.Bind(
-      std::move(intercepted_mojo_diagnosticsd_service_request));
-}
-
-void TestingDiagnosticsdBridgeWrapper::HandleMojoGetService(
-    diagnosticsd::mojom::DiagnosticsdServiceRequest
-        mojo_diagnosticsd_service_request,
-    diagnosticsd::mojom::DiagnosticsdClientPtr mojo_diagnosticsd_client) {
-  std::move(mojo_get_service_handler_)
-      .Run(std::move(mojo_diagnosticsd_service_request));
-  mojo_diagnosticsd_client_ = std::move(mojo_diagnosticsd_client);
-}
-
-TestingDiagnosticsdBridgeWrapper::TestingDiagnosticsdBridgeWrapper(
-    diagnosticsd::mojom::DiagnosticsdService* mojo_diagnosticsd_service,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    std::unique_ptr<DiagnosticsdBridge>* bridge)
-    : mojo_diagnosticsd_service_binding_(mojo_diagnosticsd_service) {
-  *bridge = std::make_unique<DiagnosticsdBridge>(
-      std::make_unique<TestingDiagnosticsdBridgeWrapperDelegate>(
-          std::make_unique<TestingMojoDiagnosticsdServiceFactory>(
-              base::BindRepeating(
-                  &TestingDiagnosticsdBridgeWrapper::HandleMojoGetService,
-                  base::Unretained(this)))),
-      url_loader_factory);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.h b/chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.h
deleted file mode 100644
index f90a6dd..0000000
--- a/chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_TESTING_DIAGNOSTICSD_BRIDGE_WRAPPER_H_
-#define CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_TESTING_DIAGNOSTICSD_BRIDGE_WRAPPER_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h"
-#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-
-namespace chromeos {
-
-// Manages a fake instance of DiagnosticsdBridge for unit tests. Mocks out the
-// Mojo communication and provides tools for simulating and handling Mojo
-// requests.
-class TestingDiagnosticsdBridgeWrapper final {
- public:
-  // |mojo_diagnosticsd_service| is an unowned pointer that should be a stub
-  // implementation of the DiagnosticsdService Mojo service (which in production
-  // is implemented by the wilco_dtc_supportd daemon).
-  // |bridge| is an unowned bridge instance that holds the stub diagnosticsd
-  // bridge instance created by the TestingDiagnosticsdBridgeWrapper.
-  static std::unique_ptr<TestingDiagnosticsdBridgeWrapper> Create(
-      diagnosticsd::mojom::DiagnosticsdService* mojo_diagnosticsd_service,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loade_factory,
-      std::unique_ptr<DiagnosticsdBridge>* bridge);
-
-  ~TestingDiagnosticsdBridgeWrapper();
-
-  // Simulates bootstrapping the Mojo communication between the diagnosticsd
-  // daemon and the browser.
-  void EstablishFakeMojoConnection();
-
-  // Returns a pointer that allows to simulate Mojo calls to the
-  // DiagnosticsdClient mojo service (which in production is implemented by the
-  // browser and called by the diagnosticsd daemon).
-  //
-  // Returns null if EstablishFakeMojoConnection() wasn't called yet.
-  diagnosticsd::mojom::DiagnosticsdClient* mojo_diagnosticsd_client() {
-    return mojo_diagnosticsd_client_.get();
-  }
-
- private:
-  // |mojo_diagnosticsd_service| is an unowned pointer that should be a stub
-  // implementation of the DiagnosticsdService Mojo service (which in production
-  // is implemented by the diagnosticsd daemon).
-  TestingDiagnosticsdBridgeWrapper(
-      diagnosticsd::mojom::DiagnosticsdService* mojo_diagnosticsd_service,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      std::unique_ptr<DiagnosticsdBridge>* bridge);
-
-  // Implements the GetService Mojo method of the DiagnosticsdServiceFactory
-  // interface. Called during the simulated Mojo boostrapping.
-  void HandleMojoGetService(
-      diagnosticsd::mojom::DiagnosticsdServiceRequest
-          mojo_diagnosticsd_service_request,
-      diagnosticsd::mojom::DiagnosticsdClientPtr mojo_diagnosticsd_client);
-
-  // Mojo binding that binds the DiagnosticsdService implementation (passed to
-  // the constructor) with the other endpoint owned from |bridge_|.
-  mojo::Binding<diagnosticsd::mojom::DiagnosticsdService>
-      mojo_diagnosticsd_service_binding_;
-
-  // Mojo pointer that points to the DiagnosticsdClient implementation (owned by
-  // |bridge_|).  Is initialized if the Mojo is bootstrapped by
-  // EstablishFakeMojoConnection().
-  diagnosticsd::mojom::DiagnosticsdClientPtr mojo_diagnosticsd_client_;
-
-  // Temporary callback that allows to deliver the DiagnosticsdServiceRequest
-  // value during the Mojo bootstrapping simulation by
-  // EstablishFakeMojoConnection().
-  base::OnceCallback<void(diagnosticsd::mojom::DiagnosticsdServiceRequest
-                              mojo_diagnosticsd_service_request)>
-      mojo_get_service_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestingDiagnosticsdBridgeWrapper);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_TESTING_DIAGNOSTICSD_BRIDGE_WRAPPER_H_
diff --git a/chrome/browser/chromeos/kiosk_next_home/intent_config_helper.cc b/chrome/browser/chromeos/kiosk_next_home/intent_config_helper.cc
index b16d86b..e4904b3 100644
--- a/chrome/browser/chromeos/kiosk_next_home/intent_config_helper.cc
+++ b/chrome/browser/chromeos/kiosk_next_home/intent_config_helper.cc
@@ -18,8 +18,8 @@
 #include "services/data_decoder/public/cpp/safe_json_parser.h"
 #include "url/url_constants.h"
 
-#if defined(GOOGLE_CHROME_BUILD)
-#include "chrome/grit/component_extension_resources.h"
+#if defined(KIOSK_NEXT) && defined(GOOGLE_CHROME_BUILD)
+#include "chrome/grit/kiosk_next_internal_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #endif
 
@@ -59,7 +59,7 @@
 
   // IntentConfigHelper::Delegate:
   std::string GetJsonConfig() const override {
-#if defined(GOOGLE_CHROME_BUILD)
+#if defined(KIOSK_NEXT) && defined(GOOGLE_CHROME_BUILD)
     return ui::ResourceBundle::GetSharedInstance()
         .GetRawDataResource(IDR_KIOSK_NEXT_INTENT_CONFIG_JSON)
         .as_string();
diff --git a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
index 4339393..c5f27494 100644
--- a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "ash/public/cpp/ash_switches.h"
 #include "base/base_paths.h"
 #include "base/environment.h"
 #include "base/path_service.h"
@@ -232,8 +233,23 @@
   ad_login_.TestPasswordChangeOldPasswordError();
 }
 
+class ActiveDirectoryWebUILoginTest : public ActiveDirectoryLoginTest {
+ public:
+  ActiveDirectoryWebUILoginTest() = default;
+  ~ActiveDirectoryWebUILoginTest() override = default;
+
+  // chromeos::ActiveDirectoryLoginTest:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
+    chromeos::ActiveDirectoryLoginTest::SetUpCommandLine(command_line);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ActiveDirectoryWebUILoginTest);
+};
+
 // Test reopening Active Directory password change screen clears errors.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest,
+IN_PROC_BROWSER_TEST_F(ActiveDirectoryWebUILoginTest,
                        PasswordChange_ReopenClearErrors) {
   OobeBaseTest::WaitForSigninScreen();
   ASSERT_TRUE(InstallAttributes::Get()->IsActiveDirectoryManaged());
diff --git a/chrome/browser/chromeos/login/arc_kiosk_controller.cc b/chrome/browser/chromeos/login/arc_kiosk_controller.cc
index 238a170..7954107 100644
--- a/chrome/browser/chromeos/login/arc_kiosk_controller.cc
+++ b/chrome/browser/chromeos/login/arc_kiosk_controller.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chromeos/login/auth/user_context.h"
 #include "components/account_id/account_id.h"
@@ -118,7 +119,7 @@
 void ArcKioskController::OnOldEncryptionDetected(
     const UserContext& user_context,
     bool has_incomplete_migration) {
-  host_->StartWizard(OobeScreen::SCREEN_ENCRYPTION_MIGRATION);
+  host_->StartWizard(EncryptionMigrationScreenView::kScreenId);
 
   EncryptionMigrationScreen* migration_screen =
       static_cast<EncryptionMigrationScreen*>(
diff --git a/chrome/browser/chromeos/login/configuration_based_oobe_browsertest.cc b/chrome/browser/chromeos/login/configuration_based_oobe_browsertest.cc
index 4dccf04..38f7f69 100644
--- a/chrome/browser/chromeos/login/configuration_based_oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/configuration_based_oobe_browsertest.cc
@@ -17,6 +17,13 @@
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_update_engine_client.h"
@@ -163,13 +170,13 @@
 // Check that configuration lets correctly pass Welcome screen.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestLeaveWelcomeScreen) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
 }
 
 // Check that language and input methods are set correctly.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestSwitchLanguageIME) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
 
   chromeos::input_method::InputMethodManager* imm =
       chromeos::input_method::InputMethodManager::Get();
@@ -191,38 +198,38 @@
 // Check that configuration lets correctly start Demo mode setup.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestEnableDemoMode) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
 }
 
 // Check that configuration lets correctly pass through demo preferences.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestDemoModePreferences) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
 }
 
 // Check that configuration lets correctly use offline demo mode on network
 // screen.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestDemoModeOfflineNetwork) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
   SimulateOfflineEnvironment();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
 }
 
 // Check that configuration lets correctly use offline demo mode on EULA
 // screen.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestDemoModeAcceptEula) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
   SimulateOfflineEnvironment();
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
 }
 
 // Check that configuration lets correctly use offline demo mode on ARC++ ToS
 // screen.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestDemoModeAcceptArcTos) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
   SimulateOfflineEnvironment();
 
   test::OobeJS().Evaluate(
@@ -232,26 +239,26 @@
       "$('demo-preferences-content').$$('oobe-dialog')."
       "querySelector('oobe-text-button').click();");
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
 }
 
 // Check that configuration lets correctly select a network by GUID.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestSelectNetwork) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
 }
 
 // Check that configuration would proceed if there is a connected network.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestSelectConnectedNetwork) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
 }
 
 // Check that configuration would not proceed with connected network if
 // welcome screen is not automated.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestConnectedNetworkNoWelcome) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
 }
 
 // Check that when configuration has ONC and EULA, we get to update screen.
@@ -262,14 +269,14 @@
   fake_update_engine_client_->set_default_status(status);
 
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
+  OobeScreenWaiter(UpdateView::kScreenId).Wait();
 }
 
 // Check that when configuration has requisition, it gets applied at the
 // beginning.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestDeviceRequisition) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
   auto* policy_manager = g_browser_process->platform_part()
                              ->browser_policy_connector_chromeos()
                              ->GetDeviceCloudPolicyManager();
@@ -280,7 +287,7 @@
 // screen.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationEnrollmentTest, TestSkipUpdate) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
   enrollment_ui_.WaitForStep(test::ui::kEnrollmentStepSignin);
 }
 
@@ -292,7 +299,7 @@
   policy_server_.ExpectTokenEnrollment("00000000-1111-2222-3333-444444444444",
                                        FakeGaiaMixin::kEnterpriseUser1);
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
   enrollment_ui_.WaitForStep(test::ui::kEnrollmentStepSuccess);
 }
 
@@ -300,14 +307,14 @@
 // configuration.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTestNoHID, TestLeaveWelcomeScreen) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_HID_DETECTION).Wait();
+  OobeScreenWaiter(HIDDetectionView::kScreenId).Wait();
 }
 
 // Check that HID detection screen is really skipped and rest of configuration
 // is applied.
 IN_PROC_BROWSER_TEST_F(OobeConfigurationTestNoHID, TestSkipHIDDetection) {
   LoadConfiguration();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc
index 2b85b51..e86792c 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc
@@ -32,6 +32,13 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -108,17 +115,17 @@
 // Returns query to access the content of the given OOBE |screen| or empty
 // string if the |screen| is not a part of Demo Mode setup flow.
 std::string ScreenToContentQuery(OobeScreenId screen) {
-  if (screen == OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES)
+  if (screen == DemoPreferencesScreenView::kScreenId)
     return "$('demo-preferences-content')";
-  if (screen == OobeScreen::SCREEN_OOBE_NETWORK)
+  if (screen == NetworkScreenView::kScreenId)
     return "$('oobe-network-md')";
-  if (screen == OobeScreen::SCREEN_OOBE_EULA)
+  if (screen == EulaView::kScreenId)
     return "$('oobe-eula-md')";
-  if (screen == OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE)
+  if (screen == ArcTermsOfServiceScreenView::kScreenId)
     return "$('arc-tos-root')";
-  if (screen == OobeScreen::SCREEN_OOBE_UPDATE)
+  if (screen == UpdateView::kScreenId)
     return "$('oobe-update-md')";
-  if (screen == OobeScreen::SCREEN_OOBE_DEMO_SETUP)
+  if (screen == DemoSetupScreenView::kScreenId)
     return "$('demo-setup-content')";
   NOTREACHED() << "This OOBE screen is not a part of Demo Mode setup flow";
   return std::string();
@@ -207,7 +214,7 @@
   // element on the network list.
   bool IsCustomNetworkListElementShown(const std::string& custom_item_name) {
     const std::string element_selector = base::StrCat(
-        {ScreenToContentQuery(OobeScreen::SCREEN_OOBE_NETWORK),
+        {ScreenToContentQuery(NetworkScreenView::kScreenId),
          ".getNetworkListItemWithQueryForTest('cr-network-list-item')"});
     const std::string query =
         base::StrCat({"!!", element_selector, " && ", element_selector,
@@ -221,7 +228,7 @@
   // |recovery_message_id|.
   bool IsErrorMessageShown(int error_message_id, int recovery_message_id) {
     const std::string element_selector =
-        base::StrCat({ScreenToContentQuery(OobeScreen::SCREEN_OOBE_DEMO_SETUP),
+        base::StrCat({ScreenToContentQuery(DemoSetupScreenView::kScreenId),
                       ".$['", DialogToStringId(DemoSetupDialog::kError),
                       "'].querySelector('div[slot=subtitle]')"});
     const std::string query = base::StrCat(
@@ -327,7 +334,7 @@
   // the aria-label of the desired cr-network-list-item.
   void ClickNetworkListElement(const std::string& element) {
     const std::string query =
-        base::StrCat({ScreenToContentQuery(OobeScreen::SCREEN_OOBE_NETWORK),
+        base::StrCat({ScreenToContentQuery(NetworkScreenView::kScreenId),
                       ".getNetworkListItemWithQueryForTest('[aria-label=\"",
                       element, "\"]').click()"});
     test::ExecuteOobeJSAsync(query);
@@ -346,12 +353,12 @@
     auto* const wizard_controller = WizardController::default_controller();
     wizard_controller->SimulateDemoModeSetupForTesting(
         DemoSession::DemoModeConfig::kOnline);
-    wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+    wizard_controller->AdvanceToScreen(DemoSetupScreenView::kScreenId);
 
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+    OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
     // TODO(agawronska): Progress dialog transition is async - extra work is
     // needed to be able to check it reliably.
-    WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+    WaitForScreenDialog(DemoSetupScreenView::kScreenId,
                         DemoSetupDialog::kError);
   }
 
@@ -374,7 +381,7 @@
   DemoSetupScreen* GetDemoSetupScreen() {
     return static_cast<DemoSetupScreen*>(
         WizardController::default_controller()->screen_manager()->GetScreen(
-            OobeScreen::SCREEN_OOBE_DEMO_SETUP));
+            DemoSetupScreenView::kScreenId));
   }
 
   void SimulateOfflineEnvironment() {
@@ -468,7 +475,7 @@
   ClickOkOnConfirmationDialog();
 
   WaitForJsCondition(kIsConfirmationDialogHiddenQuery);
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 }
 
 #if defined(OS_CHROMEOS)
@@ -487,7 +494,7 @@
   ClickCancelOnConfirmationDialog();
 
   WaitForJsCondition(kIsConfirmationDialogHiddenQuery);
-  EXPECT_FALSE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  EXPECT_FALSE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, InvokeWithTaps) {
@@ -527,49 +534,49 @@
   InvokeDemoModeWithAccelerator();
   ClickOkOnConfirmationDialog();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_TRUE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                            DemoSetupDialog::kNetwork,
                                            ButtonToTag(OobeButton::kNext)));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_NETWORK, OobeButton::kNext,
+  ClickOobeButton(NetworkScreenView::kScreenId, OobeButton::kNext,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
+  ClickScreenDialogButton(EulaView::kScreenId, DemoSetupDialog::kEula,
                           OobeButton::kText, JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(ArcTermsOfServiceScreenView::kScreenId));
 
   SetPlayStoreTermsForTesting();
 
   EXPECT_TRUE(IsScreenDialogElementVisible(
-      OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE, DemoSetupDialog::kArcTos,
+      ArcTermsOfServiceScreenView::kScreenId, DemoSetupDialog::kArcTos,
       "#arc-tos-metrics-demo-apps"));
 
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-next-button", JSExecution::kSync);
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-accept-button", JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
+  OobeScreenWaiter(UpdateView::kScreenId).Wait();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
   EXPECT_TRUE(DemoSetupController::GetSubOrganizationEmail().empty());
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
 
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
@@ -585,8 +592,8 @@
   InvokeDemoModeWithAccelerator();
   ClickOkOnConfirmationDialog();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
   // Verify the country names are displayed correctly. Regression test for
   // potential country code changes.
@@ -607,7 +614,7 @@
     const auto it = kCountryCodeToNameMap.find(country_code);
     ASSERT_NE(kCountryCodeToNameMap.end(), it);
     const std::string query = base::StrCat(
-        {ScreenToContentQuery(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES),
+        {ScreenToContentQuery(DemoPreferencesScreenView::kScreenId),
          ".$$('oobe-dialog').querySelector('#countrySelect').$$('option[value="
          "\"",
          country_code, "\"]').innerHTML"});
@@ -616,46 +623,46 @@
 
   // Select France as the Demo Mode country.
   const std::string select_country = base::StrCat(
-      {ScreenToContentQuery(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES),
+      {ScreenToContentQuery(DemoPreferencesScreenView::kScreenId),
        ".$$('oobe-dialog').querySelector('#countrySelect').onSelected_('fr')"
        ";"});
   test::ExecuteOobeJSAsync(select_country);
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_TRUE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                            DemoSetupDialog::kNetwork,
                                            ButtonToTag(OobeButton::kNext)));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_NETWORK, OobeButton::kNext,
+  ClickOobeButton(NetworkScreenView::kScreenId, OobeButton::kNext,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
+  ClickScreenDialogButton(EulaView::kScreenId, DemoSetupDialog::kEula,
                           OobeButton::kText, JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(ArcTermsOfServiceScreenView::kScreenId));
 
   SetPlayStoreTermsForTesting();
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-next-button", JSExecution::kSync);
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-accept-button", JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
+  OobeScreenWaiter(UpdateView::kScreenId).Wait();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
   // Verify the email corresponds to France.
   EXPECT_EQ("admin-fr@cros-demo-mode.com",
             DemoSetupController::GetSubOrganizationEmail());
 
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
@@ -672,53 +679,51 @@
   InvokeDemoModeWithAccelerator();
   ClickOkOnConfirmationDialog();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_TRUE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                            DemoSetupDialog::kNetwork,
                                            ButtonToTag(OobeButton::kNext)));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_NETWORK, OobeButton::kNext,
+  ClickOobeButton(NetworkScreenView::kScreenId, OobeButton::kNext,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
+  ClickScreenDialogButton(EulaView::kScreenId, DemoSetupDialog::kEula,
                           OobeButton::kText, JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(ArcTermsOfServiceScreenView::kScreenId));
 
   SetPlayStoreTermsForTesting();
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-next-button", JSExecution::kSync);
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-accept-button", JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
+  OobeScreenWaiter(UpdateView::kScreenId).Wait();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
-  WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                      DemoSetupDialog::kError);
+  WaitForScreenDialog(DemoSetupScreenView::kScreenId, DemoSetupDialog::kError);
   // Default error returned by MockDemoModeOnlineEnrollmentHelperCreator.
   EXPECT_TRUE(IsErrorMessageShown(IDS_DEMO_SETUP_TEMPORARY_ERROR,
                                   IDS_DEMO_SETUP_RECOVERY_RETRY));
-  EXPECT_TRUE(IsScreenDialogElementShown(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                                         DemoSetupDialog::kError,
-                                         "#retryButton"));
-  EXPECT_FALSE(IsScreenDialogElementShown(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  EXPECT_TRUE(IsScreenDialogElementShown(
+      DemoSetupScreenView::kScreenId, DemoSetupDialog::kError, "#retryButton"));
+  EXPECT_FALSE(IsScreenDialogElementShown(DemoSetupScreenView::kScreenId,
                                           DemoSetupDialog::kError,
                                           "#powerwashButton"));
-  EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  EXPECT_TRUE(IsScreenDialogElementEnabled(DemoSetupScreenView::kScreenId,
                                            DemoSetupDialog::kError,
                                            ButtonToTag(OobeButton::kBack)));
 
@@ -738,52 +743,50 @@
   InvokeDemoModeWithAccelerator();
   ClickOkOnConfirmationDialog();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_TRUE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                            DemoSetupDialog::kNetwork,
                                            ButtonToTag(OobeButton::kNext)));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_NETWORK, OobeButton::kNext,
+  ClickOobeButton(NetworkScreenView::kScreenId, OobeButton::kNext,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
+  ClickScreenDialogButton(EulaView::kScreenId, DemoSetupDialog::kEula,
                           OobeButton::kText, JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(ArcTermsOfServiceScreenView::kScreenId));
 
   SetPlayStoreTermsForTesting();
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-next-button", JSExecution::kSync);
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-accept-button", JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
+  OobeScreenWaiter(UpdateView::kScreenId).Wait();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
-  WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                      DemoSetupDialog::kError);
+  WaitForScreenDialog(DemoSetupScreenView::kScreenId, DemoSetupDialog::kError);
   EXPECT_TRUE(IsErrorMessageShown(IDS_DEMO_SETUP_ALREADY_LOCKED_ERROR,
                                   IDS_DEMO_SETUP_RECOVERY_POWERWASH));
-  EXPECT_FALSE(IsScreenDialogElementShown(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                                          DemoSetupDialog::kError,
-                                          "#retryButton"));
-  EXPECT_TRUE(IsScreenDialogElementShown(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  EXPECT_FALSE(IsScreenDialogElementShown(
+      DemoSetupScreenView::kScreenId, DemoSetupDialog::kError, "#retryButton"));
+  EXPECT_TRUE(IsScreenDialogElementShown(DemoSetupScreenView::kScreenId,
                                          DemoSetupDialog::kError,
                                          "#powerwashButton"));
-  EXPECT_FALSE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  EXPECT_FALSE(IsScreenDialogElementEnabled(DemoSetupScreenView::kScreenId,
                                             DemoSetupDialog::kError,
                                             ButtonToTag(OobeButton::kBack)));
 
@@ -806,43 +809,42 @@
       ->SetCrOSComponentLoadErrorForTest(
           component_updater::CrOSComponentManager::Error::INSTALL_FAILURE);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_TRUE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                            DemoSetupDialog::kNetwork,
                                            ButtonToTag(OobeButton::kNext)));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_NETWORK, OobeButton::kNext,
+  ClickOobeButton(NetworkScreenView::kScreenId, OobeButton::kNext,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
+  ClickScreenDialogButton(EulaView::kScreenId, DemoSetupDialog::kEula,
                           OobeButton::kText, JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(ArcTermsOfServiceScreenView::kScreenId));
 
   SetPlayStoreTermsForTesting();
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-next-button", JSExecution::kSync);
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-accept-button", JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
+  OobeScreenWaiter(UpdateView::kScreenId).Wait();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
-  WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                      DemoSetupDialog::kError);
+  WaitForScreenDialog(DemoSetupScreenView::kScreenId, DemoSetupDialog::kError);
   EXPECT_TRUE(IsErrorMessageShown(IDS_DEMO_SETUP_COMPONENT_ERROR,
                                   IDS_DEMO_SETUP_RECOVERY_CHECK_NETWORK));
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
@@ -855,15 +857,15 @@
   InvokeDemoModeWithAccelerator();
   ClickOkOnConfirmationDialog();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_FALSE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_FALSE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                             DemoSetupDialog::kNetwork,
                                             ButtonToTag(OobeButton::kNext)));
 
@@ -884,15 +886,15 @@
   // flow was started).
   SimulateOfflineEnvironment();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_FALSE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_FALSE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                             DemoSetupDialog::kNetwork,
                                             ButtonToTag(OobeButton::kNext)));
 
@@ -900,31 +902,31 @@
       l10n_util::GetStringUTF8(IDS_NETWORK_OFFLINE_DEMO_SETUP_LIST_ITEM_NAME);
   ClickNetworkListElement(offline_setup_item_name);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
+  ClickScreenDialogButton(EulaView::kScreenId, DemoSetupDialog::kEula,
                           OobeButton::kText, JSExecution::kSync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(ArcTermsOfServiceScreenView::kScreenId));
 
   SetPlayStoreTermsForTesting();
 
   EXPECT_TRUE(IsScreenDialogElementVisible(
-      OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE, DemoSetupDialog::kArcTos,
+      ArcTermsOfServiceScreenView::kScreenId, DemoSetupDialog::kArcTos,
       "#arc-tos-metrics-demo-apps"));
 
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-next-button", JSExecution::kSync);
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-accept-button", JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
 
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
@@ -943,15 +945,15 @@
   // flow was started).
   SimulateOfflineEnvironment();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_FALSE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_FALSE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                             DemoSetupDialog::kNetwork,
                                             ButtonToTag(OobeButton::kNext)));
 
@@ -959,36 +961,34 @@
       l10n_util::GetStringUTF8(IDS_NETWORK_OFFLINE_DEMO_SETUP_LIST_ITEM_NAME);
   ClickNetworkListElement(offline_setup_item_name);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
+  ClickScreenDialogButton(EulaView::kScreenId, DemoSetupDialog::kEula,
                           OobeButton::kText, JSExecution::kSync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(ArcTermsOfServiceScreenView::kScreenId));
 
   SetPlayStoreTermsForTesting();
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-next-button", JSExecution::kSync);
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-accept-button", JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
-  WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                      DemoSetupDialog::kError);
+  WaitForScreenDialog(DemoSetupScreenView::kScreenId, DemoSetupDialog::kError);
   // Default error returned by MockDemoModeOfflineEnrollmentHelperCreator.
   EXPECT_TRUE(IsErrorMessageShown(IDS_DEMO_SETUP_OFFLINE_POLICY_ERROR,
                                   IDS_DEMO_SETUP_RECOVERY_OFFLINE_FATAL));
-  EXPECT_TRUE(IsScreenDialogElementShown(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                                         DemoSetupDialog::kError,
-                                         "#retryButton"));
-  EXPECT_FALSE(IsScreenDialogElementShown(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  EXPECT_TRUE(IsScreenDialogElementShown(
+      DemoSetupScreenView::kScreenId, DemoSetupDialog::kError, "#retryButton"));
+  EXPECT_FALSE(IsScreenDialogElementShown(DemoSetupScreenView::kScreenId,
                                           DemoSetupDialog::kError,
                                           "#powerwashButton"));
-  EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  EXPECT_TRUE(IsScreenDialogElementEnabled(DemoSetupScreenView::kScreenId,
                                            DemoSetupDialog::kError,
                                            ButtonToTag(OobeButton::kBack)));
 
@@ -1010,15 +1010,15 @@
   // flow was started).
   SimulateOfflineEnvironment();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
+  ClickOobeButton(DemoPreferencesScreenView::kScreenId, OobeButton::kText,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
-  EXPECT_FALSE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
+  EXPECT_FALSE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                             DemoSetupDialog::kNetwork,
                                             ButtonToTag(OobeButton::kNext)));
 
@@ -1026,35 +1026,33 @@
       l10n_util::GetStringUTF8(IDS_NETWORK_OFFLINE_DEMO_SETUP_LIST_ITEM_NAME);
   ClickNetworkListElement(offline_setup_item_name);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
+  ClickScreenDialogButton(EulaView::kScreenId, DemoSetupDialog::kEula,
                           OobeButton::kText, JSExecution::kSync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+  OobeScreenWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(ArcTermsOfServiceScreenView::kScreenId));
 
   SetPlayStoreTermsForTesting();
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-next-button", JSExecution::kSync);
-  ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  ClickOobeButtonWithSelector(ArcTermsOfServiceScreenView::kScreenId,
                               "#arc-tos-accept-button", JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
+  OobeScreenWaiter(DemoSetupScreenView::kScreenId).Wait();
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
-  WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                      DemoSetupDialog::kError);
+  WaitForScreenDialog(DemoSetupScreenView::kScreenId, DemoSetupDialog::kError);
   EXPECT_TRUE(IsErrorMessageShown(IDS_DEMO_SETUP_LOCK_ERROR,
                                   IDS_DEMO_SETUP_RECOVERY_POWERWASH));
-  EXPECT_FALSE(IsScreenDialogElementShown(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                                          DemoSetupDialog::kError,
-                                          "#retryButton"));
-  EXPECT_TRUE(IsScreenDialogElementShown(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  EXPECT_FALSE(IsScreenDialogElementShown(
+      DemoSetupScreenView::kScreenId, DemoSetupDialog::kError, "#retryButton"));
+  EXPECT_TRUE(IsScreenDialogElementShown(DemoSetupScreenView::kScreenId,
                                          DemoSetupDialog::kError,
                                          "#powerwashButton"));
-  EXPECT_FALSE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  EXPECT_FALSE(IsScreenDialogElementEnabled(DemoSetupScreenView::kScreenId,
                                             DemoSetupDialog::kError,
                                             ButtonToTag(OobeButton::kBack)));
 
@@ -1064,75 +1062,75 @@
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, NextDisabledOnNetworkScreen) {
   SimulateNetworkDisconnected();
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
-  EXPECT_FALSE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  SkipToScreen(NetworkScreenView::kScreenId);
+  EXPECT_FALSE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                             DemoSetupDialog::kNetwork,
                                             ButtonToTag(OobeButton::kNext)));
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_NETWORK, OobeButton::kNext,
+  ClickOobeButton(NetworkScreenView::kScreenId, OobeButton::kNext,
                   JSExecution::kSync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(NetworkScreenView::kScreenId));
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, ClickNetworkOnNetworkScreen) {
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
-  EXPECT_FALSE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  SkipToScreen(NetworkScreenView::kScreenId);
+  EXPECT_FALSE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                             DemoSetupDialog::kNetwork,
                                             ButtonToTag(OobeButton::kNext)));
 
   ClickNetworkListElement(kDefaultNetworkName);
   SimulateNetworkConnected();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, ClickConnectedNetworkOnNetworkScreen) {
   SimulateNetworkConnected();
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
-  EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
+  SkipToScreen(NetworkScreenView::kScreenId);
+  EXPECT_TRUE(IsScreenDialogElementEnabled(NetworkScreenView::kScreenId,
                                            DemoSetupDialog::kNetwork,
                                            ButtonToTag(OobeButton::kNext)));
 
   ClickNetworkListElement(kDefaultNetworkName);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
+  OobeScreenWaiter(EulaView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(EulaView::kScreenId));
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, BackOnNetworkScreen) {
   SimulateNetworkConnected();
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  SkipToScreen(NetworkScreenView::kScreenId);
 
-  ClickOobeButton(OobeScreen::SCREEN_OOBE_NETWORK, OobeButton::kBack,
+  ClickOobeButton(NetworkScreenView::kScreenId, OobeButton::kBack,
                   JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
-  EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  OobeScreenWaiter(DemoPreferencesScreenView::kScreenId).Wait();
+  EXPECT_TRUE(IsScreenShown(DemoPreferencesScreenView::kScreenId));
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, BackOnArcTermsScreen) {
   // User cannot go to ARC ToS screen without accepting eula - simulate that.
   StartupUtils::MarkEulaAccepted();
 
-  SkipToScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
+  SkipToScreen(ArcTermsOfServiceScreenView::kScreenId);
 
-  ClickOobeButton(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE, OobeButton::kBack,
+  ClickOobeButton(ArcTermsOfServiceScreenView::kScreenId, OobeButton::kBack,
                   JSExecution::kSync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, BackOnErrorScreen) {
   SkipToErrorDialog();
 
-  ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  ClickScreenDialogButton(DemoSetupScreenView::kScreenId,
                           DemoSetupDialog::kError, OobeButton::kBack,
                           JSExecution::kAsync);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, RetryOnErrorScreen) {
@@ -1144,25 +1142,25 @@
   enrollment_helper_.ExpectEnrollmentMode(
       policy::EnrollmentConfig::MODE_ATTESTATION);
   enrollment_helper_.ExpectAttestationEnrollmentSuccess();
-  ClickScreenDialogButtonWithSelector(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
+  ClickScreenDialogButtonWithSelector(DemoSetupScreenView::kScreenId,
                                       DemoSetupDialog::kError, "#retryButton",
                                       JSExecution::kAsync);
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, ShowOfflineSetupOptionOnNetworkList) {
   auto* const wizard_controller = WizardController::default_controller();
   wizard_controller->SimulateDemoModeSetupForTesting();
   SimulateOfflineEnvironment();
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  SkipToScreen(NetworkScreenView::kScreenId);
 
   EXPECT_TRUE(IsCustomNetworkListElementShown("offlineDemoSetupListItemName"));
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, NoOfflineSetupOptionOnNetworkList) {
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  SkipToScreen(NetworkScreenView::kScreenId);
   EXPECT_FALSE(IsCustomNetworkListElementShown("offlineDemoSetupListItemName"));
 }
 
@@ -1244,12 +1242,12 @@
   wizard_controller->demo_setup_controller()->set_demo_config(
       DemoSession::DemoModeConfig::kOffline);
 
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
-  SkipToScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+  SkipToScreen(NetworkScreenView::kScreenId);
+  SkipToScreen(DemoSetupScreenView::kScreenId);
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
 
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
@@ -1279,12 +1277,12 @@
   wizard_controller->demo_setup_controller()->set_demo_config(
       DemoSession::DemoModeConfig::kOffline);
 
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
-  SkipToScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+  SkipToScreen(NetworkScreenView::kScreenId);
+  SkipToScreen(DemoSetupScreenView::kScreenId);
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
 
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
@@ -1315,12 +1313,12 @@
   wizard_controller->demo_setup_controller()->set_demo_config(
       DemoSession::DemoModeConfig::kOffline);
 
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
-  SkipToScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+  SkipToScreen(NetworkScreenView::kScreenId);
+  SkipToScreen(DemoSetupScreenView::kScreenId);
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
 
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
@@ -1349,12 +1347,11 @@
   wizard_controller->demo_setup_controller()->set_demo_config(
       DemoSession::DemoModeConfig::kOffline);
 
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK);
-  SkipToScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+  SkipToScreen(NetworkScreenView::kScreenId);
+  SkipToScreen(DemoSetupScreenView::kScreenId);
   // TODO(agawronska): Progress dialog transition is async - extra work is
   // needed to be able to check it reliably.
-  WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
-                      DemoSetupDialog::kError);
+  WaitForScreenDialog(DemoSetupScreenView::kScreenId, DemoSetupDialog::kError);
 
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
   EXPECT_FALSE(StartupUtils::IsDeviceRegistered());
diff --git a/chrome/browser/chromeos/login/enable_debugging_browsertest.cc b/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
index 873ab17..98187c4 100644
--- a/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
+++ b/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
+#include "chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
@@ -193,7 +194,7 @@
 
   void InvokeEnableDebuggingScreen() {
     test::ExecuteOobeJS("cr.ui.Oobe.handleAccelerator('debugging');");
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING).Wait();
+    OobeScreenWaiter(EnableDebuggingScreenView::kScreenId).Wait();
   }
 
   void CloseEnableDebuggingScreen() {
@@ -402,12 +403,12 @@
 
 // Setup screen is automatically shown when the feature is requested.
 IN_PROC_BROWSER_TEST_F(EnableDebuggingRequestedTest, AutoShowSetup) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING).Wait();
+  OobeScreenWaiter(EnableDebuggingScreenView::kScreenId).Wait();
 }
 
 // Canceling auto shown setup screen should close it.
 IN_PROC_BROWSER_TEST_F(EnableDebuggingRequestedTest, CancelAutoShowSetup) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING).Wait();
+  OobeScreenWaiter(EnableDebuggingScreenView::kScreenId).Wait();
   CloseEnableDebuggingScreen();
   test::OobeJS().ExpectHidden("debugging");
 }
diff --git a/chrome/browser/chromeos/login/encryption_migration_browsertest.cc b/chrome/browser/chromeos/login/encryption_migration_browsertest.cc
index 7826284..1d3258f 100644
--- a/chrome/browser/chromeos/login/encryption_migration_browsertest.cc
+++ b/chrome/browser/chromeos/login/encryption_migration_browsertest.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/constants/dbus_paths.h"
@@ -255,7 +256,7 @@
 
 IN_PROC_BROWSER_TEST_F(EncryptionMigrationTest, SkipWithNoPolicySet) {
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("ready-dialog");
   VerifyUiElementVisible("ready-dialog");
@@ -280,7 +281,7 @@
 
 IN_PROC_BROWSER_TEST_F(EncryptionMigrationTest, MigrateWithNoUserPolicySet) {
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("ready-dialog");
   VerifyUiElementVisible("ready-dialog");
@@ -305,7 +306,7 @@
 IN_PROC_BROWSER_TEST_F(EncryptionMigrationTest,
                        ResumeMigrationWithNoUserPolicySet) {
   SetUpStubAuthenticatorAndAttemptLogin(true /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   // Migration is expected to continue immediately.
   RunFullMigrationFlowTest();
@@ -316,7 +317,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   // With kMigrate policy, the migration should start immediately.
   RunFullMigrationFlowTest();
@@ -328,7 +329,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(true /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   RunFullMigrationFlowTest();
 }
@@ -340,7 +341,7 @@
       arc::policy_util::EcryptfsMigrationAction::kAskUser);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   // Verify that ready dialog is not shown, and that the migration started
   // without ask user for confirmation.
@@ -359,7 +360,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMinimalMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("minimal-migration-dialog");
   VerifyUiElementVisible("minimal-migration-dialog");
@@ -389,7 +390,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMinimalMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("minimal-migration-dialog");
   VerifyUiElementVisible("minimal-migration-dialog");
@@ -414,7 +415,7 @@
       cryptohome::DIRCRYPTO_MIGRATION_SUCCESS, 5 /*current*/, 5 /*total*/);
   EXPECT_EQ(0, FakePowerManagerClient::Get()->num_request_restart_calls());
 
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(EncryptionMigrationTest,
@@ -423,7 +424,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("migrating-dialog");
 }
@@ -436,7 +437,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMinimalMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(true /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   RunFullMigrationFlowTest();
 }
@@ -446,7 +447,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMinimalMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("minimal-migration-dialog");
 }
@@ -456,7 +457,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(true /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("minimal-migration-dialog");
   VerifyUiElementVisible("minimal-migration-dialog");
@@ -494,7 +495,7 @@
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
 
   // Wipe is expected to wipe the cryptohome, and force online login.
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 
   EXPECT_FALSE(FakeCryptohomeClient::Get()
                    ->get_id_for_disk_migrated_to_dircrypto()
@@ -506,7 +507,7 @@
   set_free_space(5 * 1000 * 1000);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("insufficient-space-dialog");
   VerifyUiElementVisible("insufficient-space-dialog");
@@ -533,7 +534,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("insufficient-space-dialog");
   VerifyUiElementVisible("insufficient-space-dialog");
@@ -561,7 +562,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(true /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("insufficient-space-dialog");
   VerifyUiElementVisible("insufficient-space-dialog");
@@ -588,7 +589,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("migrating-dialog");
 
@@ -621,7 +622,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("ready-dialog");
   VerifyUiElementVisible("ready-dialog");
@@ -654,7 +655,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(true /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("ready-dialog");
   VerifyUiElementVisible("ready-dialog");
@@ -679,7 +680,7 @@
       arc::policy_util::EcryptfsMigrationAction::kMigrate);
 
   SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */);
-  OobeScreenWaiter(OobeScreen::SCREEN_ENCRYPTION_MIGRATION).Wait();
+  OobeScreenWaiter(EncryptionMigrationScreenView::kScreenId).Wait();
 
   WaitForElementCreation("ready-dialog");
   VerifyUiElementVisible("ready-dialog");
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
index 8b9b91a..3104740 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
@@ -39,14 +39,14 @@
 AutoEnrollmentCheckScreen* AutoEnrollmentCheckScreen::Get(
     ScreenManager* manager) {
   return static_cast<AutoEnrollmentCheckScreen*>(
-      manager->GetScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK));
+      manager->GetScreen(AutoEnrollmentCheckScreenView::kScreenId));
 }
 
 AutoEnrollmentCheckScreen::AutoEnrollmentCheckScreen(
     AutoEnrollmentCheckScreenView* view,
     ErrorScreen* error_screen,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK),
+    : BaseScreen(AutoEnrollmentCheckScreenView::kScreenId),
       view_(view),
       error_screen_(error_screen),
       exit_callback_(exit_callback),
@@ -249,7 +249,7 @@
   error_screen_->SetHideCallback(
       base::BindRepeating(&AutoEnrollmentCheckScreen::OnErrorScreenHidden,
                           weak_ptr_factory_.GetWeakPtr()));
-  error_screen_->SetParentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  error_screen_->SetParentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   error_screen_->Show();
   histogram_helper_->OnErrorShow(error_state);
 }
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_view.h b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_view.h
index 8436f61..2b43e74 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_view.h
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_view.h
@@ -23,8 +23,7 @@
     virtual void OnViewDestroyed(AutoEnrollmentCheckScreenView* view) = 0;
   };
 
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK;
+  constexpr static StaticOobeScreenId kScreenId{"auto-enrollment-check"};
 
   virtual ~AutoEnrollmentCheckScreenView() {}
 
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
index 77cc4d2a..0f1ca69 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
+#include "chrome/browser/chromeos/login/enrollment/enrollment_screen_view.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/test/device_state_mixin.h"
 #include "chrome/browser/chromeos/login/test/enrollment_ui_mixin.h"
@@ -21,6 +22,10 @@
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h"
 #include "chrome/browser/policy/test/local_policy_test_server.h"
+#include "chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/attestation/mock_attestation_flow.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -91,8 +96,8 @@
   }
 
   void TriggerEnrollmentAndSignInSuccessfully() {
-    host()->StartWizard(OobeScreen::SCREEN_OOBE_ENROLLMENT);
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+    host()->StartWizard(EnrollmentScreenView::kScreenId);
+    OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
 
     ASSERT_FALSE(StartupUtils::IsDeviceRegistered());
     ASSERT_FALSE(InstallAttributes::Get()->IsEnterpriseManaged());
@@ -403,7 +408,7 @@
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
   EXPECT_TRUE(InstallAttributes::Get()->IsCloudManaged());
   enrollment_ui_.LeaveDeviceAttributeErrorScreen();
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 // Error during enrollment : Error fetching policy : 500 server error.
@@ -454,8 +459,8 @@
 
 // No state keys on the server. Auto enrollment check should proceed to login.
 IN_PROC_BROWSER_TEST_F(AutoEnrollmentLocalPolicyServer, AutoEnrollmentCheck) {
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 // State keys are present but restore mode is not requested.
@@ -464,8 +469,8 @@
       state_keys_broker(),
       enterprise_management::DeviceStateRetrievalResponse::RESTORE_MODE_NONE,
       kTestDomain));
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 // Reenrollment requested. User can skip.
@@ -475,10 +480,10 @@
       enterprise_management::DeviceStateRetrievalResponse::
           RESTORE_MODE_REENROLLMENT_REQUESTED,
       kTestDomain));
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
   enrollment_screen()->OnCancel();
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 // Reenrollment forced. User can not skip.
@@ -488,8 +493,8 @@
       enterprise_management::DeviceStateRetrievalResponse::
           RESTORE_MODE_REENROLLMENT_ENFORCED,
       kTestDomain));
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
   base::RunLoop loop;
   enrollment_screen()->set_exit_callback_for_testing(
       UserCannotSkipCallback(loop.QuitClosure()));
@@ -504,8 +509,8 @@
       enterprise_management::DeviceStateRetrievalResponse::
           RESTORE_MODE_DISABLED,
       kTestDomain));
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_DEVICE_DISABLED).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(DeviceDisabledScreenView::kScreenId).Wait();
 }
 
 // Attestation enrollment.
@@ -517,7 +522,7 @@
           RESTORE_MODE_REENROLLMENT_ZERO_TOUCH,
       kTestDomain));
 
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
   enrollment_ui_.WaitForStep(test::ui::kEnrollmentStepSuccess);
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
   EXPECT_TRUE(InstallAttributes::Get()->IsCloudManaged());
@@ -526,21 +531,21 @@
 // FRE explicitly required in VPD, but the state keys are missing.
 IN_PROC_BROWSER_TEST_F(AutoEnrollmentNoStateKeys, FREExplicitlyRequired) {
   SetFRERequiredKey("1");
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(AutoEnrollmentCheckScreenView::kScreenId).Wait();
 
   // Chrome waits for state keys to be available, force a timeout.
   FireSafeguardTimer();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_ERROR_MESSAGE).Wait();
+  OobeScreenWaiter(ErrorScreenView::kScreenId).Wait();
   test::OobeJS().ExpectHasNoClass("allow-guest-signin", {"error-message"});
 }
 
 // FRE not explicitly required and the state keys are missing. Should proceed to
 // normal signin.
 IN_PROC_BROWSER_TEST_F(AutoEnrollmentNoStateKeys, FRENotRequired) {
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 // FRE explicitly not required in VPD, so it should not even contact the policy
@@ -555,8 +560,8 @@
           RESTORE_MODE_REENROLLMENT_ENFORCED,
       kTestDomain));
 
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 // FRE is not required when VPD is valid and activate date is not there.
@@ -568,8 +573,8 @@
           RESTORE_MODE_REENROLLMENT_ENFORCED,
       kTestDomain));
 
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 }
 
 // FRE is required when VPD is valid and activate date is there.
@@ -582,8 +587,8 @@
           RESTORE_MODE_REENROLLMENT_ENFORCED,
       kTestDomain));
 
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
 }
 
 // FRE is required when VPD in invalid state.
@@ -596,8 +601,8 @@
           RESTORE_MODE_REENROLLMENT_ENFORCED,
       kTestDomain));
 
-  host()->StartWizard(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId);
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
index d10ffd7..afeae2a 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
@@ -90,12 +90,12 @@
 // static
 EnrollmentScreen* EnrollmentScreen::Get(ScreenManager* manager) {
   return static_cast<EnrollmentScreen*>(
-      manager->GetScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT));
+      manager->GetScreen(EnrollmentScreenView::kScreenId));
 }
 
 EnrollmentScreen::EnrollmentScreen(EnrollmentScreenView* view,
                                    const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT),
+    : BaseScreen(EnrollmentScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback),
       weak_ptr_factory_(this) {
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc
index 7bde3e69..389d89a 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc
@@ -42,7 +42,7 @@
   }
   void SetUpOnMainThread() override {
     InProcessBrowserTest::SetUpOnMainThread();
-    ShowLoginWizard(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+    ShowLoginWizard(EnrollmentScreenView::kScreenId);
     EXPECT_EQ(WizardController::default_controller()->current_screen(),
               enrollment_screen());
     enrollment_screen()->set_exit_callback_for_testing(base::BindRepeating(
@@ -138,7 +138,7 @@
 
   // Run through the flow
   view->Show();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
   checker.ExpectTrue(
       "window.getComputedStyle(document.getElementById('oauth-enroll-step-"
       "signin')).display !== 'none'");
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen_view.h b/chrome/browser/chromeos/login/enrollment/enrollment_screen_view.h
index aa26eb1..43b941d6 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen_view.h
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen_view.h
@@ -47,8 +47,7 @@
                                            const std::string& location) = 0;
   };
 
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_OOBE_ENROLLMENT;
+  constexpr static StaticOobeScreenId kScreenId{"oauth-enrollment"};
 
   virtual ~EnrollmentScreenView() {}
 
diff --git a/chrome/browser/chromeos/login/enrollment/hands_off_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enrollment/hands_off_enrollment_browsertest.cc
index 29d9200..c88c927 100644
--- a/chrome/browser/chromeos/login/enrollment/hands_off_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enrollment/hands_off_enrollment_browsertest.cc
@@ -14,6 +14,8 @@
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
+#include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill/shill_service_client.h"
@@ -98,11 +100,11 @@
   SimulateNetworkConnected();
 
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_OOBE_WELCOME);
+      WelcomeView::kScreenId);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
 
   base::RunLoop().RunUntilIdle();
 
@@ -118,13 +120,13 @@
   enrollment_helper_.DisableAttributePromptUpdate();
   enrollment_helper_.SetupClearAuth();
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_OOBE_WELCOME);
+      WelcomeView::kScreenId);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
 
   SimulateNetworkConnected();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
 
   base::RunLoop().RunUntilIdle();
 
@@ -148,16 +150,16 @@
   SimulateNetworkConnected();
 
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_OOBE_WELCOME);
+      WelcomeView::kScreenId);
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+  OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
 
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(
-      OobeScreen::SCREEN_OOBE_ENROLLMENT.AsId(),
+      EnrollmentScreenView::kScreenId.AsId(),
       WizardController::default_controller()->current_screen()->screen_id());
   EXPECT_FALSE(ExistingUserController::current_controller());
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 1b2db68..6efe625 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -168,8 +168,8 @@
   void ShowEnrollmentScreen() {
     LoginDisplayHost* host = LoginDisplayHost::default_host();
     ASSERT_TRUE(host != nullptr);
-    host->StartWizard(OobeScreen::SCREEN_OOBE_ENROLLMENT);
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+    host->StartWizard(EnrollmentScreenView::kScreenId);
+    OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
     ASSERT_TRUE(enrollment_screen() != nullptr);
     ASSERT_TRUE(WizardController::default_controller() != nullptr);
     ASSERT_FALSE(StartupUtils::IsOobeCompleted());
diff --git a/chrome/browser/chromeos/login/eula_browsertest.cc b/chrome/browser/chromeos/login/eula_browsertest.cc
index e890981..072197b 100644
--- a/chrome/browser/chromeos/login/eula_browsertest.cc
+++ b/chrome/browser/chromeos/login/eula_browsertest.cc
@@ -120,9 +120,9 @@
   }
 
   void ShowEulaScreen() {
-    LoginDisplayHost::default_host()->StartWizard(OobeScreen::SCREEN_OOBE_EULA);
+    LoginDisplayHost::default_host()->StartWizard(EulaView::kScreenId);
     OverrideOnlineEulaUrl();
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
+    OobeScreenWaiter(EulaView::kScreenId).Wait();
   }
 
   std::string GetLoadedEulaAsText() {
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 3392907..bc862582 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -65,7 +65,12 @@
 #include "chrome/browser/signin/chrome_device_id_helper.h"
 #include "chrome/browser/ui/ash/system_tray_client.h"
 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
+#include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
+#include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
@@ -739,11 +744,11 @@
 }
 
 void ExistingUserController::ShowWrongHWIDScreen() {
-  GetLoginDisplayHost()->StartWizard(OobeScreen::SCREEN_WRONG_HWID);
+  GetLoginDisplayHost()->StartWizard(WrongHWIDScreenView::kScreenId);
 }
 
 void ExistingUserController::ShowUpdateRequiredScreen() {
-  GetLoginDisplayHost()->StartWizard(OobeScreen::SCREEN_UPDATE_REQUIRED);
+  GetLoginDisplayHost()->StartWizard(UpdateRequiredView::kScreenId);
 }
 
 void ExistingUserController::Signout() {
@@ -789,30 +794,30 @@
 }
 
 void ExistingUserController::ShowEnrollmentScreen() {
-  GetLoginDisplayHost()->StartWizard(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  GetLoginDisplayHost()->StartWizard(EnrollmentScreenView::kScreenId);
 }
 
 void ExistingUserController::ShowEnableDebuggingScreen() {
-  GetLoginDisplayHost()->StartWizard(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING);
+  GetLoginDisplayHost()->StartWizard(EnableDebuggingScreenView::kScreenId);
 }
 
 void ExistingUserController::ShowKioskEnableScreen() {
-  GetLoginDisplayHost()->StartWizard(OobeScreen::SCREEN_KIOSK_ENABLE);
+  GetLoginDisplayHost()->StartWizard(KioskEnableScreenView::kScreenId);
 }
 
 void ExistingUserController::ShowKioskAutolaunchScreen() {
-  GetLoginDisplayHost()->StartWizard(OobeScreen::SCREEN_KIOSK_AUTOLAUNCH);
+  GetLoginDisplayHost()->StartWizard(KioskAutolaunchScreenView::kScreenId);
 }
 
 void ExistingUserController::ShowEncryptionMigrationScreen(
     const UserContext& user_context,
     EncryptionMigrationMode migration_mode) {
-  GetLoginDisplayHost()->StartWizard(OobeScreen::SCREEN_ENCRYPTION_MIGRATION);
+  GetLoginDisplayHost()->StartWizard(EncryptionMigrationScreenView::kScreenId);
 
   EncryptionMigrationScreen* migration_screen =
       static_cast<EncryptionMigrationScreen*>(
           WizardController::default_controller()->GetScreen(
-              OobeScreen::SCREEN_ENCRYPTION_MIGRATION));
+              EncryptionMigrationScreenView::kScreenId));
   DCHECK(migration_screen);
   migration_screen->SetUserContext(user_context);
   migration_screen->SetMode(migration_mode);
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index 20b9e7475..cb099cf 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -41,6 +41,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -269,7 +270,7 @@
   session_manager_test_api.InjectStubUserContext(user_context);
   EXPECT_CALL(*mock_login_display_, SetUIEnabled(true)).Times(1);
   EXPECT_CALL(*mock_login_display_host_,
-              StartWizard(OobeScreenId(OobeScreen::SCREEN_TERMS_OF_SERVICE)))
+              StartWizard(OobeScreenId(TermsOfServiceScreenView::kScreenId)))
       .Times(0);
 
   content::WindowedNotificationObserver profile_prepared_observer(
@@ -435,7 +436,7 @@
     // There may be in-session oobe or an initial login screen created from
     // --login-manager.
     EXPECT_CALL(*mock_login_display_host_,
-                StartWizard(OobeScreen::SCREEN_TERMS_OF_SERVICE.AsId()))
+                StartWizard(TermsOfServiceScreenView::kScreenId.AsId()))
         .Times(AnyNumber());
     EXPECT_CALL(*mock_login_display_, SetUIEnabled(false)).Times(AnyNumber());
     EXPECT_CALL(*mock_login_display_, SetUIEnabled(true)).Times(AnyNumber());
diff --git a/chrome/browser/chromeos/login/hid_detection_browsertest.cc b/chrome/browser/chromeos/login/hid_detection_browsertest.cc
index 693b575..1652b389 100644
--- a/chrome/browser/chromeos/login/hid_detection_browsertest.cc
+++ b/chrome/browser/chromeos/login/hid_detection_browsertest.cc
@@ -9,6 +9,8 @@
 #include "chrome/browser/chromeos/login/test/hid_controller_mixin.h"
 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
+#include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 
 using testing::_;
 
@@ -37,11 +39,11 @@
 };
 
 IN_PROC_BROWSER_TEST_F(HidDetectionTest, NoDevicesConnected) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_HID_DETECTION).Wait();
+  OobeScreenWaiter(HIDDetectionView::kScreenId).Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(HidDetectionSkipTest, BothDevicesPreConnected) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 03c99ff3..be3b2d2 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "apps/test/app_window_waiter.h"
+#include "ash/public/cpp/ash_switches.h"
 #include "ash/public/interfaces/login_screen_test_api.test-mojom-test-utils.h"
 #include "ash/public/interfaces/wallpaper.mojom.h"
 #include "base/bind.h"
@@ -54,6 +55,10 @@
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
@@ -592,7 +597,7 @@
     if (wizard_controller)
       wizard_controller->SkipToLoginForTesting(LoginScreenContext());
 
-    OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+    OobeScreenWaiter(GaiaView::kScreenId).Wait();
   }
 
   void PrepareAppLaunch() {
@@ -738,7 +743,7 @@
     // Start app launch and wait for network connectivity timeout.
     StartAppLaunchFromLoginScreen(
         NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE);
-    OobeScreenWaiter splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
+    OobeScreenWaiter splash_waiter(AppLaunchSplashScreenView::kScreenId);
     splash_waiter.Wait();
     WaitForAppLaunchNetworkTimeout();
 
@@ -757,7 +762,7 @@
     test::OobeJS().ExpectTrue("$('pod-row').alwaysFocusSinglePod");
 
     // A network error screen should be shown after authenticating.
-    OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
+    OobeScreenWaiter error_screen_waiter(ErrorScreenView::kScreenId);
     static_cast<AppLaunchSigninScreen::Delegate*>(GetAppLaunchController())
         ->OnOwnerSigninSuccess();
     error_screen_waiter.Wait();
@@ -967,11 +972,11 @@
   // Start app launch and wait for network connectivity timeout.
   StartAppLaunchFromLoginScreen(
       NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
-  OobeScreenWaiter splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
+  OobeScreenWaiter splash_waiter(AppLaunchSplashScreenView::kScreenId);
   splash_waiter.Wait();
 
   // A network error screen should be shown after authenticating.
-  OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
+  OobeScreenWaiter error_screen_waiter(ErrorScreenView::kScreenId);
   // Simulate Ctrl+Alt+N accelerator.
   GetLoginUI()->CallJavascriptFunctionUnsafe(
       "cr.ui.Oobe.handleAccelerator", base::Value("app_launch_network_config"));
@@ -997,7 +1002,7 @@
   // Start app launch and wait for network connectivity timeout.
   StartAppLaunchFromLoginScreen(
       NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE);
-  OobeScreenWaiter splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
+  OobeScreenWaiter splash_waiter(AppLaunchSplashScreenView::kScreenId);
   splash_waiter.Wait();
   WaitForAppLaunchNetworkTimeout();
 
@@ -1017,7 +1022,7 @@
   StartAppLaunchFromLoginScreen(
       NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL);
 
-  OobeScreenWaiter app_splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
+  OobeScreenWaiter app_splash_waiter(AppLaunchSplashScreenView::kScreenId);
   app_splash_waiter.set_no_assert_last_screen();
   app_splash_waiter.Wait();
 
@@ -1025,7 +1030,7 @@
 
   // Network error should show up automatically since this test does not
   // require owner auth to configure network.
-  OobeScreenWaiter(OobeScreen::SCREEN_ERROR_MESSAGE).Wait();
+  OobeScreenWaiter(ErrorScreenView::kScreenId).Wait();
 
   ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog());
   SimulateNetworkOnline();
@@ -1035,7 +1040,7 @@
 IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppUserCancel) {
   // Make fake_cws_ return empty update response.
   set_test_app_version("");
-  OobeScreenWaiter splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
+  OobeScreenWaiter splash_waiter(AppLaunchSplashScreenView::kScreenId);
   StartAppLaunchFromLoginScreen(
       NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE);
   splash_waiter.Wait();
@@ -1087,7 +1092,7 @@
 
   // Start login screen after configuring auto launch app since the warning
   // is triggered when switching to login screen.
-  wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  wizard_controller->AdvanceToScreen(WelcomeView::kScreenId);
   ReloadAutolaunchKioskApps();
   EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
   EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
@@ -1120,7 +1125,7 @@
 
   // Start login screen after configuring auto launch app since the warning
   // is triggered when switching to login screen.
-  wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  wizard_controller->AdvanceToScreen(WelcomeView::kScreenId);
   ReloadAutolaunchKioskApps();
   EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
   EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
@@ -1163,7 +1168,7 @@
 
   // Wait for the login UI to come up and switch to the kiosk_enable screen.
   wizard_controller->SkipToLoginForTesting(LoginScreenContext());
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
                                              base::Value("kiosk_enable"));
 
@@ -1199,7 +1204,7 @@
 
   // Wait for the login UI to come up and switch to the kiosk_enable screen.
   wizard_controller->SkipToLoginForTesting(LoginScreenContext());
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
                                              base::Value("kiosk_enable"));
 
@@ -1232,7 +1237,7 @@
 
   // Wait for the login UI to come up and switch to the kiosk_enable screen.
   wizard_controller->SkipToLoginForTesting(LoginScreenContext());
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
                                              base::Value("kiosk_enable"));
 
@@ -1252,7 +1257,7 @@
 
   // Show signin screen again.
   LoginDisplayHost::default_host()->StartSignInScreen(LoginScreenContext());
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 
   // Show kiosk enable screen again.
   GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
@@ -1315,7 +1320,7 @@
   chromeos::WizardController* wizard_controller =
       chromeos::WizardController::default_controller();
   ASSERT_TRUE(wizard_controller);
-  wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  wizard_controller->AdvanceToScreen(WelcomeView::kScreenId);
   ReloadAutolaunchKioskApps();
   wizard_controller->SkipToLoginForTesting(LoginScreenContext());
   content::WindowedNotificationObserver(
@@ -1330,7 +1335,7 @@
       CrosSettingsProvider::PERMANENTLY_UNTRUSTED);
 
   // Check that the attempt to auto-launch a kiosk app fails with an error.
-  OobeScreenWaiter(OobeScreen::SCREEN_ERROR_MESSAGE).Wait();
+  OobeScreenWaiter(ErrorScreenView::kScreenId).Wait();
 }
 
 // Verifies available volumes for kiosk apps in kiosk session.
@@ -1393,6 +1398,11 @@
     KioskTest::SetUp();
   }
 
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
+    KioskTest::SetUpCommandLine(command_line);
+  }
+
   void TearDown() override {
     disks::DiskMountManager::Shutdown();
 
@@ -2536,7 +2546,7 @@
 
   // Start login screen after configuring auto launch app since the warning
   // is triggered when switching to login screen.
-  wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  wizard_controller->AdvanceToScreen(WelcomeView::kScreenId);
   ReloadAutolaunchKioskApps();
   wizard_controller->SkipToLoginForTesting(LoginScreenContext());
 
diff --git a/chrome/browser/chromeos/login/login_ui_browsertest.cc b/chrome/browser/chromeos/login/login_ui_browsertest.cc
index 8fa449a3..5b587bb 100644
--- a/chrome/browser/chromeos/login/login_ui_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_browsertest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/chromeos/login/test/js_checker.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
@@ -82,7 +83,7 @@
 // Tests that the default first screen is the welcome screen after OOBE
 // when auto enrollment is enabled and device is not yet enrolled.
 IN_PROC_BROWSER_TEST_F(LoginUITest, InterruptedAutoStartEnrollment) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(LoginUITest, OobeNoExceptions) {
diff --git a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
index 5317c05..44cb1e5 100644
--- a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -266,7 +267,7 @@
 
   // Switch to Gaia.
   ASSERT_TRUE(test::LoginScreenTester().ClickAddUserButton());
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
   CheckGaiaKeyboard();
 
   // Switch back.
diff --git a/chrome/browser/chromeos/login/login_ui_shelf_visibility_browsertest.cc b/chrome/browser/chromeos/login/login_ui_shelf_visibility_browsertest.cc
index ef2de1fb..d344ed8 100644
--- a/chrome/browser/chromeos/login/login_ui_shelf_visibility_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_shelf_visibility_browsertest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h"
 #include "net/dns/mock_host_resolver.h"
 
 namespace chromeos {
@@ -74,7 +75,7 @@
                                 FakeGaiaMixin::kEmptyUserServices);
 
   // Sync consent is the first post-login screen shown when a new user signs in.
-  OobeScreenWaiter(OobeScreen::SCREEN_SYNC_CONSENT).Wait();
+  OobeScreenWaiter(SyncConsentScreenView::kScreenId).Wait();
 
   EXPECT_FALSE(test::LoginScreenTester().IsGuestButtonShown());
   EXPECT_FALSE(test::LoginScreenTester().IsAddUserButtonShown());
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index cd0f620..c0947e8 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -97,7 +97,7 @@
                             false,   // shift
                             true,    // alt
                             false);  // command
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_ENROLLMENT).Wait();
+  OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
index 8481897..facfa01 100644
--- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -22,8 +22,14 @@
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
+#include "chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/update_engine_client.h"
 #include "content/public/browser/notification_service.h"
@@ -139,7 +145,7 @@
         chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
         content::NotificationService::AllSources());
     observer.Wait();
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+    OobeScreenWaiter(WelcomeView::kScreenId).Wait();
   }
 
   void RunWelcomeScreenChecks() {
@@ -165,7 +171,7 @@
   }
 
   void WaitForNetworkSelectionScreen() {
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
+    OobeScreenWaiter(NetworkScreenView::kScreenId).Wait();
     LOG(INFO)
         << "OobeInteractiveUITest: Switched to 'network-selection' screen.";
   }
@@ -183,7 +189,7 @@
   }
 
   void WaitForEulaScreen() {
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
+    OobeScreenWaiter(EulaView::kScreenId).Wait();
     LOG(INFO) << "OobeInteractiveUITest: Switched to 'eula' screen.";
   }
 
@@ -200,7 +206,7 @@
   }
 
   void WaitForUpdateScreen() {
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
+    OobeScreenWaiter(UpdateView::kScreenId).Wait();
     test::OobeJS().CreateVisibilityWaiter(true, {"update"})->Wait();
 
     LOG(INFO) << "OobeInteractiveUITest: Switched to 'update' screen.";
@@ -209,14 +215,14 @@
   void ExitUpdateScreenNoUpdate() {
     UpdateScreen* screen = static_cast<UpdateScreen*>(
         WizardController::default_controller()->GetScreen(
-            OobeScreen::SCREEN_OOBE_UPDATE));
+            UpdateView::kScreenId));
     UpdateEngineClient::Status status;
     status.status = UpdateEngineClient::UPDATE_STATUS_ERROR;
     screen->UpdateStatusChanged(status);
   }
 
   void WaitForGaiaSignInScreen() {
-    OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+    OobeScreenWaiter(GaiaView::kScreenId).Wait();
     LOG(INFO) << "OobeInteractiveUITest: Switched to 'gaia-signin' screen.";
   }
 
@@ -232,25 +238,25 @@
 
   void WaitForSyncConsentScreen() {
     LOG(INFO) << "OobeInteractiveUITest: Waiting for 'sync-consent' screen.";
-    OobeScreenWaiter(OobeScreen::SCREEN_SYNC_CONSENT).Wait();
+    OobeScreenWaiter(SyncConsentScreenView::kScreenId).Wait();
   }
 
   void ExitScreenSyncConsent() {
     SyncConsentScreen* screen = static_cast<SyncConsentScreen*>(
         WizardController::default_controller()->GetScreen(
-            OobeScreen::SCREEN_SYNC_CONSENT));
+            SyncConsentScreenView::kScreenId));
 
     screen->SetProfileSyncDisabledByPolicyForTesting(true);
     screen->OnStateChanged(nullptr);
     LOG(INFO) << "OobeInteractiveUITest: Waiting for 'sync-consent' screen "
                  "to close.";
-    OobeScreenExitWaiter(OobeScreen::SCREEN_SYNC_CONSENT).Wait();
+    OobeScreenExitWaiter(SyncConsentScreenView::kScreenId).Wait();
   }
 
   void WaitForFingerprintScreen() {
     LOG(INFO)
         << "OobeInteractiveUITest: Waiting for 'fingerprint-setup' screen.";
-    OobeScreenWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+    OobeScreenWaiter(FingerprintSetupScreenView::kScreenId).Wait();
     LOG(INFO) << "OobeInteractiveUITest: Waiting for fingerprint setup screen "
                  "to show.";
     test::OobeJS().CreateVisibilityWaiter(true, {"fingerprint-setup"})->Wait();
@@ -292,12 +298,12 @@
         "$('fingerprint-setup-impl').$.setupFingerprintLater.click()");
     LOG(INFO) << "OobeInteractiveUITest: Waiting for fingerprint setup screen "
                  "to close.";
-    OobeScreenExitWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+    OobeScreenExitWaiter(FingerprintSetupScreenView::kScreenId).Wait();
     LOG(INFO) << "OobeInteractiveUITest: 'fingerprint-setup' screen done.";
   }
 
   void WaitForDiscoverScreen() {
-    OobeScreenWaiter(OobeScreen::SCREEN_DISCOVER).Wait();
+    OobeScreenWaiter(DiscoverScreenView::kScreenId).Wait();
     LOG(INFO) << "OobeInteractiveUITest: Switched to 'discover' screen.";
   }
 
@@ -322,7 +328,7 @@
     test::OobeJS().ExecuteAsync(
         "$('discover-impl').root.querySelector('discover-pin-setup-module')."
         "$.setupSkipButton.click()");
-    OobeScreenExitWaiter(OobeScreen::SCREEN_DISCOVER).Wait();
+    OobeScreenExitWaiter(DiscoverScreenView::kScreenId).Wait();
     LOG(INFO) << "OobeInteractiveUITest: 'discover' screen done.";
   }
 
diff --git a/chrome/browser/chromeos/login/oobe_screen.cc b/chrome/browser/chromeos/login/oobe_screen.cc
index d6c7989..662d6ad 100644
--- a/chrome/browser/chromeos/login/oobe_screen.cc
+++ b/chrome/browser/chromeos/login/oobe_screen.cc
@@ -32,52 +32,28 @@
   return OobeScreenId(name);
 }
 
+// OobeScreenId instances should always be attached to their associated handler;
+// the list below contains only OobeScreenId instances that do not have a
+// handler.
+//
+// Ideally this list should contain only special or helper screens, e.g., those
+// without a JS counterpart.
+//
+// TODO(crbug.com/958905): Reduce this list to only special or helper screens
+
 // static
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_HID_DETECTION;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_WELCOME;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_NETWORK;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_EULA;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_UPDATE;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_ENROLLMENT;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_RESET;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_GAIA_SIGNIN;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_ACCOUNT_PICKER;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_KIOSK_AUTOLAUNCH;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_KIOSK_ENABLE;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_ERROR_MESSAGE;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_TPM_ERROR;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_PASSWORD_CHANGED;
 constexpr StaticOobeScreenId
     OobeScreen::SCREEN_CREATE_SUPERVISED_USER_FLOW_DEPRECATED;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_TERMS_OF_SERVICE;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_WRONG_HWID;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_APP_LAUNCH_SPLASH;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_ARC_KIOSK_SPLASH;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_CONFIRM_PASSWORD;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_FATAL_ERROR;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_DEVICE_DISABLED;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_USER_SELECTION;
 constexpr StaticOobeScreenId
     OobeScreen::SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_ENCRYPTION_MIGRATION;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_SUPERVISION_TRANSITION;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_UPDATE_REQUIRED;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_SPECIAL_LOGIN;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_SPECIAL_OOBE;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_TEST_NO_WINDOW;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_SYNC_CONSENT;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_FINGERPRINT_SETUP;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_DEMO_SETUP;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_RECOMMEND_APPS;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_APP_DOWNLOADING;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_DISCOVER;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_MARKETING_OPT_IN;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_MULTIDEVICE_SETUP;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_UNKNOWN;
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/oobe_screen.h b/chrome/browser/chromeos/login/oobe_screen.h
index a3e1caa..404a0e3b 100644
--- a/chrome/browser/chromeos/login/oobe_screen.h
+++ b/chrome/browser/chromeos/login/oobe_screen.h
@@ -39,50 +39,18 @@
 };
 
 struct OobeScreen {
-  constexpr static StaticOobeScreenId SCREEN_OOBE_HID_DETECTION{
-      "hid-detection"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_WELCOME{"connect"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_NETWORK{"network-selection"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_EULA{"eula"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_UPDATE{"update"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_ENABLE_DEBUGGING{"debugging"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_ENROLLMENT{
-      "oauth-enrollment"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_RESET{"reset"};
-  constexpr static StaticOobeScreenId SCREEN_GAIA_SIGNIN{"gaia-signin"};
   constexpr static StaticOobeScreenId SCREEN_ACCOUNT_PICKER{"account-picker"};
-  constexpr static StaticOobeScreenId SCREEN_KIOSK_AUTOLAUNCH{"autolaunch"};
-  constexpr static StaticOobeScreenId SCREEN_KIOSK_ENABLE{"kiosk-enable"};
-  constexpr static StaticOobeScreenId SCREEN_ERROR_MESSAGE{"error-message"};
+
   constexpr static StaticOobeScreenId SCREEN_TPM_ERROR{"tpm-error-message"};
   constexpr static StaticOobeScreenId SCREEN_PASSWORD_CHANGED{
       "password-changed"};
   constexpr static StaticOobeScreenId
       SCREEN_CREATE_SUPERVISED_USER_FLOW_DEPRECATED{"supervised-user-creation"};
-  constexpr static StaticOobeScreenId SCREEN_TERMS_OF_SERVICE{
-      "terms-of-service"};
-  constexpr static StaticOobeScreenId SCREEN_ARC_TERMS_OF_SERVICE{"arc-tos"};
-  constexpr static StaticOobeScreenId SCREEN_WRONG_HWID{"wrong-hwid"};
-  constexpr static StaticOobeScreenId SCREEN_AUTO_ENROLLMENT_CHECK{
-      "auto-enrollment-check"};
-  constexpr static StaticOobeScreenId SCREEN_APP_LAUNCH_SPLASH{
-      "app-launch-splash"};
-  constexpr static StaticOobeScreenId SCREEN_ARC_KIOSK_SPLASH{
-      "arc-kiosk-splash"};
   constexpr static StaticOobeScreenId SCREEN_CONFIRM_PASSWORD{
       "confirm-password"};
   constexpr static StaticOobeScreenId SCREEN_FATAL_ERROR{"fatal-error"};
-  constexpr static StaticOobeScreenId SCREEN_DEVICE_DISABLED{"device-disabled"};
-  constexpr static StaticOobeScreenId SCREEN_USER_SELECTION{"userBoard"};
   constexpr static StaticOobeScreenId SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE{
       "ad-password-change"};
-  constexpr static StaticOobeScreenId SCREEN_ENCRYPTION_MIGRATION{
-      "encryption-migration"};
-  constexpr static StaticOobeScreenId SCREEN_SUPERVISION_TRANSITION{
-      "supervision-transition"};
-  constexpr static StaticOobeScreenId SCREEN_UPDATE_REQUIRED{"update-required"};
-  constexpr static StaticOobeScreenId SCREEN_ASSISTANT_OPTIN_FLOW{
-      "assistant-optin-flow"};
 
   // Special "first screen" that initiates login flow.
   constexpr static StaticOobeScreenId SCREEN_SPECIAL_LOGIN{"login"};
@@ -91,19 +59,6 @@
   // Special test value that commands not to create any window yet.
   constexpr static StaticOobeScreenId SCREEN_TEST_NO_WINDOW{"test:nowindow"};
 
-  constexpr static StaticOobeScreenId SCREEN_SYNC_CONSENT{"sync-consent"};
-  constexpr static StaticOobeScreenId SCREEN_FINGERPRINT_SETUP{
-      "fingerprint-setup"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_DEMO_SETUP{"demo-setup"};
-  constexpr static StaticOobeScreenId SCREEN_OOBE_DEMO_PREFERENCES{
-      "demo-preferences"};
-  constexpr static StaticOobeScreenId SCREEN_RECOMMEND_APPS{"recommend-apps"};
-  constexpr static StaticOobeScreenId SCREEN_APP_DOWNLOADING{"app-downloading"};
-  constexpr static StaticOobeScreenId SCREEN_DISCOVER{"discover"};
-  constexpr static StaticOobeScreenId SCREEN_MARKETING_OPT_IN{
-      "marketing-opt-in"};
-  constexpr static StaticOobeScreenId SCREEN_MULTIDEVICE_SETUP{
-      "multidevice-setup"};
   constexpr static StaticOobeScreenId SCREEN_UNKNOWN{"unknown"};
 };
 
diff --git a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
index 755de0b6..0b37992 100644
--- a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
+++ b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
 #include "chrome/browser/ui/login/login_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/notification_details.h"
@@ -108,7 +109,7 @@
   }
 
   {
-    OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_GAIA_SIGNIN);
+    OobeScreenWaiter screen_waiter(GaiaView::kScreenId);
     ProxyAuthDialogWaiter auth_dialog_waiter;
     ASSERT_TRUE(test::LoginScreenTester().ClickAddUserButton());
     screen_waiter.Wait();
diff --git a/chrome/browser/chromeos/login/reset_browsertest.cc b/chrome/browser/chromeos/login/reset_browsertest.cc
index 1127c60..293b682 100644
--- a/chrome/browser/chromeos/login/reset_browsertest.cc
+++ b/chrome/browser/chromeos/login/reset_browsertest.cc
@@ -19,6 +19,9 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -90,7 +93,7 @@
   // Simulates reset screen request from views based login.
   void InvokeResetScreen() {
     chromeos::LoginDisplayHost::default_host()->ShowResetScreen();
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+    OobeScreenWaiter(ResetView::kScreenId).Wait();
   }
 
  private:
@@ -231,9 +234,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ResetOobeTest, ResetOnWelcomeScreen) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
   InvokeResetScreen();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
   test::OobeJS().ExpectVisible("reset");
 
   ClickResetButton();
@@ -243,14 +246,14 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ResetOobeTest, RequestAndCancleResetOnWelcomeScreen) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
   InvokeResetScreen();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
   test::OobeJS().ExpectVisible("reset");
 
   CloseResetScreen();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
   test::OobeJS().ExpectHidden("reset");
 
   EXPECT_EQ(0, FakePowerManagerClient::Get()->num_request_restart_calls());
@@ -308,7 +311,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ResetFirstAfterBootTest, ShowAfterBootIfRequested) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
   test::OobeJS().CreateVisibilityWaiter(true, {"reset"})->Wait();
   CloseResetScreen();
   test::OobeJS().CreateVisibilityWaiter(false, {"reset"})->Wait();
@@ -331,7 +334,7 @@
   EXPECT_EQ(1, FakeSessionManagerClient::Get()->start_device_wipe_call_count());
   EXPECT_EQ(0, update_engine_client_->rollback_call_count());
   CloseResetScreen();
-  OobeScreenExitWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenExitWaiter(ResetView::kScreenId).Wait();
 
   // Next invocation leads to rollback view.
   PrefService* prefs = g_browser_process->local_state();
@@ -364,7 +367,7 @@
   EXPECT_EQ(1, FakeSessionManagerClient::Get()->start_device_wipe_call_count());
   EXPECT_EQ(0, update_engine_client_->rollback_call_count());
   CloseResetScreen();
-  OobeScreenExitWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenExitWaiter(ResetView::kScreenId).Wait();
 
   // Next invocation leads to simple reset, not rollback view.
   prefs->SetBoolean(prefs::kFactoryResetRequested, true);
@@ -372,7 +375,7 @@
   InvokeRollbackOption();  // Shows rollback.
   ClickDismissConfirmationButton();
   CloseResetScreen();
-  OobeScreenExitWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenExitWaiter(ResetView::kScreenId).Wait();
 
   InvokeResetScreen();
   ClickToConfirmButton();
@@ -381,7 +384,7 @@
   EXPECT_EQ(2, FakeSessionManagerClient::Get()->start_device_wipe_call_count());
   EXPECT_EQ(0, update_engine_client_->rollback_call_count());
   CloseResetScreen();
-  OobeScreenExitWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenExitWaiter(ResetView::kScreenId).Wait();
 
   prefs->SetBoolean(prefs::kFactoryResetRequested, true);
   InvokeResetScreen();
@@ -401,7 +404,7 @@
 
 IN_PROC_BROWSER_TEST_F(ResetFirstAfterBootTestWithRollback,
                        ErrorOnRollbackRequested) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
   EXPECT_EQ(0, FakePowerManagerClient::Get()->num_request_restart_calls());
   EXPECT_EQ(0, FakeSessionManagerClient::Get()->start_device_wipe_call_count());
   EXPECT_EQ(0, update_engine_client_->rollback_call_count());
@@ -416,7 +419,7 @@
   UpdateEngineClient::Status error_update_status;
   error_update_status.status = UpdateEngineClient::UPDATE_STATUS_ERROR;
   update_engine_client_->NotifyObserversThatStatusChanged(error_update_status);
-  OobeScreenWaiter(OobeScreen::SCREEN_ERROR_MESSAGE).Wait();
+  OobeScreenWaiter(ErrorScreenView::kScreenId).Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(ResetFirstAfterBootTestWithRollback,
@@ -426,7 +429,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ResetFirstAfterBootTestWithRollback, RevertAfterCancel) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
   EXPECT_EQ(0, FakePowerManagerClient::Get()->num_request_restart_calls());
   EXPECT_EQ(0, FakeSessionManagerClient::Get()->start_device_wipe_call_count());
   EXPECT_EQ(0, update_engine_client_->rollback_call_count());
@@ -440,10 +443,10 @@
       ->Wait();
 
   CloseResetScreen();
-  OobeScreenExitWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenExitWaiter(ResetView::kScreenId).Wait();
 
   InvokeResetScreen();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
 
   InvokeRollbackOption();
   test::OobeJS()
@@ -464,7 +467,7 @@
 
 IN_PROC_BROWSER_TEST_F(ResetTestWithTpmFirmwareUpdate,
                        ResetFromSigninWithFirmwareUpdate) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
 
   ASSERT_TRUE(HasPendingTpmFirmwareUpdateCheck());
   FinishPendingTpmFirmwareUpdateCheck({tpm_firmware_update::Mode::kPowerwash});
@@ -501,7 +504,7 @@
 
 IN_PROC_BROWSER_TEST_F(ResetTestWithTpmFirmwareUpdate,
                        TpmFirmwareUpdateAvailableButNotSelected) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
 
   ASSERT_TRUE(HasPendingTpmFirmwareUpdateCheck());
   FinishPendingTpmFirmwareUpdateCheck({tpm_firmware_update::Mode::kPowerwash});
@@ -528,7 +531,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ResetTestWithTpmFirmwareUpdate, ResetWithTpmCleanUp) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
 
   EXPECT_FALSE(HasPendingTpmFirmwareUpdateCheck());
   test::OobeJS()
@@ -563,7 +566,7 @@
 
 IN_PROC_BROWSER_TEST_F(ResetTestWithTpmFirmwareUpdate,
                        ResetWithTpmUpdatePreservingDeviceState) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
 
   EXPECT_FALSE(HasPendingTpmFirmwareUpdateCheck());
   test::OobeJS()
@@ -602,7 +605,7 @@
 // settings, or by policy).
 IN_PROC_BROWSER_TEST_F(ResetTestWithTpmFirmwareUpdate,
                        TpmFirmwareUpdateRequestedBeforeShowNotEditable) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
 
   EXPECT_FALSE(HasPendingTpmFirmwareUpdateCheck());
   test::OobeJS()
@@ -642,7 +645,7 @@
 
 IN_PROC_BROWSER_TEST_F(ResetTestWithTpmFirmwareUpdate,
                        AvailableTpmUpdateModesChangeDuringRequest) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_RESET).Wait();
+  OobeScreenWaiter(ResetView::kScreenId).Wait();
 
   EXPECT_FALSE(HasPendingTpmFirmwareUpdateCheck());
   test::OobeJS()
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index 52c0246..c6a54ad 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/ash_switches.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -970,6 +971,21 @@
   DISALLOW_COPY_AND_ASSIGN(SAMLPolicyTest);
 };
 
+class SAMLPolicyTestWebUILogin : public SAMLPolicyTest {
+ public:
+  SAMLPolicyTestWebUILogin() = default;
+  ~SAMLPolicyTestWebUILogin() override = default;
+
+  // SAMLPolicyTest:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
+    SAMLPolicyTest::SetUpCommandLine(command_line);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SAMLPolicyTestWebUILogin);
+};
+
 SAMLPolicyTest::SAMLPolicyTest()
     : device_policy_(test_helper_.device_policy()) {}
 
@@ -1210,7 +1226,7 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_NoSAML) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, PRE_NoSAML) {
   // Set the offline login time limit for SAML users to zero.
   SetSAMLOfflineSigninTimeLimitPolicy(0);
 
@@ -1235,7 +1251,7 @@
 
 // Verifies that the offline login time limit does not affect a user who
 // authenticated without SAML.
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, NoSAML) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, NoSAML) {
   login_screen_load_observer_->Wait();
   // Verify that offline login is allowed.
   test::OobeJS().ExpectTrue(
@@ -1243,7 +1259,7 @@
       "    '#pod-row .reauth-hint-container')).display == 'none'");
 }
 
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_SAMLNoLimit) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, PRE_SAMLNoLimit) {
   // Remove the offline login time limit for SAML users.
   SetSAMLOfflineSigninTimeLimitPolicy(-1);
 
@@ -1252,7 +1268,7 @@
 
 // Verifies that when no offline login time limit is set, a user who
 // authenticated with SAML is allowed to log in offline.
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, SAMLNoLimit) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, SAMLNoLimit) {
   login_screen_load_observer_->Wait();
   // Verify that offline login is allowed.
   test::OobeJS().ExpectTrue(
@@ -1260,7 +1276,7 @@
       "    '#pod-row .reauth-hint-container')).display == 'none'");
 }
 
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_SAMLZeroLimit) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, PRE_SAMLZeroLimit) {
   // Set the offline login time limit for SAML users to zero.
   SetSAMLOfflineSigninTimeLimitPolicy(0);
 
@@ -1269,7 +1285,7 @@
 
 // Verifies that when the offline login time limit is exceeded for a user who
 // authenticated via SAML, that user is forced to log in online the next time.
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, SAMLZeroLimit) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, SAMLZeroLimit) {
   login_screen_load_observer_->Wait();
   // Verify that offline login is not allowed.
   test::OobeJS().ExpectTrue(
@@ -1277,7 +1293,8 @@
       "    '#pod-row .reauth-hint-container')).display != 'none'");
 }
 
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_PRE_TransferCookiesAffiliated) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin,
+                       PRE_PRE_TransferCookiesAffiliated) {
   fake_saml_idp()->SetCookieValue(kSAMLIdPCookieValue1);
   LogInWithSAML(kFirstSAMLUserEmail, kTestAuthSIDCookie1, kTestAuthLSIDCookie1);
 
@@ -1291,7 +1308,8 @@
 // IdP cookies are not transferred to a user's profile on subsequent login, even
 // if the user belongs to the domain that the device is enrolled into. Also
 // verifies that GAIA cookies are not transferred.
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_TransferCookiesAffiliated) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin,
+                       PRE_TransferCookiesAffiliated) {
   fake_saml_idp()->SetCookieValue(kSAMLIdPCookieValue2);
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
   ShowGAIALoginForm();
@@ -1307,7 +1325,7 @@
 // cookies are transferred to a user's profile on subsequent login when the user
 // belongs to the domain that the device is enrolled into. Also verifies that
 // GAIA cookies are not transferred.
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, TransferCookiesAffiliated) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, TransferCookiesAffiliated) {
   fake_saml_idp()->SetCookieValue(kSAMLIdPCookieValue2);
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
   ShowGAIALoginForm();
@@ -1321,7 +1339,8 @@
   EXPECT_EQ(kSAMLIdPCookieValue2, GetCookieValue(kSAMLIdPCookieName));
 }
 
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_TransferCookiesUnaffiliated) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin,
+                       PRE_TransferCookiesUnaffiliated) {
   fake_saml_idp()->SetCookieValue(kSAMLIdPCookieValue1);
   LogInWithSAML(kDifferentDomainSAMLUserEmail, kTestAuthSIDCookie1,
                 kTestAuthLSIDCookie1);
@@ -1336,7 +1355,7 @@
 // IdP are not transferred to a user's profile on subsequent login if the user
 // does not belong to the domain that the device is enrolled into. Also verifies
 // that GAIA cookies are not transferred.
-IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, TransferCookiesUnaffiliated) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTestWebUILogin, TransferCookiesUnaffiliated) {
   fake_saml_idp()->SetCookieValue(kSAMLIdPCookieValue2);
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
   ShowGAIALoginForm();
@@ -1398,32 +1417,10 @@
   session_start_waiter.Wait();
 }
 
-// A specialization of SAMLPolicyTest which doesn't pass the command-line switch
-// forcing the WebUI login, thus allowing views-based login.
-class SAMLPolicyViewsBasedLoginTest : public SAMLPolicyTest {
- public:
-  SAMLPolicyViewsBasedLoginTest() : SAMLPolicyTest() {
-    device_state_.SetState(
-        chromeos::DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED);
-  }
-  ~SAMLPolicyViewsBasedLoginTest() override = default;
-
- protected:
-  // OobeBaseTest:
-  bool ShouldForceWebUiLogin() override {
-    // Allow the Views-based login to be used.
-    return false;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SAMLPolicyViewsBasedLoginTest);
-};
-
 // Ensure that the permission status of getUserMedia requests from SAML login
 // pages is controlled by the kLoginVideoCaptureAllowedUrls pref rather than the
 // underlying user content setting.
-IN_PROC_BROWSER_TEST_F(SAMLPolicyViewsBasedLoginTest,
-                       TestLoginMediaPermission) {
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, TestLoginMediaPermission) {
   EXPECT_TRUE(ash::features::IsViewsLoginEnabled());
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
 
diff --git a/chrome/browser/chromeos/login/screens/app_downloading_screen.cc b/chrome/browser/chromeos/login/screens/app_downloading_screen.cc
index 16cfc5a..8f4549a 100644
--- a/chrome/browser/chromeos/login/screens/app_downloading_screen.cc
+++ b/chrome/browser/chromeos/login/screens/app_downloading_screen.cc
@@ -19,7 +19,7 @@
 AppDownloadingScreen::AppDownloadingScreen(
     AppDownloadingScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_APP_DOWNLOADING),
+    : BaseScreen(AppDownloadingScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc
index 45e89ba..c24113cd 100644
--- a/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc
@@ -83,7 +83,7 @@
 IN_PROC_BROWSER_TEST_F(AppDownloadingScreenTest, NoAppsSelected) {
   app_downloading_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_APP_DOWNLOADING);
+  OobeScreenWaiter screen_waiter(AppDownloadingScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -115,7 +115,7 @@
 
   app_downloading_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_APP_DOWNLOADING);
+  OobeScreenWaiter screen_waiter(AppDownloadingScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -149,7 +149,7 @@
 
   app_downloading_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_APP_DOWNLOADING);
+  OobeScreenWaiter screen_waiter(AppDownloadingScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
diff --git a/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.cc b/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.cc
index dacb51b..61fbac07 100644
--- a/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.cc
+++ b/chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.cc
@@ -37,7 +37,7 @@
 ArcTermsOfServiceScreen::ArcTermsOfServiceScreen(
     ArcTermsOfServiceScreenView* view,
     const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE),
+    : BaseScreen(ArcTermsOfServiceScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.cc b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.cc
index e73f612..2494dcfb 100644
--- a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.cc
+++ b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.cc
@@ -21,7 +21,7 @@
 AssistantOptInFlowScreen::AssistantOptInFlowScreen(
     AssistantOptInFlowScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW),
+    : BaseScreen(AssistantOptInFlowScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
index 785853ec..a0e4d92 100644
--- a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
@@ -365,7 +365,7 @@
 
     WizardController::default_controller()
         ->screen_manager()
-        ->DeleteScreenForTesting(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+        ->DeleteScreenForTesting(AssistantOptInFlowScreenView::kScreenId);
     auto assistant_optin_flow_screen =
         std::make_unique<AssistantOptInFlowScreen>(
             GetOobeUI()->GetView<AssistantOptInFlowScreenHandler>(),
@@ -531,7 +531,7 @@
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -569,7 +569,7 @@
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -608,7 +608,7 @@
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -644,7 +644,7 @@
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -682,7 +682,7 @@
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -726,7 +726,7 @@
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
       ash::mojom::VoiceInteractionState::STOPPED);
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -765,7 +765,7 @@
 
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -791,7 +791,7 @@
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -832,7 +832,7 @@
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -877,7 +877,7 @@
 
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -912,7 +912,7 @@
 
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -945,7 +945,7 @@
 
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -1035,7 +1035,7 @@
 
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -1087,7 +1087,7 @@
 
   assistant_optin_flow_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
+  OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
diff --git a/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc b/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
index d7336a3..c3bbc19 100644
--- a/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
+++ b/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
@@ -40,7 +40,7 @@
 DemoPreferencesScreen::DemoPreferencesScreen(
     DemoPreferencesScreenView* view,
     const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES),
+    : BaseScreen(DemoPreferencesScreenView::kScreenId),
       input_manager_observer_(this),
       view_(view),
       exit_callback_(exit_callback) {
diff --git a/chrome/browser/chromeos/login/screens/demo_setup_screen.cc b/chrome/browser/chromeos/login/screens/demo_setup_screen.cc
index 94efb7b..140db5f 100644
--- a/chrome/browser/chromeos/login/screens/demo_setup_screen.cc
+++ b/chrome/browser/chromeos/login/screens/demo_setup_screen.cc
@@ -21,7 +21,7 @@
 
 DemoSetupScreen::DemoSetupScreen(DemoSetupScreenView* view,
                                  const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP),
+    : BaseScreen(DemoSetupScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback),
       weak_ptr_factory_(this) {
diff --git a/chrome/browser/chromeos/login/screens/device_disabled_screen.cc b/chrome/browser/chromeos/login/screens/device_disabled_screen.cc
index 75d8752..c3eb7f4 100644
--- a/chrome/browser/chromeos/login/screens/device_disabled_screen.cc
+++ b/chrome/browser/chromeos/login/screens/device_disabled_screen.cc
@@ -21,7 +21,7 @@
 }  // namespace
 
 DeviceDisabledScreen::DeviceDisabledScreen(DeviceDisabledScreenView* view)
-    : BaseScreen(OobeScreen::SCREEN_DEVICE_DISABLED), view_(view) {
+    : BaseScreen(DeviceDisabledScreenView::kScreenId), view_(view) {
   view_->SetDelegate(this);
 }
 
diff --git a/chrome/browser/chromeos/login/screens/discover_screen.cc b/chrome/browser/chromeos/login/screens/discover_screen.cc
index 7829a72..590f2f48 100644
--- a/chrome/browser/chromeos/login/screens/discover_screen.cc
+++ b/chrome/browser/chromeos/login/screens/discover_screen.cc
@@ -20,7 +20,7 @@
 
 DiscoverScreen::DiscoverScreen(DiscoverScreenView* view,
                                const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_DISCOVER),
+    : BaseScreen(DiscoverScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/enable_debugging_screen.cc b/chrome/browser/chromeos/login/screens/enable_debugging_screen.cc
index 4704c6c..c2a424e 100644
--- a/chrome/browser/chromeos/login/screens/enable_debugging_screen.cc
+++ b/chrome/browser/chromeos/login/screens/enable_debugging_screen.cc
@@ -12,7 +12,7 @@
 EnableDebuggingScreen::EnableDebuggingScreen(
     EnableDebuggingScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING),
+    : BaseScreen(EnableDebuggingScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/encryption_migration_screen.cc b/chrome/browser/chromeos/login/screens/encryption_migration_screen.cc
index 51b75cf9..cb77f76b 100644
--- a/chrome/browser/chromeos/login/screens/encryption_migration_screen.cc
+++ b/chrome/browser/chromeos/login/screens/encryption_migration_screen.cc
@@ -14,7 +14,7 @@
 
 EncryptionMigrationScreen::EncryptionMigrationScreen(
     EncryptionMigrationScreenView* view)
-    : BaseScreen(OobeScreen::SCREEN_ENCRYPTION_MIGRATION), view_(view) {
+    : BaseScreen(EncryptionMigrationScreenView::kScreenId), view_(view) {
   DCHECK(view_);
   if (view_)
     view_->SetDelegate(this);
diff --git a/chrome/browser/chromeos/login/screens/error_screen.cc b/chrome/browser/chromeos/login/screens/error_screen.cc
index bd09953..76643b8 100644
--- a/chrome/browser/chromeos/login/screens/error_screen.cc
+++ b/chrome/browser/chromeos/login/screens/error_screen.cc
@@ -74,9 +74,7 @@
     "show-captive-portal";
 
 ErrorScreen::ErrorScreen(ErrorScreenView* view)
-    : BaseScreen(OobeScreen::SCREEN_ERROR_MESSAGE),
-      view_(view),
-      weak_factory_(this) {
+    : BaseScreen(ErrorScreenView::kScreenId), view_(view), weak_factory_(this) {
   network_state_informer_ = new NetworkStateInformer();
   network_state_informer_->Init();
   NetworkHandler::Get()->network_connection_handler()->AddObserver(this);
diff --git a/chrome/browser/chromeos/login/screens/eula_screen.cc b/chrome/browser/chromeos/login/screens/eula_screen.cc
index 21a6433..98dfe82 100644
--- a/chrome/browser/chromeos/login/screens/eula_screen.cc
+++ b/chrome/browser/chromeos/login/screens/eula_screen.cc
@@ -30,7 +30,7 @@
 }  // namespace
 
 EulaScreen::EulaScreen(EulaView* view, const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_EULA),
+    : BaseScreen(EulaView::kScreenId),
       view_(view),
       exit_callback_(exit_callback),
       password_fetcher_(this) {
diff --git a/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc b/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc
index dc87a95..334eeb40 100644
--- a/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc
@@ -98,7 +98,7 @@
 IN_PROC_BROWSER_TEST_F(FingerprintSetupTest, FingerprintEnrollHalf) {
   quick_unlock::EnabledForTesting(true);
   fingerprint_setup_screen_->Show();
-  OobeScreenWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+  OobeScreenWaiter(FingerprintSetupScreenView::kScreenId).Wait();
 
   EnrollFingerprint(50);
   test::OobeJS().ExpectVisiblePath({"fingerprint-setup-impl", "arc"});
@@ -118,7 +118,7 @@
   quick_unlock::EnabledForTesting(true);
   fingerprint_setup_screen_->Show();
 
-  OobeScreenWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+  OobeScreenWaiter(FingerprintSetupScreenView::kScreenId).Wait();
   EnrollFingerprint(100);
   CheckCompletedEnroll();
 
@@ -130,7 +130,7 @@
 IN_PROC_BROWSER_TEST_F(FingerprintSetupTest, FingerprintEnrollLimit) {
   quick_unlock::EnabledForTesting(true);
   fingerprint_setup_screen_->Show();
-  OobeScreenWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+  OobeScreenWaiter(FingerprintSetupScreenView::kScreenId).Wait();
 
   for (int i = 0; i < kMaxAllowedFingerprints - 1; i++) {
     EnrollFingerprint(100);
@@ -157,7 +157,7 @@
 IN_PROC_BROWSER_TEST_F(FingerprintSetupTest, FingerprintSetupScreenElements) {
   quick_unlock::EnabledForTesting(true);
   fingerprint_setup_screen_->Show();
-  OobeScreenWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+  OobeScreenWaiter(FingerprintSetupScreenView::kScreenId).Wait();
 
   test::OobeJS().CreateVisibilityWaiter(true, {"fingerprint-setup"})->Wait();
   test::OobeJS().ExpectVisible("fingerprint-setup-impl");
@@ -169,7 +169,7 @@
 IN_PROC_BROWSER_TEST_F(FingerprintSetupTest, FingerprintSetupCancel) {
   quick_unlock::EnabledForTesting(true);
   fingerprint_setup_screen_->Show();
-  OobeScreenWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+  OobeScreenWaiter(FingerprintSetupScreenView::kScreenId).Wait();
   test::OobeJS().TapOnPath({"fingerprint-setup-impl", "skipFingerprintSetup"});
   WaitForScreenExit();
 }
@@ -177,7 +177,7 @@
 IN_PROC_BROWSER_TEST_F(FingerprintSetupTest, FingerprintSetupNext) {
   quick_unlock::EnabledForTesting(true);
   fingerprint_setup_screen_->Show();
-  OobeScreenWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+  OobeScreenWaiter(FingerprintSetupScreenView::kScreenId).Wait();
 
   test::OobeJS().CreateVisibilityWaiter(true, {"fingerprint-setup"})->Wait();
   test::OobeJS().TapOnPath(
@@ -192,7 +192,7 @@
 IN_PROC_BROWSER_TEST_F(FingerprintSetupTest, FingerprintSetupLater) {
   quick_unlock::EnabledForTesting(true);
   fingerprint_setup_screen_->Show();
-  OobeScreenWaiter(OobeScreen::SCREEN_FINGERPRINT_SETUP).Wait();
+  OobeScreenWaiter(FingerprintSetupScreenView::kScreenId).Wait();
 
   test::OobeJS().CreateVisibilityWaiter(true, {"fingerprint-setup"})->Wait();
   test::OobeJS().TapOnPath(
diff --git a/chrome/browser/chromeos/login/screens/fingerprint_setup_screen.cc b/chrome/browser/chromeos/login/screens/fingerprint_setup_screen.cc
index 8e215e2..c7ef674 100644
--- a/chrome/browser/chromeos/login/screens/fingerprint_setup_screen.cc
+++ b/chrome/browser/chromeos/login/screens/fingerprint_setup_screen.cc
@@ -18,7 +18,7 @@
 FingerprintSetupScreen::FingerprintSetupScreen(
     FingerprintSetupScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_FINGERPRINT_SETUP),
+    : BaseScreen(FingerprintSetupScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/hid_detection_screen.cc b/chrome/browser/chromeos/login/screens/hid_detection_screen.cc
index f4e1af8..ac0f1fda 100644
--- a/chrome/browser/chromeos/login/screens/hid_detection_screen.cc
+++ b/chrome/browser/chromeos/login/screens/hid_detection_screen.cc
@@ -57,7 +57,7 @@
 HIDDetectionScreen::HIDDetectionScreen(
     HIDDetectionView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_HID_DETECTION),
+    : BaseScreen(HIDDetectionView::kScreenId),
       view_(view),
       exit_callback_(exit_callback),
       binding_(this),
diff --git a/chrome/browser/chromeos/login/screens/hid_detection_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/hid_detection_screen_browsertest.cc
index c8789ff..70a5461 100644
--- a/chrome/browser/chromeos/login/screens/hid_detection_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/hid_detection_screen_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "services/device/public/cpp/hid/fake_input_service_linux.h"
@@ -44,12 +45,12 @@
   }
 
   void SetUpOnMainThread() override {
-    ShowLoginWizard(OobeScreen::SCREEN_OOBE_HID_DETECTION);
+    ShowLoginWizard(HIDDetectionView::kScreenId);
     ASSERT_TRUE(WizardController::default_controller());
 
     hid_detection_screen_ = static_cast<HIDDetectionScreen*>(
         WizardController::default_controller()->GetScreen(
-            OobeScreen::SCREEN_OOBE_HID_DETECTION));
+            HIDDetectionView::kScreenId));
     ASSERT_TRUE(hid_detection_screen_);
     ASSERT_EQ(WizardController::default_controller()->current_screen(),
               hid_detection_screen_);
@@ -135,7 +136,7 @@
 // Test that if there is any Bluetooth device connected on HID screen, the
 // Bluetooth adapter should not be disabled after advancing to the next screen.
 IN_PROC_BROWSER_TEST_F(HIDDetectionScreenTest, BluetoothDeviceConnected) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_HID_DETECTION).Wait();
+  OobeScreenWaiter(HIDDetectionView::kScreenId).Wait();
   EXPECT_TRUE(adapter()->IsPowered());
 
   // Add a pair of USB mouse/keyboard so that |pointing_device_connect_type_|
@@ -150,7 +151,7 @@
 
   // Simulate the user's click on "Continue" button.
   hid_detection_screen()->OnContinueButtonClicked();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
 
   // The adapter should not be powered off at this moment.
   EXPECT_TRUE(adapter()->IsPowered());
@@ -159,7 +160,7 @@
 // Test that if there is no Bluetooth device connected on HID screen, the
 // Bluetooth adapter should be disabled after advancing to the next screen.
 IN_PROC_BROWSER_TEST_F(HIDDetectionScreenTest, NoBluetoothDeviceConnected) {
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_HID_DETECTION).Wait();
+  OobeScreenWaiter(HIDDetectionView::kScreenId).Wait();
   EXPECT_TRUE(adapter()->IsPowered());
 
   AddDeviceToService(true, device::mojom::InputDeviceType::TYPE_USB);
@@ -167,7 +168,7 @@
 
   // Simulate the user's click on "Continue" button.
   hid_detection_screen()->OnContinueButtonClicked();
-  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_WELCOME).Wait();
+  OobeScreenWaiter(WelcomeView::kScreenId).Wait();
 
   // The adapter should be powered off at this moment.
   EXPECT_FALSE(adapter()->IsPowered());
diff --git a/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.cc b/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.cc
index 667489a..5cd2b55 100644
--- a/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.cc
+++ b/chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.cc
@@ -14,7 +14,7 @@
 KioskAutolaunchScreen::KioskAutolaunchScreen(
     KioskAutolaunchScreenView* view,
     const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_KIOSK_AUTOLAUNCH),
+    : BaseScreen(KioskAutolaunchScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/kiosk_enable_screen.cc b/chrome/browser/chromeos/login/screens/kiosk_enable_screen.cc
index f554e98..8b98759 100644
--- a/chrome/browser/chromeos/login/screens/kiosk_enable_screen.cc
+++ b/chrome/browser/chromeos/login/screens/kiosk_enable_screen.cc
@@ -14,7 +14,7 @@
 KioskEnableScreen::KioskEnableScreen(
     KioskEnableScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_KIOSK_ENABLE),
+    : BaseScreen(KioskEnableScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
index bb95894..0e0b741 100644
--- a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
+++ b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
@@ -18,7 +18,7 @@
 MarketingOptInScreen::MarketingOptInScreen(
     MarketingOptInScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_MARKETING_OPT_IN),
+    : BaseScreen(MarketingOptInScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/multidevice_setup_screen.cc b/chrome/browser/chromeos/login/screens/multidevice_setup_screen.cc
index 3fb0d8a..54e2f39 100644
--- a/chrome/browser/chromeos/login/screens/multidevice_setup_screen.cc
+++ b/chrome/browser/chromeos/login/screens/multidevice_setup_screen.cc
@@ -27,7 +27,7 @@
 MultiDeviceSetupScreen::MultiDeviceSetupScreen(
     MultiDeviceSetupScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_MULTIDEVICE_SETUP),
+    : BaseScreen(MultiDeviceSetupScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/network_screen.cc b/chrome/browser/chromeos/login/screens/network_screen.cc
index f7a7128..a0379cc 100644
--- a/chrome/browser/chromeos/login/screens/network_screen.cc
+++ b/chrome/browser/chromeos/login/screens/network_screen.cc
@@ -33,12 +33,12 @@
 // static
 NetworkScreen* NetworkScreen::Get(ScreenManager* manager) {
   return static_cast<NetworkScreen*>(
-      manager->GetScreen(OobeScreen::SCREEN_OOBE_NETWORK));
+      manager->GetScreen(NetworkScreenView::kScreenId));
 }
 
 NetworkScreen::NetworkScreen(NetworkScreenView* view,
                              const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_NETWORK),
+    : BaseScreen(NetworkScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback),
       network_state_helper_(std::make_unique<login::NetworkStateHelper>()),
diff --git a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
index aaeeddd..702867a 100644
--- a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "content/public/test/browser_test_utils.h"
@@ -58,7 +59,7 @@
 
   void SetUpOnMainThread() override {
     InProcessBrowserTest::SetUpOnMainThread();
-    ShowLoginWizard(OobeScreen::SCREEN_OOBE_NETWORK);
+    ShowLoginWizard(NetworkScreenView::kScreenId);
     network_screen_ = NetworkScreen::Get(
         WizardController::default_controller()->screen_manager());
     ASSERT_EQ(WizardController::default_controller()->current_screen(),
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc b/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc
index 5f83c86..610fa505 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc
+++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc
@@ -12,7 +12,7 @@
 RecommendAppsScreen::RecommendAppsScreen(
     RecommendAppsScreenView* view,
     const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_RECOMMEND_APPS),
+    : BaseScreen(RecommendAppsScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc
index 62a7de5..13d4a94e 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc
@@ -119,7 +119,7 @@
     // will bind to the handler.
     WizardController::default_controller()
         ->screen_manager()
-        ->DeleteScreenForTesting(OobeScreen::SCREEN_RECOMMEND_APPS);
+        ->DeleteScreenForTesting(RecommendAppsScreenView::kScreenId);
     auto recommend_apps_screen = std::make_unique<RecommendAppsScreen>(
         GetOobeUI()->GetView<RecommendAppsScreenHandler>(),
         base::BindRepeating(&RecommendAppsScreenTest::HandleScreenExit,
@@ -235,7 +235,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, BasicSelection) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -302,7 +302,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, SelectionChange) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -370,7 +370,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, SkipWithSelectedApps) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -432,7 +432,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, SkipWithNoAppsSelected) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -500,7 +500,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, InstallWithNoAppsSelected) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -542,7 +542,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, NoRecommendedApps) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -585,7 +585,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, ParseError) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -603,7 +603,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, SkipOnLoadError) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
@@ -645,7 +645,7 @@
 IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, RetryOnLoadError) {
   recommend_apps_screen_->Show();
 
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_RECOMMEND_APPS);
+  OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
   screen_waiter.Wait();
 
diff --git a/chrome/browser/chromeos/login/screens/reset_screen.cc b/chrome/browser/chromeos/login/screens/reset_screen.cc
index 1cb20f95..753ba65 100644
--- a/chrome/browser/chromeos/login/screens/reset_screen.cc
+++ b/chrome/browser/chromeos/login/screens/reset_screen.cc
@@ -90,7 +90,7 @@
 ResetScreen::ResetScreen(ResetView* view,
                          ErrorScreen* error_screen,
                          const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_RESET),
+    : BaseScreen(ResetView::kScreenId),
       view_(view),
       error_screen_(error_screen),
       exit_callback_(exit_callback),
diff --git a/chrome/browser/chromeos/login/screens/supervision_transition_screen.cc b/chrome/browser/chromeos/login/screens/supervision_transition_screen.cc
index 44645516..5d9e72c 100644
--- a/chrome/browser/chromeos/login/screens/supervision_transition_screen.cc
+++ b/chrome/browser/chromeos/login/screens/supervision_transition_screen.cc
@@ -11,7 +11,7 @@
 SupervisionTransitionScreen::SupervisionTransitionScreen(
     SupervisionTransitionScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_SUPERVISION_TRANSITION),
+    : BaseScreen(SupervisionTransitionScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   if (view_)
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
index 8b4139c..bcd5db3 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
+++ b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
@@ -65,7 +65,7 @@
 SyncConsentScreen::SyncConsentScreen(
     SyncConsentScreenView* view,
     const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_SYNC_CONSENT),
+    : BaseScreen(SyncConsentScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc b/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
index 7414216..39b3524 100644
--- a/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
+++ b/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
@@ -32,7 +32,7 @@
 TermsOfServiceScreen::TermsOfServiceScreen(
     TermsOfServiceScreenView* view,
     const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_TERMS_OF_SERVICE),
+    : BaseScreen(TermsOfServiceScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/update_required_screen.cc b/chrome/browser/chromeos/login/screens/update_required_screen.cc
index b2a00dc4..87cb6b4 100644
--- a/chrome/browser/chromeos/login/screens/update_required_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_required_screen.cc
@@ -12,7 +12,7 @@
 namespace chromeos {
 
 UpdateRequiredScreen::UpdateRequiredScreen(UpdateRequiredView* view)
-    : BaseScreen(OobeScreen::SCREEN_UPDATE_REQUIRED),
+    : BaseScreen(UpdateRequiredView::kScreenId),
       view_(view),
       weak_factory_(this) {
   if (view_)
diff --git a/chrome/browser/chromeos/login/screens/update_required_screen.h b/chrome/browser/chromeos/login/screens/update_required_screen.h
index 8080ecb..a455b2b 100644
--- a/chrome/browser/chromeos/login/screens/update_required_screen.h
+++ b/chrome/browser/chromeos/login/screens/update_required_screen.h
@@ -21,9 +21,6 @@
 // Controller for the update required screen.
 class UpdateRequiredScreen : public BaseScreen {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_UPDATE_REQUIRED;
-
   explicit UpdateRequiredScreen(UpdateRequiredView* view);
   ~UpdateRequiredScreen() override;
 
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index d37e61f..8886b89 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -88,15 +88,14 @@
 
 // static
 UpdateScreen* UpdateScreen::Get(ScreenManager* manager) {
-  return static_cast<UpdateScreen*>(
-      manager->GetScreen(OobeScreen::SCREEN_OOBE_UPDATE));
+  return static_cast<UpdateScreen*>(manager->GetScreen(UpdateView::kScreenId));
 }
 
 UpdateScreen::UpdateScreen(BaseScreenDelegate* base_screen_delegate,
                            UpdateView* view,
                            ErrorScreen* error_screen,
                            const ScreenExitCallback& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_UPDATE),
+    : BaseScreen(UpdateView::kScreenId),
       tick_clock_(base::DefaultTickClock::GetInstance()),
       reboot_check_delay_(kWaitForRebootTimeSec),
       base_screen_delegate_(base_screen_delegate),
@@ -525,7 +524,7 @@
       error_screen_->RegisterConnectRequestCallback(base::BindRepeating(
           &UpdateScreen::OnConnectRequested, base::Unretained(this)));
   error_screen_->SetUIState(NetworkError::UI_STATE_UPDATE);
-  error_screen_->SetParentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  error_screen_->SetParentScreen(UpdateView::kScreenId);
   error_screen_->SetHideCallback(base::BindRepeating(
       &UpdateScreen::OnErrorScreenHidden, weak_factory_.GetWeakPtr()));
   error_screen_->Show();
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
index 0e83351..b22806c 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/chromeos/login/test/network_portal_detector_mixin.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
+#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
@@ -173,11 +174,11 @@
   EXPECT_EQ(UpdateScreen::Result::UPDATE_NOT_REQUIRED,
             last_screen_result_.value());
 
-  ASSERT_NE(GetOobeUI()->current_screen(), OobeScreen::SCREEN_OOBE_UPDATE);
+  ASSERT_NE(GetOobeUI()->current_screen(), UpdateView::kScreenId);
 
   // Show another screen, and verify the Update screen in not shown before it.
   GetOobeUI()->GetView<NetworkScreenHandler>()->Show();
-  OobeScreenWaiter network_screen_waiter(OobeScreen::SCREEN_OOBE_NETWORK);
+  OobeScreenWaiter network_screen_waiter(NetworkScreenView::kScreenId);
   network_screen_waiter.set_assert_next_screen();
   network_screen_waiter.Wait();
 }
@@ -197,7 +198,7 @@
   // If show is called explicitly, the update screen is expected to be shown.
   update_screen_->Show();
 
-  OobeScreenWaiter update_screen_waiter(OobeScreen::SCREEN_OOBE_UPDATE);
+  OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId);
   update_screen_waiter.set_assert_next_screen();
   update_screen_waiter.Wait();
 
@@ -232,7 +233,7 @@
 
   update_screen_->Show();
 
-  OobeScreenWaiter update_screen_waiter(OobeScreen::SCREEN_OOBE_UPDATE);
+  OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId);
   update_screen_waiter.set_assert_next_screen();
   update_screen_waiter.Wait();
 
@@ -457,7 +458,7 @@
   fake_update_engine_client_->NotifyObserversThatStatusChanged(status);
 
   // Verify that update screen is showing checking for update UI.
-  OobeScreenWaiter update_screen_waiter(OobeScreen::SCREEN_OOBE_UPDATE);
+  OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId);
   update_screen_waiter.set_assert_next_screen();
   update_screen_waiter.Wait();
 
@@ -489,10 +490,9 @@
   update_screen_->GetErrorMessageTimerForTesting()->FireNow();
   EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
 
-  ASSERT_EQ(OobeScreen::SCREEN_OOBE_UPDATE.AsId(),
-            error_screen_->GetParentScreen());
+  ASSERT_EQ(UpdateView::kScreenId.AsId(), error_screen_->GetParentScreen());
 
-  OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
+  OobeScreenWaiter error_screen_waiter(ErrorScreenView::kScreenId);
   error_screen_waiter.set_assert_next_screen();
   error_screen_waiter.Wait();
 
@@ -529,12 +529,11 @@
   network_portal_detector_.SimulateNoNetwork();
 
   EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
-  ASSERT_EQ(OobeScreen::SCREEN_OOBE_UPDATE.AsId(),
-            error_screen_->GetParentScreen());
+  ASSERT_EQ(UpdateView::kScreenId.AsId(), error_screen_->GetParentScreen());
 
   // Second portal detection also returns NULL network and undefined
   // results.  In this case, offline message should be displayed.
-  OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
+  OobeScreenWaiter error_screen_waiter(ErrorScreenView::kScreenId);
   error_screen_waiter.set_assert_next_screen();
   error_screen_waiter.Wait();
 
@@ -557,10 +556,9 @@
   // Force timer expiration.
   EXPECT_TRUE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning());
   update_screen_->GetErrorMessageTimerForTesting()->FireNow();
-  ASSERT_EQ(OobeScreen::SCREEN_OOBE_UPDATE.AsId(),
-            error_screen_->GetParentScreen());
+  ASSERT_EQ(UpdateView::kScreenId.AsId(), error_screen_->GetParentScreen());
 
-  OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
+  OobeScreenWaiter error_screen_waiter(ErrorScreenView::kScreenId);
   error_screen_waiter.set_assert_next_screen();
   error_screen_waiter.Wait();
 
@@ -571,7 +569,7 @@
   ASSERT_EQ(OobeScreen::SCREEN_UNKNOWN.AsId(),
             error_screen_->GetParentScreen());
 
-  OobeScreenWaiter update_screen_waiter(OobeScreen::SCREEN_OOBE_UPDATE);
+  OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId);
   update_screen_waiter.set_assert_next_screen();
   update_screen_waiter.Wait();
 
@@ -590,7 +588,7 @@
   fake_update_engine_client_->set_default_status(status);
   fake_update_engine_client_->NotifyObserversThatStatusChanged(status);
 
-  OobeScreenWaiter update_screen_waiter(OobeScreen::SCREEN_OOBE_UPDATE);
+  OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId);
   update_screen_waiter.set_assert_next_screen();
   update_screen_waiter.Wait();
 
@@ -632,7 +630,7 @@
   fake_update_engine_client_->set_default_status(status);
   fake_update_engine_client_->NotifyObserversThatStatusChanged(status);
 
-  OobeScreenWaiter update_screen_waiter(OobeScreen::SCREEN_OOBE_UPDATE);
+  OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId);
   update_screen_waiter.set_assert_next_screen();
   update_screen_waiter.Wait();
 
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
index 86da0b9..2c12df7b 100644
--- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -365,7 +365,7 @@
 };
 
 UserSelectionScreen::UserSelectionScreen(const std::string& display_type)
-    : BaseScreen(OobeScreen::SCREEN_USER_SELECTION),
+    : BaseScreen(UserBoardView::kScreenId),
       display_type_(display_type),
       weak_factory_(this) {}
 
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen.cc b/chrome/browser/chromeos/login/screens/welcome_screen.cc
index 95bbecc..5732faa7 100644
--- a/chrome/browser/chromeos/login/screens/welcome_screen.cc
+++ b/chrome/browser/chromeos/login/screens/welcome_screen.cc
@@ -47,12 +47,12 @@
 // static
 WelcomeScreen* WelcomeScreen::Get(ScreenManager* manager) {
   return static_cast<WelcomeScreen*>(
-      manager->GetScreen(OobeScreen::SCREEN_OOBE_WELCOME));
+      manager->GetScreen(WelcomeView::kScreenId));
 }
 
 WelcomeScreen::WelcomeScreen(WelcomeView* view,
                              const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_OOBE_WELCOME),
+    : BaseScreen(WelcomeView::kScreenId),
       view_(view),
       exit_callback_(exit_callback),
       weak_factory_(this) {
diff --git a/chrome/browser/chromeos/login/screens/wrong_hwid_screen.cc b/chrome/browser/chromeos/login/screens/wrong_hwid_screen.cc
index bb7f23e..55deaf7 100644
--- a/chrome/browser/chromeos/login/screens/wrong_hwid_screen.cc
+++ b/chrome/browser/chromeos/login/screens/wrong_hwid_screen.cc
@@ -11,7 +11,7 @@
 
 WrongHWIDScreen::WrongHWIDScreen(WrongHWIDScreenView* view,
                                  const base::RepeatingClosure& exit_callback)
-    : BaseScreen(OobeScreen::SCREEN_WRONG_HWID),
+    : BaseScreen(WrongHWIDScreenView::kScreenId),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index 3b352c4..fd0fb56 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -77,7 +78,7 @@
   session_manager::SessionManager::Get()->SetSessionState(
       session_manager::SessionState::LOGIN_PRIMARY);
 
-  ShowLoginWizard(chromeos::OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
+  ShowLoginWizard(chromeos::AppLaunchSplashScreenView::kScreenId);
 
   // Login screen is skipped but 'login-prompt-visible' signal is still needed.
   VLOG(1) << "Kiosk app auto launch >> login-prompt-visible";
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc b/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
index 1565a2f..0ca2e611 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
@@ -92,7 +92,7 @@
         WizardController::default_controller();
     ASSERT_TRUE(wizard_controller);
     wizard_controller->SkipToLoginForTesting(LoginScreenContext());
-    OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+    OobeScreenWaiter(GaiaView::kScreenId).Wait();
   }
 
  protected:
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 471c30b..0e588f3 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -102,6 +102,8 @@
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/webui/chromeos/login/discover/discover_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/discover/modules/discover_module_pin_setup.h"
+#include "chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h"
 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
@@ -1707,14 +1709,14 @@
       if (!StartupUtils::IsDeviceRegistered())
         StartupUtils::MarkDeviceRegistered(base::Closure());
 
-      ActivateWizard(OobeScreen::SCREEN_TERMS_OF_SERVICE);
+      ActivateWizard(TermsOfServiceScreenView::kScreenId);
       return false;
     } else if (base::FeatureList::IsEnabled(
                    chromeos::features::kEnableSupervisionTransitionScreens) &&
                !user_manager->IsCurrentUserNew() &&
                arc::GetSupervisionTransition(profile) !=
                    arc::ArcSupervisionTransition::NO_TRANSITION) {
-      ActivateWizard(OobeScreen::SCREEN_SUPERVISION_TRANSITION);
+      ActivateWizard(SupervisionTransitionScreenView::kScreenId);
       return false;
     }
   }
diff --git a/chrome/browser/chromeos/login/signin/device_id_browsertest.cc b/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
index 514c2c2..d8eb8e6c 100644
--- a/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/public/cpp/ash_switches.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/json/json_reader.h"
@@ -51,6 +52,7 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     OobeBaseTest::SetUpCommandLine(command_line);
     command_line->AppendSwitch(switches::kOobeSkipPostLogin);
+    command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
   }
 
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
index 564443e..cc8a29a 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/public/cpp/ash_switches.h"
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -243,6 +244,7 @@
   // OobeBaseTest overrides.
   void SetUpCommandLine(base::CommandLine* command_line) override {
     OobeBaseTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
 
     base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
 
diff --git a/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc b/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc
index 75ecdb7..54ee52b 100644
--- a/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc
+++ b/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc
@@ -147,7 +147,7 @@
       const std::string expected_consent_confirmation_string) {
     SyncConsentScreen* screen = static_cast<SyncConsentScreen*>(
         WizardController::default_controller()->GetScreen(
-            OobeScreen::SCREEN_SYNC_CONSENT));
+            SyncConsentScreenView::kScreenId));
     ConsentRecordedWaiter consent_recorded_waiter;
     screen->SetDelegateForTesting(&consent_recorded_waiter);
 
@@ -269,7 +269,7 @@
 
   SyncConsentScreen* screen = static_cast<SyncConsentScreen*>(
       WizardController::default_controller()->GetScreen(
-          OobeScreen::SCREEN_SYNC_CONSENT));
+          SyncConsentScreenView::kScreenId));
 
   screen->SetProfileSyncDisabledByPolicyForTesting(true);
   screen->SetProfileSyncEngineInitializedForTesting(GetParam());
diff --git a/chrome/browser/chromeos/login/test/active_directory_login_mixin.cc b/chrome/browser/chromeos/login/test/active_directory_login_mixin.cc
index d633f51..00011277 100644
--- a/chrome/browser/chromeos/login/test/active_directory_login_mixin.cc
+++ b/chrome/browser/chromeos/login/test/active_directory_login_mixin.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/chromeos/login/test/js_checker.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chromeos/dbus/auth_policy/fake_auth_policy_client.h"
@@ -88,7 +89,7 @@
 
 // Checks if Active Directory login is visible.
 void ActiveDirectoryLoginMixin::TestLoginVisible() {
-  OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_GAIA_SIGNIN);
+  OobeScreenWaiter screen_waiter(GaiaView::kScreenId);
   screen_waiter.Wait();
   // Checks if Gaia signin is hidden.
   test::OobeJS().ExpectHidden(kGaiaSigninId);
diff --git a/chrome/browser/chromeos/login/test/enrollment_helper_mixin.cc b/chrome/browser/chromeos/login/test/enrollment_helper_mixin.cc
index dcf3cd7..9581747 100644
--- a/chrome/browser/chromeos/login/test/enrollment_helper_mixin.cc
+++ b/chrome/browser/chromeos/login/test/enrollment_helper_mixin.cc
@@ -47,7 +47,7 @@
   if (WizardController::default_controller()) {
     auto* screen_manager =
         WizardController::default_controller()->screen_manager();
-    if (screen_manager->HasScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT)) {
+    if (screen_manager->HasScreen(EnrollmentScreenView::kScreenId)) {
       EnrollmentScreen::Get(screen_manager)->enrollment_helper_.reset();
     }
   }
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.cc b/chrome/browser/chromeos/login/test/oobe_base_test.cc
index 5cca82d..a8a9052 100644
--- a/chrome/browser/chromeos/login/test/oobe_base_test.cc
+++ b/chrome/browser/chromeos/login/test/oobe_base_test.cc
@@ -53,8 +53,6 @@
 }
 
 void OobeBaseTest::SetUpCommandLine(base::CommandLine* command_line) {
-  if (ShouldForceWebUiLogin())
-    command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
   command_line->AppendSwitch(chromeos::switches::kLoginManager);
   command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
   if (!needs_background_networking_)
@@ -83,10 +81,6 @@
   MixinBasedInProcessBrowserTest::SetUpOnMainThread();
 }
 
-bool OobeBaseTest::ShouldForceWebUiLogin() {
-  return true;
-}
-
 bool OobeBaseTest::ShouldWaitForOobeUI() {
   return true;
 }
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.h b/chrome/browser/chromeos/login/test/oobe_base_test.h
index 566d898..50b40391 100644
--- a/chrome/browser/chromeos/login/test/oobe_base_test.h
+++ b/chrome/browser/chromeos/login/test/oobe_base_test.h
@@ -35,12 +35,6 @@
   void SetUpCommandLine(base::CommandLine* command_line) override;
   void SetUpOnMainThread() override;
 
-  // If this returns true (default), the |ash::switches::kShowWebUiLogin|
-  // command-line switch is passed to force the Web Ui Login.
-  // If this returns false, the switch is omitted so the views-based login may
-  // be used.
-  virtual bool ShouldForceWebUiLogin();
-
   // If this returns true (default), then SetUpOnMainThread would wait for
   // Oobe UI to start up before initializing all mix-ins.
   virtual bool ShouldWaitForOobeUI();
diff --git a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
index 8fad419..b89d855 100644
--- a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
+++ b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
@@ -226,7 +226,7 @@
 
   ASSERT_EQ(PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN, strategy_id());
   network_portal_detector()->NotifyObserversForTesting();
-  OobeScreenWaiter(OobeScreen::SCREEN_ERROR_MESSAGE).Wait();
+  OobeScreenWaiter(ErrorScreenView::kScreenId).Wait();
   ASSERT_EQ(PortalDetectorStrategy::STRATEGY_ID_ERROR_SCREEN, strategy_id());
 
   error_screen->ShowCaptivePortal();
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.cc b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
index f641c78..7c57155a 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_common.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
@@ -284,7 +284,7 @@
     }
     LoadWallpaper(*prefilled_account);
   } else {
-    if (GetOobeUI()->current_screen() != OobeScreen::SCREEN_GAIA_SIGNIN)
+    if (GetOobeUI()->current_screen() != GaiaView::kScreenId)
       GetOobeUI()->GetView<GaiaScreenHandler>()->ShowGaiaAsync(base::nullopt);
     LoadSigninWallpaper();
   }
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
index 018c0e8b..f15a858 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/login/auth/user_context.h"
@@ -204,13 +205,13 @@
   // TODO(tbarzic): Reassess when https://crbug.com/943720 is fixed.
   PrefService* local_state = g_browser_process->local_state();
   if (local_state->GetBoolean(prefs::kFactoryResetRequested)) {
-    StartWizard(OobeScreen::SCREEN_OOBE_RESET);
+    StartWizard(ResetView::kScreenId);
     start_delayed_for_oobe_dialog_ = true;
     return;
   }
 
   if (local_state->GetBoolean(prefs::kDebuggingFeaturesRequested)) {
-    StartWizard(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING);
+    StartWizard(EnableDebuggingScreenView::kScreenId);
     start_delayed_for_oobe_dialog_ = true;
     return;
   }
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 f6efa6e..e3adb4d 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -55,9 +55,11 @@
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/browser/ui/ash/system_tray_client.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -1188,7 +1190,7 @@
   session_manager::SessionManager::Get()->SetSessionState(session_state);
 
   bool show_app_launch_splash_screen =
-      (first_screen == OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
+      (first_screen == AppLaunchSplashScreenView::kScreenId);
   if (show_app_launch_splash_screen) {
     const std::string& auto_launch_app_id =
         KioskAppManager::Get()->GetAutoLaunchApp();
@@ -1213,7 +1215,7 @@
     // Shows networks screen instead of enrollment screen to resume the
     // interrupted auto start enrollment flow because enrollment screen does
     // not handle flaky network. See http://crbug.com/332572
-    display_host->StartWizard(OobeScreen::SCREEN_OOBE_WELCOME);
+    display_host->StartWizard(WelcomeView::kScreenId);
     return;
   }
 
diff --git a/chrome/browser/chromeos/login/ui/views/user_board_view.h b/chrome/browser/chromeos/login/ui/views/user_board_view.h
index 3fc8dfe..28180292 100644
--- a/chrome/browser/chromeos/login/ui/views/user_board_view.h
+++ b/chrome/browser/chromeos/login/ui/views/user_board_view.h
@@ -27,8 +27,7 @@
 // or Views one.
 class UserBoardView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_USER_SELECTION;
+  constexpr static StaticOobeScreenId kScreenId{"userBoard"};
 
   virtual ~UserBoardView() {}
 
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc
index 914a1fa..7e9881c 100644
--- a/chrome/browser/chromeos/login/webview_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/ui/login/login_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
@@ -530,8 +531,8 @@
   }
 
   void ShowEulaScreen() {
-    LoginDisplayHost::default_host()->StartWizard(OobeScreen::SCREEN_OOBE_EULA);
-    OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
+    LoginDisplayHost::default_host()->StartWizard(EulaView::kScreenId);
+    OobeScreenWaiter(EulaView::kScreenId).Wait();
   }
 
  protected:
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 42887e9..7ed2635 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -90,6 +90,8 @@
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h"
@@ -100,6 +102,7 @@
 #include "chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h"
@@ -167,21 +170,21 @@
 
 // Stores the list of all screens that should be shown when resuming OOBE.
 const chromeos::StaticOobeScreenId kResumableScreens[] = {
-    chromeos::OobeScreen::SCREEN_OOBE_WELCOME,
-    chromeos::OobeScreen::SCREEN_OOBE_NETWORK,
-    chromeos::OobeScreen::SCREEN_OOBE_UPDATE,
-    chromeos::OobeScreen::SCREEN_OOBE_EULA,
-    chromeos::OobeScreen::SCREEN_OOBE_ENROLLMENT,
-    chromeos::OobeScreen::SCREEN_TERMS_OF_SERVICE,
-    chromeos::OobeScreen::SCREEN_SYNC_CONSENT,
-    chromeos::OobeScreen::SCREEN_FINGERPRINT_SETUP,
-    chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
-    chromeos::OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK,
-    chromeos::OobeScreen::SCREEN_RECOMMEND_APPS,
-    chromeos::OobeScreen::SCREEN_APP_DOWNLOADING,
-    chromeos::OobeScreen::SCREEN_DISCOVER,
-    chromeos::OobeScreen::SCREEN_MARKETING_OPT_IN,
-    chromeos::OobeScreen::SCREEN_MULTIDEVICE_SETUP,
+    chromeos::WelcomeView::kScreenId,
+    chromeos::NetworkScreenView::kScreenId,
+    chromeos::UpdateView::kScreenId,
+    chromeos::EulaView::kScreenId,
+    chromeos::EnrollmentScreenView::kScreenId,
+    chromeos::TermsOfServiceScreenView::kScreenId,
+    chromeos::SyncConsentScreenView::kScreenId,
+    chromeos::FingerprintSetupScreenView::kScreenId,
+    chromeos::ArcTermsOfServiceScreenView::kScreenId,
+    chromeos::AutoEnrollmentCheckScreenView::kScreenId,
+    chromeos::RecommendAppsScreenView::kScreenId,
+    chromeos::AppDownloadingScreenView::kScreenId,
+    chromeos::DiscoverScreenView::kScreenId,
+    chromeos::MarketingOptInScreenView::kScreenId,
+    chromeos::MultiDeviceSetupScreenView::kScreenId,
 };
 
 // Checks if device is in tablet mode, and that HID-detection screen is not
@@ -210,12 +213,12 @@
 // Some screens had multiple different names in the past (they have since been
 // unified). We need to always use the same name for UMA stats, though.
 constexpr const Entry kLegacyUmaOobeScreenNames[] = {
-    {chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE, "arc_tos"},
-    {chromeos::OobeScreen::SCREEN_OOBE_ENROLLMENT, "enroll"},
-    {chromeos::OobeScreen::SCREEN_OOBE_WELCOME, "network"},
+    {chromeos::ArcTermsOfServiceScreenView::kScreenId, "arc_tos"},
+    {chromeos::EnrollmentScreenView::kScreenId, "enroll"},
+    {chromeos::WelcomeView::kScreenId, "network"},
     {chromeos::OobeScreen::SCREEN_CREATE_SUPERVISED_USER_FLOW_DEPRECATED,
      "supervised-user-creation-flow"},
-    {chromeos::OobeScreen::SCREEN_TERMS_OF_SERVICE, "tos"}};
+    {chromeos::TermsOfServiceScreenView::kScreenId, "tos"}};
 
 void RecordUMAHistogramForOOBEStepCompletionTime(chromeos::OobeScreenId screen,
                                                  base::TimeDelta step_time) {
@@ -396,7 +399,7 @@
 }
 
 BaseScreen* WizardController::GetScreen(OobeScreenId screen) {
-  if (screen == OobeScreen::SCREEN_ERROR_MESSAGE)
+  if (screen == ErrorScreenView::kScreenId)
     return GetErrorScreen();
   return screen_manager_->GetScreen(screen);
 }
@@ -535,11 +538,11 @@
 }
 
 void WizardController::ShowWelcomeScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_WELCOME));
+  SetCurrentScreen(GetScreen(WelcomeView::kScreenId));
 }
 
 void WizardController::ShowNetworkScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_NETWORK));
+  SetCurrentScreen(GetScreen(NetworkScreenView::kScreenId));
 }
 
 void WizardController::ShowLoginScreen(const LoginScreenContext& context) {
@@ -559,7 +562,7 @@
 }
 
 void WizardController::ShowEulaScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_EULA));
+  SetCurrentScreen(GetScreen(EulaView::kScreenId));
 }
 
 void WizardController::ShowEnrollmentScreen() {
@@ -571,27 +574,27 @@
 }
 
 void WizardController::ShowDemoModePreferencesScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
+  SetCurrentScreen(GetScreen(DemoPreferencesScreenView::kScreenId));
 }
 
 void WizardController::ShowDemoModeSetupScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP));
+  SetCurrentScreen(GetScreen(DemoSetupScreenView::kScreenId));
 }
 
 void WizardController::ShowResetScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_RESET));
+  SetCurrentScreen(GetScreen(ResetView::kScreenId));
 }
 
 void WizardController::ShowKioskEnableScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_KIOSK_ENABLE));
+  SetCurrentScreen(GetScreen(KioskEnableScreenView::kScreenId));
 }
 
 void WizardController::ShowKioskAutolaunchScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_KIOSK_AUTOLAUNCH));
+  SetCurrentScreen(GetScreen(KioskAutolaunchScreenView::kScreenId));
 }
 
 void WizardController::ShowEnableDebuggingScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING));
+  SetCurrentScreen(GetScreen(EnableDebuggingScreenView::kScreenId));
 }
 
 void WizardController::ShowTermsOfServiceScreen() {
@@ -605,27 +608,27 @@
     return;
   }
 
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_TERMS_OF_SERVICE));
+  SetCurrentScreen(GetScreen(TermsOfServiceScreenView::kScreenId));
 }
 
 void WizardController::ShowSyncConsentScreen() {
   if (is_official_build_)
-    SetCurrentScreen(GetScreen(OobeScreen::SCREEN_SYNC_CONSENT));
+    SetCurrentScreen(GetScreen(SyncConsentScreenView::kScreenId));
   else
     OnSyncConsentFinished();
 }
 
 void WizardController::ShowFingerprintSetupScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_FINGERPRINT_SETUP));
+  SetCurrentScreen(GetScreen(FingerprintSetupScreenView::kScreenId));
 }
 
 void WizardController::ShowMarketingOptInScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_MARKETING_OPT_IN));
+  SetCurrentScreen(GetScreen(MarketingOptInScreenView::kScreenId));
 }
 
 void WizardController::ShowArcTermsOfServiceScreen() {
   if (arc::IsArcTermsOfServiceOobeNegotiationNeeded()) {
-    SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
+    SetCurrentScreen(GetScreen(ArcTermsOfServiceScreenView::kScreenId));
     ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean(
         arc::prefs::kArcTermsShownInOobe, true);
   } else {
@@ -634,15 +637,15 @@
 }
 
 void WizardController::ShowRecommendAppsScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_RECOMMEND_APPS));
+  SetCurrentScreen(GetScreen(RecommendAppsScreenView::kScreenId));
 }
 
 void WizardController::ShowAppDownloadingScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_APP_DOWNLOADING));
+  SetCurrentScreen(GetScreen(AppDownloadingScreenView::kScreenId));
 }
 
 void WizardController::ShowWrongHWIDScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_WRONG_HWID));
+  SetCurrentScreen(GetScreen(WrongHWIDScreenView::kScreenId));
 }
 
 void WizardController::ShowAutoEnrollmentCheckScreen() {
@@ -655,40 +658,40 @@
 }
 
 void WizardController::ShowArcKioskSplashScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ARC_KIOSK_SPLASH));
+  SetCurrentScreen(GetScreen(ArcKioskSplashScreenView::kScreenId));
 }
 
 void WizardController::ShowHIDDetectionScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_HID_DETECTION));
+  SetCurrentScreen(GetScreen(HIDDetectionView::kScreenId));
 }
 
 void WizardController::ShowDeviceDisabledScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_DEVICE_DISABLED));
+  SetCurrentScreen(GetScreen(DeviceDisabledScreenView::kScreenId));
 }
 
 void WizardController::ShowEncryptionMigrationScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ENCRYPTION_MIGRATION));
+  SetCurrentScreen(GetScreen(EncryptionMigrationScreenView::kScreenId));
 }
 
 void WizardController::ShowSupervisionTransitionScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_SUPERVISION_TRANSITION));
+  SetCurrentScreen(GetScreen(SupervisionTransitionScreenView::kScreenId));
 }
 
 void WizardController::ShowUpdateRequiredScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_UPDATE_REQUIRED));
+  SetCurrentScreen(GetScreen(UpdateRequiredView::kScreenId));
 }
 
 void WizardController::ShowAssistantOptInFlowScreen() {
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW));
+  UpdateStatusAreaVisibilityForScreen(AssistantOptInFlowScreenView::kScreenId);
+  SetCurrentScreen(GetScreen(AssistantOptInFlowScreenView::kScreenId));
 }
 
 void WizardController::ShowMultiDeviceSetupScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_MULTIDEVICE_SETUP));
+  SetCurrentScreen(GetScreen(MultiDeviceSetupScreenView::kScreenId));
 }
 
 void WizardController::ShowDiscoverScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_DISCOVER));
+  SetCurrentScreen(GetScreen(DiscoverScreenView::kScreenId));
 }
 
 void WizardController::SkipToLoginForTesting(
@@ -724,7 +727,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 // WizardController, ExitHandlers:
 void WizardController::OnWrongHWIDScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_WRONG_HWID, 0 /* exit_code */);
+  OnScreenExit(WrongHWIDScreenView::kScreenId, 0 /* exit_code */);
 
   if (previous_screen_) {
     SetCurrentScreen(previous_screen_);
@@ -734,7 +737,7 @@
 }
 
 void WizardController::OnHidDetectionScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_HID_DETECTION, 0 /* exit_code */);
+  OnScreenExit(HIDDetectionView::kScreenId, 0 /* exit_code */);
 
   // Check for tests configuration.
   if (!StartupUtils::IsOobeCompleted())
@@ -742,13 +745,13 @@
 }
 
 void WizardController::OnWelcomeScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_WELCOME, 0 /* exit_code */);
+  OnScreenExit(WelcomeView::kScreenId, 0 /* exit_code */);
 
   ShowNetworkScreen();
 }
 
 void WizardController::OnNetworkScreenExit(NetworkScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_NETWORK, static_cast<int>(result));
+  OnScreenExit(NetworkScreenView::kScreenId, static_cast<int>(result));
 
   if (result == NetworkScreen::Result::BACK) {
     if (demo_setup_controller_) {
@@ -815,7 +818,7 @@
 }
 
 void WizardController::OnEulaScreenExit(EulaScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_EULA, static_cast<int>(result));
+  OnScreenExit(EulaView::kScreenId, static_cast<int>(result));
 
   switch (result) {
     case EulaScreen::Result::ACCEPTED_WITH_USAGE_STATS_REPORTING:
@@ -854,7 +857,7 @@
 }
 
 void WizardController::OnUpdateScreenExit(UpdateScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_UPDATE, static_cast<int>(result));
+  OnScreenExit(UpdateView::kScreenId, static_cast<int>(result));
 
   switch (result) {
     case UpdateScreen::Result::UPDATE_NOT_REQUIRED:
@@ -877,7 +880,7 @@
 }
 
 void WizardController::OnAutoEnrollmentCheckScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK, 0 /* exit_code */);
+  OnScreenExit(AutoEnrollmentCheckScreenView::kScreenId, 0 /* exit_code */);
 
   // Check whether the device is disabled. OnDeviceDisabledChecked() will be
   // invoked when the result of this check is known. Until then, the current
@@ -890,7 +893,7 @@
 }
 
 void WizardController::OnEnrollmentScreenExit(EnrollmentScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_ENROLLMENT, static_cast<int>(result));
+  OnScreenExit(EnrollmentScreenView::kScreenId, static_cast<int>(result));
 
   switch (result) {
     case EnrollmentScreen::Result::COMPLETED:
@@ -923,20 +926,20 @@
 }
 
 void WizardController::OnEnableDebuggingScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING, 0 /* exit_code */);
+  OnScreenExit(EnableDebuggingScreenView::kScreenId, 0 /* exit_code */);
 
   OnDeviceModificationCanceled();
 }
 
 void WizardController::OnKioskEnableScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_KIOSK_ENABLE, 0 /* exit_code */);
+  OnScreenExit(KioskEnableScreenView::kScreenId, 0 /* exit_code */);
 
   ShowLoginScreen(LoginScreenContext());
 }
 
 void WizardController::OnKioskAutolaunchScreenExit(
     KioskAutolaunchScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_KIOSK_AUTOLAUNCH, 0 /* exit_code */);
+  OnScreenExit(KioskAutolaunchScreenView::kScreenId, 0 /* exit_code */);
 
   switch (result) {
     case KioskAutolaunchScreen::Result::COMPLETED:
@@ -951,8 +954,7 @@
 
 void WizardController::OnDemoPreferencesScreenExit(
     DemoPreferencesScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES,
-               static_cast<int>(result));
+  OnScreenExit(DemoPreferencesScreenView::kScreenId, static_cast<int>(result));
 
   DCHECK(demo_setup_controller_);
 
@@ -968,7 +970,7 @@
 }
 
 void WizardController::OnDemoSetupScreenExit(DemoSetupScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_DEMO_SETUP, static_cast<int>(result));
+  OnScreenExit(DemoSetupScreenView::kScreenId, static_cast<int>(result));
 
   DCHECK(demo_setup_controller_);
   demo_setup_controller_.reset();
@@ -986,7 +988,7 @@
 
 void WizardController::OnTermsOfServiceScreenExit(
     TermsOfServiceScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_TERMS_OF_SERVICE, static_cast<int>(result));
+  OnScreenExit(TermsOfServiceScreenView::kScreenId, static_cast<int>(result));
 
   switch (result) {
     case TermsOfServiceScreen::Result::ACCEPTED:
@@ -1004,7 +1006,7 @@
 }
 
 void WizardController::OnSyncConsentScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_SYNC_CONSENT, 0 /* exit_code */);
+  OnScreenExit(SyncConsentScreenView::kScreenId, 0 /* exit_code */);
   OnSyncConsentFinished();
 }
 
@@ -1013,24 +1015,24 @@
 }
 
 void WizardController::OnFingerprintSetupScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_FINGERPRINT_SETUP, 0 /* exit_code */);
+  OnScreenExit(FingerprintSetupScreenView::kScreenId, 0 /* exit_code */);
 
   ShowDiscoverScreen();
 }
 
 void WizardController::OnDiscoverScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_DISCOVER, 0 /* exit_code */);
+  OnScreenExit(DiscoverScreenView::kScreenId, 0 /* exit_code */);
   ShowMarketingOptInScreen();
 }
 
 void WizardController::OnMarketingOptInScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_MARKETING_OPT_IN, 0 /* exit_code */);
+  OnScreenExit(MarketingOptInScreenView::kScreenId, 0 /* exit_code */);
   ShowArcTermsOfServiceScreen();
 }
 
 void WizardController::OnArcTermsOfServiceScreenExit(
     ArcTermsOfServiceScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  OnScreenExit(ArcTermsOfServiceScreenView::kScreenId,
                static_cast<int>(result));
 
   switch (result) {
@@ -1083,7 +1085,7 @@
 
 void WizardController::OnRecommendAppsScreenExit(
     RecommendAppsScreen::Result result) {
-  OnScreenExit(OobeScreen::SCREEN_RECOMMEND_APPS, static_cast<int>(result));
+  OnScreenExit(RecommendAppsScreenView::kScreenId, static_cast<int>(result));
 
   switch (result) {
     case RecommendAppsScreen::Result::SELECTED:
@@ -1096,25 +1098,25 @@
 }
 
 void WizardController::OnAppDownloadingScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_APP_DOWNLOADING, 0 /* exit_code */);
+  OnScreenExit(AppDownloadingScreenView::kScreenId, 0 /* exit_code */);
 
   ShowAssistantOptInFlowScreen();
 }
 
 void WizardController::OnAssistantOptInFlowScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW, 0 /* exit_code */);
+  OnScreenExit(AssistantOptInFlowScreenView::kScreenId, 0 /* exit_code */);
 
   ShowMultiDeviceSetupScreen();
 }
 
 void WizardController::OnMultiDeviceSetupScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_MULTIDEVICE_SETUP, 0 /* exit_code */);
+  OnScreenExit(MultiDeviceSetupScreenView::kScreenId, 0 /* exit_code */);
 
   OnOobeFlowFinished();
 }
 
 void WizardController::OnResetScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_OOBE_RESET, 0 /* exit_code */);
+  OnScreenExit(ResetView::kScreenId, 0 /* exit_code */);
   OnDeviceModificationCanceled();
 }
 
@@ -1139,14 +1141,14 @@
 }
 
 void WizardController::OnSupervisionTransitionScreenExit() {
-  OnScreenExit(OobeScreen::SCREEN_SUPERVISION_TRANSITION, 0 /* exit_code */);
+  OnScreenExit(SupervisionTransitionScreenView::kScreenId, 0 /* exit_code */);
 
   OnOobeFlowFinished();
 }
 
 void WizardController::OnOobeFlowFinished() {
   if (is_in_session_oobe_ && current_screen_->screen_id() !=
-                                 OobeScreen::SCREEN_SUPERVISION_TRANSITION) {
+                                 SupervisionTransitionScreenView::kScreenId) {
     GetLoginDisplayHost()->SetStatusAreaVisible(true);
     GetLoginDisplayHost()->Finalize(base::OnceClosure());
     return;
@@ -1224,7 +1226,7 @@
 }
 
 void WizardController::StartOOBEUpdate() {
-  SetCurrentScreenSmooth(GetScreen(OobeScreen::SCREEN_OOBE_UPDATE), true);
+  SetCurrentScreenSmooth(GetScreen(UpdateView::kScreenId), true);
   UpdateScreen::Get(screen_manager())->StartNetworkCheck();
 }
 
@@ -1338,18 +1340,18 @@
 
 void WizardController::UpdateStatusAreaVisibilityForScreen(
     OobeScreenId screen) {
-  if (screen == OobeScreen::SCREEN_OOBE_WELCOME) {
+  if (screen == WelcomeView::kScreenId) {
     // Hide the status area initially; it only appears after OOBE first animates
     // in. Keep it visible if the user goes back to the existing welcome screen.
     GetLoginDisplayHost()->SetStatusAreaVisible(
-        screen_manager_->HasScreen(OobeScreen::SCREEN_OOBE_WELCOME));
-  } else if (screen == OobeScreen::SCREEN_OOBE_RESET ||
-             screen == OobeScreen::SCREEN_KIOSK_ENABLE ||
-             screen == OobeScreen::SCREEN_KIOSK_AUTOLAUNCH ||
-             screen == OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING ||
-             screen == OobeScreen::SCREEN_WRONG_HWID ||
-             screen == OobeScreen::SCREEN_SUPERVISION_TRANSITION ||
-             screen == OobeScreen::SCREEN_ARC_KIOSK_SPLASH) {
+        screen_manager_->HasScreen(WelcomeView::kScreenId));
+  } else if (screen == ResetView::kScreenId ||
+             screen == KioskEnableScreenView::kScreenId ||
+             screen == KioskAutolaunchScreenView::kScreenId ||
+             screen == EnableDebuggingScreenView::kScreenId ||
+             screen == WrongHWIDScreenView::kScreenId ||
+             screen == SupervisionTransitionScreenView::kScreenId ||
+             screen == ArcKioskSplashScreenView::kScreenId) {
     GetLoginDisplayHost()->SetStatusAreaVisible(false);
   } else {
     GetLoginDisplayHost()->SetStatusAreaVisible(true);
@@ -1391,73 +1393,73 @@
 }
 
 void WizardController::AdvanceToScreen(OobeScreenId screen) {
-  if (screen == OobeScreen::SCREEN_OOBE_WELCOME) {
+  if (screen == WelcomeView::kScreenId) {
     ShowWelcomeScreen();
-  } else if (screen == OobeScreen::SCREEN_OOBE_NETWORK) {
+  } else if (screen == NetworkScreenView::kScreenId) {
     ShowNetworkScreen();
   } else if (screen == OobeScreen::SCREEN_SPECIAL_LOGIN) {
     ShowLoginScreen(LoginScreenContext());
-  } else if (screen == OobeScreen::SCREEN_OOBE_UPDATE) {
+  } else if (screen == UpdateView::kScreenId) {
     InitiateOOBEUpdate();
-  } else if (screen == OobeScreen::SCREEN_OOBE_EULA) {
+  } else if (screen == EulaView::kScreenId) {
     ShowEulaScreen();
-  } else if (screen == OobeScreen::SCREEN_OOBE_RESET) {
+  } else if (screen == ResetView::kScreenId) {
     ShowResetScreen();
-  } else if (screen == OobeScreen::SCREEN_KIOSK_ENABLE) {
+  } else if (screen == KioskEnableScreenView::kScreenId) {
     ShowKioskEnableScreen();
-  } else if (screen == OobeScreen::SCREEN_KIOSK_AUTOLAUNCH) {
+  } else if (screen == KioskAutolaunchScreenView::kScreenId) {
     ShowKioskAutolaunchScreen();
-  } else if (screen == OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING) {
+  } else if (screen == EnableDebuggingScreenView::kScreenId) {
     ShowEnableDebuggingScreen();
-  } else if (screen == OobeScreen::SCREEN_OOBE_ENROLLMENT) {
+  } else if (screen == EnrollmentScreenView::kScreenId) {
     ShowEnrollmentScreen();
-  } else if (screen == OobeScreen::SCREEN_OOBE_DEMO_SETUP) {
+  } else if (screen == DemoSetupScreenView::kScreenId) {
     ShowDemoModeSetupScreen();
-  } else if (screen == OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES) {
+  } else if (screen == DemoPreferencesScreenView::kScreenId) {
     ShowDemoModePreferencesScreen();
-  } else if (screen == OobeScreen::SCREEN_TERMS_OF_SERVICE) {
+  } else if (screen == TermsOfServiceScreenView::kScreenId) {
     ShowTermsOfServiceScreen();
-  } else if (screen == OobeScreen::SCREEN_SYNC_CONSENT) {
+  } else if (screen == SyncConsentScreenView::kScreenId) {
     ShowSyncConsentScreen();
-  } else if (screen == OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE) {
+  } else if (screen == ArcTermsOfServiceScreenView::kScreenId) {
     ShowArcTermsOfServiceScreen();
-  } else if (screen == OobeScreen::SCREEN_RECOMMEND_APPS) {
+  } else if (screen == RecommendAppsScreenView::kScreenId) {
     ShowRecommendAppsScreen();
-  } else if (screen == OobeScreen::SCREEN_APP_DOWNLOADING) {
+  } else if (screen == AppDownloadingScreenView::kScreenId) {
     ShowAppDownloadingScreen();
-  } else if (screen == OobeScreen::SCREEN_WRONG_HWID) {
+  } else if (screen == WrongHWIDScreenView::kScreenId) {
     ShowWrongHWIDScreen();
-  } else if (screen == OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK) {
+  } else if (screen == AutoEnrollmentCheckScreenView::kScreenId) {
     ShowAutoEnrollmentCheckScreen();
-  } else if (screen == OobeScreen::SCREEN_APP_LAUNCH_SPLASH) {
+  } else if (screen == AppLaunchSplashScreenView::kScreenId) {
     AutoLaunchKioskApp();
-  } else if (screen == OobeScreen::SCREEN_ARC_KIOSK_SPLASH) {
+  } else if (screen == ArcKioskSplashScreenView::kScreenId) {
     ShowArcKioskSplashScreen();
-  } else if (screen == OobeScreen::SCREEN_OOBE_HID_DETECTION) {
+  } else if (screen == HIDDetectionView::kScreenId) {
     ShowHIDDetectionScreen();
-  } else if (screen == OobeScreen::SCREEN_DEVICE_DISABLED) {
+  } else if (screen == DeviceDisabledScreenView::kScreenId) {
     ShowDeviceDisabledScreen();
-  } else if (screen == OobeScreen::SCREEN_ENCRYPTION_MIGRATION) {
+  } else if (screen == EncryptionMigrationScreenView::kScreenId) {
     ShowEncryptionMigrationScreen();
-  } else if (screen == OobeScreen::SCREEN_UPDATE_REQUIRED) {
+  } else if (screen == UpdateRequiredView::kScreenId) {
     ShowUpdateRequiredScreen();
-  } else if (screen == OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW) {
+  } else if (screen == AssistantOptInFlowScreenView::kScreenId) {
     ShowAssistantOptInFlowScreen();
-  } else if (screen == OobeScreen::SCREEN_MULTIDEVICE_SETUP) {
+  } else if (screen == MultiDeviceSetupScreenView::kScreenId) {
     ShowMultiDeviceSetupScreen();
-  } else if (screen == OobeScreen::SCREEN_DISCOVER) {
+  } else if (screen == DiscoverScreenView::kScreenId) {
     ShowDiscoverScreen();
-  } else if (screen == OobeScreen::SCREEN_FINGERPRINT_SETUP) {
+  } else if (screen == FingerprintSetupScreenView::kScreenId) {
     ShowFingerprintSetupScreen();
-  } else if (screen == OobeScreen::SCREEN_MARKETING_OPT_IN) {
+  } else if (screen == MarketingOptInScreenView::kScreenId) {
     ShowMarketingOptInScreen();
-  } else if (screen == OobeScreen::SCREEN_SUPERVISION_TRANSITION) {
+  } else if (screen == SupervisionTransitionScreenView::kScreenId) {
     ShowSupervisionTransitionScreen();
   } else if (screen != OobeScreen::SCREEN_TEST_NO_WINDOW) {
     if (is_out_of_box_) {
       time_oobe_started_ = base::Time::Now();
       if (CanShowHIDDetectionScreen()) {
-        hid_screen_ = GetScreen(OobeScreen::SCREEN_OOBE_HID_DETECTION);
+        hid_screen_ = GetScreen(HIDDetectionView::kScreenId);
         base::Callback<void(bool)> on_check =
             base::Bind(&WizardController::OnHIDScreenNecessityCheck,
                        weak_factory_.GetWeakPtr());
@@ -1489,7 +1491,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 // WizardController, BaseScreenDelegate overrides:
 void WizardController::ShowErrorScreen() {
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ERROR_MESSAGE));
+  SetCurrentScreen(GetScreen(ErrorScreenView::kScreenId));
 }
 
 void WizardController::OnAccessibilityStatusChanged(
@@ -1561,12 +1563,12 @@
 
 // static
 bool WizardController::IsOOBEStepToTrack(OobeScreenId screen_id) {
-  return (screen_id == OobeScreen::SCREEN_OOBE_HID_DETECTION ||
-          screen_id == OobeScreen::SCREEN_OOBE_WELCOME ||
-          screen_id == OobeScreen::SCREEN_OOBE_UPDATE ||
-          screen_id == OobeScreen::SCREEN_OOBE_EULA ||
+  return (screen_id == HIDDetectionView::kScreenId ||
+          screen_id == WelcomeView::kScreenId ||
+          screen_id == UpdateView::kScreenId ||
+          screen_id == EulaView::kScreenId ||
           screen_id == OobeScreen::SCREEN_SPECIAL_LOGIN ||
-          screen_id == OobeScreen::SCREEN_WRONG_HWID);
+          screen_id == WrongHWIDScreenView::kScreenId);
 }
 
 // static
@@ -1577,12 +1579,12 @@
 
   const OobeScreenId current_screen_id =
       default_controller()->current_screen()->screen_id();
-  if (current_screen_id == OobeScreen::SCREEN_TERMS_OF_SERVICE ||
-      current_screen_id == OobeScreen::SCREEN_SYNC_CONSENT ||
-      current_screen_id == OobeScreen::SCREEN_FINGERPRINT_SETUP ||
-      current_screen_id == OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE ||
-      current_screen_id == OobeScreen::SCREEN_DISCOVER ||
-      current_screen_id == OobeScreen::SCREEN_MARKETING_OPT_IN) {
+  if (current_screen_id == TermsOfServiceScreenView::kScreenId ||
+      current_screen_id == SyncConsentScreenView::kScreenId ||
+      current_screen_id == FingerprintSetupScreenView::kScreenId ||
+      current_screen_id == ArcTermsOfServiceScreenView::kScreenId ||
+      current_screen_id == DiscoverScreenView::kScreenId ||
+      current_screen_id == MarketingOptInScreenView::kScreenId) {
     default_controller()->OnOobeFlowFinished();
   } else {
     LOG(WARNING) << "SkipPostLoginScreensForTesting(): Ignore screen "
@@ -1751,7 +1753,7 @@
 
   EnrollmentScreen* screen = EnrollmentScreen::Get(screen_manager());
   screen->SetEnrollmentConfig(effective_config);
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  UpdateStatusAreaVisibilityForScreen(EnrollmentScreenView::kScreenId);
   SetCurrentScreen(screen);
 }
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index d347889..0885efc 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -103,12 +103,12 @@
 
   // Starts Demo Mode setup flow. The flow starts from network screen and reuses
   // some of regular OOBE screens. It consists of the following screens:
-  //    chromeos::OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES
-  //    chromeos::OobeScreen::SCREEN_OOBE_NETWORK
-  //    chromeos::OobeScreen::SCREEN_OOBE_EULA
-  //    chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE
-  //    chromeos::OobeScreen::SCREEN_OOBE_UPDATE
-  //    chromeos::OobeScreen::SCREEN_OOBE_DEMO_SETUP
+  //    chromeos::DemoPreferencesScreenView::kScreenId
+  //    chromeos::NetworkScreenView::kScreenId
+  //    chromeos::EulaView::kScreenId
+  //    chromeos::ArcTermsOfServiceScreenView::kScreenId
+  //    chromeos::UpdateView::kScreenId
+  //    chromeos::DemoSetupScreenView::kScreenId
   void StartDemoModeSetup();
 
   // Simulates demo mode setup environment. If |demo_config| has a value, it
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 01b68cf..d6e0b04c 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -419,7 +419,7 @@
   WrongHWIDScreen* GetWrongHWIDScreen() {
     return static_cast<WrongHWIDScreen*>(
         WizardController::default_controller()->GetScreen(
-            OobeScreen::SCREEN_WRONG_HWID));
+            WrongHWIDScreenView::kScreenId));
   }
 
  private:
@@ -429,7 +429,7 @@
 IN_PROC_BROWSER_TEST_F(WizardControllerTest, SwitchLanguage) {
   ASSERT_TRUE(WizardController::default_controller() != NULL);
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_OOBE_WELCOME);
+      WelcomeView::kScreenId);
 
   // Checking the default locale. Provided that the profile is cleared in SetUp.
   EXPECT_EQ("en-US", g_browser_process->GetApplicationLocale());
@@ -545,8 +545,8 @@
   LoginDisplayHost::default_host()->StartSignInScreen(LoginScreenContext());
   // Advance to supervision transition screen.
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_SUPERVISION_TRANSITION);
-  CheckCurrentScreen(OobeScreen::SCREEN_SUPERVISION_TRANSITION);
+      SupervisionTransitionScreenView::kScreenId);
+  CheckCurrentScreen(SupervisionTransitionScreenView::kScreenId);
   mock_supervision_transition_screen_->ExitScreen();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(session_manager::SessionManager::Get()->session_state(),
@@ -696,7 +696,7 @@
     EXPECT_EQ(NULL, wizard_controller->current_screen());
     EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(NotNull())).Times(1);
     EXPECT_CALL(*mock_welcome_screen_, Show()).Times(1);
-    wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+    wizard_controller->AdvanceToScreen(WelcomeView::kScreenId);
   }
 
   void TearDownOnMainThread() override {
@@ -743,11 +743,11 @@
   void ResetAutoEnrollmentCheckScreen() {
     WizardController::default_controller()
         ->screen_manager()
-        ->DeleteScreenForTesting(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+        ->DeleteScreenForTesting(AutoEnrollmentCheckScreenView::kScreenId);
   }
 
   void TestControlFlowMain() {
-    CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+    CheckCurrentScreen(WelcomeView::kScreenId);
 
     WaitUntilJSIsReady();
 
@@ -778,11 +778,11 @@
     EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
     mock_welcome_screen_->ExitScreen();
 
-    CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+    CheckCurrentScreen(NetworkScreenView::kScreenId);
     EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
     mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-    CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+    CheckCurrentScreen(EulaView::kScreenId);
     // Login shelf should still be visible.
     EXPECT_TRUE(shelf_helper.IsLoginShelfShown());
 
@@ -798,12 +798,12 @@
     // Let update screen smooth time process (time = 0ms).
     content::RunAllPendingInMessageLoop();
 
-    CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+    CheckCurrentScreen(UpdateView::kScreenId);
     EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
     EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
     mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-    CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+    CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
     EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(0);
     EXPECT_CALL(*mock_eula_screen_, Show()).Times(0);
     mock_auto_enrollment_check_screen_->ExitScreen();
@@ -877,7 +877,7 @@
 // log in.
 IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
                        ControlFlowErrorUpdateNonCriticalUpdate) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(0);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
@@ -885,12 +885,12 @@
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -900,12 +900,12 @@
   // Let update screen smooth time process (time = 0ms).
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(0);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(0);
   mock_auto_enrollment_check_screen_->ExitScreen();
@@ -918,7 +918,7 @@
 // screen and thus prevents the user from proceeding to log in.
 IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
                        ControlFlowErrorUpdateCriticalUpdate) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(0);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
@@ -926,12 +926,12 @@
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -941,18 +941,18 @@
   // Let update screen smooth time process (time = 0ms).
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(0);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(0);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(0);  // last transition
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_ERROR);
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowSkipUpdateEnroll) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(0);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
@@ -960,12 +960,12 @@
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(0);
@@ -980,43 +980,43 @@
       EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING);
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_enrollment_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_enrollment_screen_, Hide()).Times(0);
   mock_auto_enrollment_check_screen_->ExitScreen();
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
   EXPECT_EQ("ethernet,wifi,cellular", NetworkHandler::Get()
                                           ->network_state_handler()
                                           ->GetCheckPortalListForTest());
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowEulaDeclined) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   mock_eula_screen_->ExitScreen(EulaScreen::Result::BACK);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
                        ControlFlowEnrollmentCompleted) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0);
   EXPECT_CALL(*mock_enrollment_screen_view_,
               SetEnrollmentConfig(
@@ -1028,8 +1028,8 @@
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
 
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_OOBE_ENROLLMENT);
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+      EnrollmentScreenView::kScreenId);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
   mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
 
   EXPECT_FALSE(ExistingUserController::current_controller() == NULL);
@@ -1037,13 +1037,13 @@
 
 IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
                        ControlFlowWrongHWIDScreenFromLogin) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
 
   LoginDisplayHost::default_host()->StartSignInScreen(LoginScreenContext());
   EXPECT_FALSE(ExistingUserController::current_controller() == NULL);
   ExistingUserController::current_controller()->ShowWrongHWIDScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_WRONG_HWID);
+  CheckCurrentScreen(WrongHWIDScreenView::kScreenId);
 
   // After warning is skipped, user returns to sign-in screen.
   // And this destroys WizardController.
@@ -1074,7 +1074,7 @@
 // OOBE is marked complete, it allows the user to proceed to log in.
 IN_PROC_BROWSER_TEST_P(WizardControllerUpdateAfterCompletedOobeTest,
                        ControlFlowErrorUpdate) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(0);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
@@ -1082,12 +1082,12 @@
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1097,12 +1097,12 @@
   // Let update screen smooth time process (time = 0ms).
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(GetParam());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(0);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(0);
   mock_auto_enrollment_check_screen_->ExitScreen();
@@ -1199,18 +1199,18 @@
   EXPECT_NE(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1220,12 +1220,12 @@
   // Let update screen smooth time process (time = 0ms).
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   mock_auto_enrollment_check_screen_->RealShow();
   EXPECT_EQ(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
@@ -1245,18 +1245,18 @@
 #endif
 IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateTest,
                        MAYBE_ControlFlowDeviceDisabled) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1266,12 +1266,12 @@
   // Let update screen smooth time process (time = 0ms).
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
   mock_auto_enrollment_check_screen_->RealShow();
 
@@ -1280,8 +1280,8 @@
 
   // The error screen shows up if device state could not be retrieved.
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK.AsId(),
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
+  EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
             GetErrorScreen()->GetParentScreen());
   base::DictionaryValue device_state;
   device_state.SetString(policy::kDeviceStateMode,
@@ -1298,7 +1298,7 @@
   ResetAutoEnrollmentCheckScreen();
 
   // Make sure the device disabled screen is shown.
-  CheckCurrentScreen(OobeScreen::SCREEN_DEVICE_DISABLED);
+  CheckCurrentScreen(DeviceDisabledScreenView::kScreenId);
 
   EXPECT_EQ(0,
             FakeCryptohomeClient::Get()
@@ -1347,18 +1347,18 @@
 // LSan bot.
 IN_PROC_BROWSER_TEST_P(WizardControllerDeviceStateExplicitRequirementTest,
                        DISABLED_ControlFlowForcedReEnrollment) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1368,12 +1368,12 @@
   // Let update screen smooth time process (time = 0ms).
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
   mock_auto_enrollment_check_screen_->RealShow();
 
@@ -1382,8 +1382,8 @@
 
   // The error screen shows up if there's no auto-enrollment decision.
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK.AsId(),
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
+  EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
             GetErrorScreen()->GetParentScreen());
 
   WaitUntilJSIsReady();
@@ -1426,7 +1426,7 @@
   ResetAutoEnrollmentCheckScreen();
 
   // Make sure enterprise enrollment page shows up.
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
   mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
 
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
@@ -1447,18 +1447,18 @@
   ScopedFakeAutoEnrollmentClientFactory fake_auto_enrollment_client_factory(
       auto_enrollment_controller());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1468,12 +1468,12 @@
   // Let update screen smooth time process (time = 0ms).
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   mock_auto_enrollment_check_screen_->RealShow();
 
   policy::FakeAutoEnrollmentClient* fake_auto_enrollment_client =
@@ -1491,8 +1491,8 @@
 
     // The error screen shows up.
     EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-    CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-    EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK.AsId(),
+    CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
+    EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
               GetErrorScreen()->GetParentScreen());
 
     WaitUntilJSIsReady();
@@ -1523,7 +1523,7 @@
     ResetAutoEnrollmentCheckScreen();
 
     // Make sure enterprise enrollment page shows up.
-    CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+    CheckCurrentScreen(EnrollmentScreenView::kScreenId);
     mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
 
     EXPECT_TRUE(StartupUtils::IsOobeCompleted());
@@ -1593,18 +1593,18 @@
   fake_statistics_provider_.SetMachineStatistic(
       system::kRlzEmbargoEndDateKey,
       GenerateEmbargoEndDate(-15 /* days_offset */));
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1614,12 +1614,12 @@
   // Let update screen smooth time process (time = 0ms).
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
   mock_auto_enrollment_check_screen_->RealShow();
 
@@ -1628,7 +1628,7 @@
 
   // The error screen shows up if there's no auto-enrollment decision.
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK.AsId(),
+  EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
             GetErrorScreen()->GetParentScreen());
   base::DictionaryValue device_state;
   device_state.SetString(policy::kDeviceStateMode,
@@ -1647,7 +1647,7 @@
   ResetAutoEnrollmentCheckScreen();
 
   // Make sure enterprise enrollment page shows up.
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
   mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
 
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
@@ -1668,18 +1668,18 @@
   fake_statistics_provider_.SetMachineStatistic(
       system::kRlzEmbargoEndDateKey,
       GenerateEmbargoEndDate(-15 /* days_offset */));
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1689,12 +1689,12 @@
   // Let update screen smooth time process (time = 0ms).
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   mock_auto_enrollment_check_screen_->RealShow();
 
   policy::FakeAutoEnrollmentClient* fake_auto_enrollment_client =
@@ -1712,7 +1712,7 @@
 
   // The error screen shows up if there's no auto-enrollment decision.
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
-  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK.AsId(),
+  EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
             GetErrorScreen()->GetParentScreen());
 
   WaitUntilJSIsReady();
@@ -1742,7 +1742,7 @@
   ResetAutoEnrollmentCheckScreen();
 
   // Make sure enterprise enrollment page shows up.
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
   mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
 
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
@@ -1764,18 +1764,18 @@
   EXPECT_NE(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1785,12 +1785,12 @@
   // Let update screen smooth time process (time = 0ms).
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   mock_auto_enrollment_check_screen_->RealShow();
   EXPECT_EQ(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
@@ -1809,18 +1809,18 @@
   EXPECT_NE(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1830,12 +1830,12 @@
   // Let update screen smooth time process (time = 0ms).
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   mock_auto_enrollment_check_screen_->RealShow();
   EXPECT_EQ(AutoEnrollmentController::AutoEnrollmentCheckType::kNone,
             auto_enrollment_controller()->auto_enrollment_check_type());
@@ -1866,18 +1866,18 @@
   EXPECT_NE(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1887,12 +1887,12 @@
   // Let update screen smooth time process (time = 0ms).
   task_runner->RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   mock_auto_enrollment_check_screen_->RealShow();
   EXPECT_EQ(AutoEnrollmentController::AutoEnrollmentCheckType::kNone,
             auto_enrollment_controller()->auto_enrollment_check_type());
@@ -1923,18 +1923,18 @@
   EXPECT_NE(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -1944,12 +1944,12 @@
   // Let update screen smooth time process (time = 0ms).
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   mock_auto_enrollment_check_screen_->RealShow();
   EXPECT_EQ(AutoEnrollmentController::AutoEnrollmentCheckType::kNone,
             auto_enrollment_controller()->auto_enrollment_check_type());
@@ -1987,7 +1987,7 @@
       policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT);
 
   // Make sure enterprise enrollment page shows up.
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
   mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
 
@@ -2006,18 +2006,18 @@
   EXPECT_NE(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -2027,12 +2027,12 @@
   // Let update screen smooth time process (time = 0ms).
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   mock_auto_enrollment_check_screen_->RealShow();
   EXPECT_EQ(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT,
             auto_enrollment_controller()->state());
@@ -2102,7 +2102,7 @@
   void SetUpOnMainThread() override {
     WizardControllerTest::SetUpOnMainThread();
     WizardController::default_controller()->AdvanceToScreen(
-        OobeScreen::SCREEN_OOBE_WELCOME);
+        WelcomeView::kScreenId);
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -2126,7 +2126,7 @@
       chrome::NOTIFICATION_AUTH_NEEDED,
       content::NotificationService::AllSources());
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
 
   LoginDisplayHost::default_host()->StartSignInScreen(LoginScreenContext());
   auth_needed_waiter.Wait();
@@ -2159,18 +2159,18 @@
           mock_enrollment_screen_,
           EnrollmentModeMatches(policy::EnrollmentConfig::MODE_LOCAL_FORCED)))
       .Times(1);
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -2180,12 +2180,12 @@
   // Let update screen smooth time process (time = 0ms).
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_enrollment_screen_, Show()).Times(1);
   mock_auto_enrollment_check_screen_->ExitScreen();
@@ -2193,7 +2193,7 @@
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
 
   // Make sure enterprise enrollment page shows up right after update screen.
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
   mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
 
   EXPECT_TRUE(StartupUtils::IsOobeCompleted());
@@ -2208,18 +2208,18 @@
           EnrollmentModeMatches(policy::EnrollmentConfig::MODE_LOCAL_FORCED)))
       .Times(1);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
   EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
   mock_welcome_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1);
   EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
@@ -2229,12 +2229,12 @@
   // Let update screen smooth time process (time = 0ms).
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_enrollment_screen_, Show()).Times(1);
   EXPECT_CALL(*mock_enrollment_screen_, Hide()).Times(1);
@@ -2243,11 +2243,11 @@
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
 
   // Make sure enterprise enrollment page shows up right after update screen.
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1);
   mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::BACK);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
 }
 
@@ -2267,7 +2267,7 @@
 
 IN_PROC_BROWSER_TEST_F(WizardControllerEnableDebuggingTest,
                        ShowAndCancelEnableDebugging) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   WaitUntilJSIsReady();
 
   EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1);
@@ -2286,7 +2286,7 @@
 
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING);
+  CheckCurrentScreen(EnableDebuggingScreenView::kScreenId);
   EXPECT_CALL(*mock_enable_debugging_screen_, Hide()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(NotNull())).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, Show()).Times(1);
@@ -2296,7 +2296,7 @@
   // Let update screen smooth time process (time = 0ms).
   content::RunAllPendingInMessageLoop();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
 }
 
 class WizardControllerDemoSetupTest : public WizardControllerFlowTest {
@@ -2324,7 +2324,7 @@
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest,
                        OnlineDemoSetupFlowFinished) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   WaitUntilJSIsReady();
 
@@ -2334,7 +2334,7 @@
 
   WizardController::default_controller()->StartDemoModeSetup();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+  CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_demo_preferences_screen_, Hide()).Times(1);
@@ -2343,7 +2343,7 @@
   mock_demo_preferences_screen_->ExitScreen(
       DemoPreferencesScreen::Result::COMPLETED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
@@ -2351,7 +2351,7 @@
 
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
@@ -2360,7 +2360,7 @@
   mock_eula_screen_->ExitScreen(
       EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
+  CheckCurrentScreen(ArcTermsOfServiceScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_arc_terms_of_service_screen_, Hide()).Times(1);
@@ -2371,7 +2371,7 @@
 
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
@@ -2379,7 +2379,7 @@
 
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
@@ -2387,7 +2387,7 @@
 
   mock_auto_enrollment_check_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+  CheckCurrentScreen(DemoSetupScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   mock_demo_setup_screen_->ExitScreen(DemoSetupScreen::Result::COMPLETED);
@@ -2399,7 +2399,7 @@
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest,
                        OfflineDemoSetupFlowFinished) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   WaitUntilJSIsReady();
 
@@ -2409,7 +2409,7 @@
 
   WizardController::default_controller()->StartDemoModeSetup();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+  CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_demo_preferences_screen_, Hide()).Times(1);
@@ -2418,7 +2418,7 @@
   mock_demo_preferences_screen_->ExitScreen(
       DemoPreferencesScreen::Result::COMPLETED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
@@ -2426,7 +2426,7 @@
 
   mock_network_screen_->ExitScreen(NetworkScreen::Result::OFFLINE_DEMO_SETUP);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
@@ -2435,7 +2435,7 @@
   mock_eula_screen_->ExitScreen(
       EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
+  CheckCurrentScreen(ArcTermsOfServiceScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_arc_terms_of_service_screen_, Hide()).Times(1);
@@ -2446,7 +2446,7 @@
 
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+  CheckCurrentScreen(DemoSetupScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   mock_demo_setup_screen_->ExitScreen(DemoSetupScreen::Result::COMPLETED);
@@ -2457,7 +2457,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, DemoSetupCanceled) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   WaitUntilJSIsReady();
 
@@ -2467,7 +2467,7 @@
 
   WizardController::default_controller()->StartDemoModeSetup();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+  CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_demo_preferences_screen_, Hide()).Times(1);
@@ -2476,7 +2476,7 @@
   mock_demo_preferences_screen_->ExitScreen(
       DemoPreferencesScreen::Result::COMPLETED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
@@ -2484,7 +2484,7 @@
 
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
@@ -2493,7 +2493,7 @@
   mock_eula_screen_->ExitScreen(
       EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
+  CheckCurrentScreen(ArcTermsOfServiceScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_arc_terms_of_service_screen_, Hide()).Times(1);
@@ -2504,7 +2504,7 @@
 
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
@@ -2512,7 +2512,7 @@
 
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
@@ -2520,7 +2520,7 @@
 
   mock_auto_enrollment_check_screen_->ExitScreen();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+  CheckCurrentScreen(DemoSetupScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_demo_setup_screen_, Hide()).Times(1);
@@ -2529,19 +2529,19 @@
 
   mock_demo_setup_screen_->ExitScreen(DemoSetupScreen::Result::CANCELED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, DemoPreferencesCanceled) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   WaitUntilJSIsReady();
-  SkipToScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES,
+  SkipToScreen(DemoPreferencesScreenView::kScreenId,
                mock_demo_preferences_screen_);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+  CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_demo_preferences_screen_, Hide()).Times(1);
@@ -2550,17 +2550,17 @@
   mock_demo_preferences_screen_->ExitScreen(
       DemoPreferencesScreen::Result::CANCELED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, NetworkBackPressed) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   WaitUntilJSIsReady();
-  SkipToScreen(OobeScreen::SCREEN_OOBE_NETWORK, mock_network_screen_);
+  SkipToScreen(NetworkScreenView::kScreenId, mock_network_screen_);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
@@ -2568,17 +2568,17 @@
 
   mock_network_screen_->ExitScreen(NetworkScreen::Result::BACK);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+  CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, EulaBackPressed) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   WaitUntilJSIsReady();
-  SkipToScreen(OobeScreen::SCREEN_OOBE_EULA, mock_eula_screen_);
+  SkipToScreen(EulaView::kScreenId, mock_eula_screen_);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
@@ -2586,21 +2586,21 @@
 
   mock_eula_screen_->ExitScreen(EulaScreen::Result::BACK);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, ArcTosBackPressed) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   WaitUntilJSIsReady();
 
   // User cannot go to ARC ToS screen without accepting eula - simulate that.
   StartupUtils::MarkEulaAccepted();
-  SkipToScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
+  SkipToScreen(ArcTermsOfServiceScreenView::kScreenId,
                mock_arc_terms_of_service_screen_);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
+  CheckCurrentScreen(ArcTermsOfServiceScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_arc_terms_of_service_screen_, Hide()).Times(1);
@@ -2609,7 +2609,7 @@
   mock_arc_terms_of_service_screen_->ExitScreen(
       ArcTermsOfServiceScreen::Result::BACK);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 }
 
@@ -2631,7 +2631,7 @@
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupDeviceDisabledTest,
                        OnlineDemoSetup) {
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
   WaitUntilJSIsReady();
 
@@ -2641,7 +2641,7 @@
 
   WizardController::default_controller()->StartDemoModeSetup();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+  CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_demo_preferences_screen_, Hide()).Times(1);
@@ -2650,7 +2650,7 @@
   mock_demo_preferences_screen_->ExitScreen(
       DemoPreferencesScreen::Result::COMPLETED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_NETWORK);
+  CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
@@ -2658,7 +2658,7 @@
 
   mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_EULA);
+  CheckCurrentScreen(EulaView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
@@ -2667,7 +2667,7 @@
   mock_eula_screen_->ExitScreen(
       EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
+  CheckCurrentScreen(ArcTermsOfServiceScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_arc_terms_of_service_screen_, Hide()).Times(1);
@@ -2678,7 +2678,7 @@
 
   base::RunLoop().RunUntilIdle();
 
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_UPDATE);
+  CheckCurrentScreen(UpdateView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
@@ -2686,7 +2686,7 @@
 
   mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
 
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
 
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1);
@@ -2697,8 +2697,8 @@
   WaitForAutoEnrollmentState(policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR);
 
   // The error screen shows up if device state could not be retrieved.
-  CheckCurrentScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
-  EXPECT_EQ(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK.AsId(),
+  CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
+  EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
             GetErrorScreen()->GetParentScreen());
   base::DictionaryValue device_state;
   device_state.SetString(policy::kDeviceStateMode,
@@ -2713,7 +2713,7 @@
   base::RunLoop().RunUntilIdle();
 
   ResetAutoEnrollmentCheckScreen();
-  CheckCurrentScreen(OobeScreen::SCREEN_DEVICE_DISABLED);
+  CheckCurrentScreen(DeviceDisabledScreenView::kScreenId);
 
   EXPECT_FALSE(StartupUtils::IsOobeCompleted());
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
@@ -2774,8 +2774,8 @@
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(NotNull())).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, Show()).Times(1);
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_OOBE_WELCOME);
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+      WelcomeView::kScreenId);
+  CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_enrollment_screen_view_,
               SetEnrollmentConfig(
                   mock_enrollment_screen_,
@@ -2786,13 +2786,13 @@
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(IsNull())).Times(1);
 
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_OOBE_ENROLLMENT);
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
+      EnrollmentScreenView::kScreenId);
+  CheckCurrentScreen(EnrollmentScreenView::kScreenId);
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerOobeResumeTest,
                        ControlFlowResumeInterruptedOobe) {
-  EXPECT_EQ(OobeScreen::SCREEN_OOBE_ENROLLMENT.AsId(), GetFirstScreen());
+  EXPECT_EQ(EnrollmentScreenView::kScreenId.AsId(), GetFirstScreen());
 }
 
 class WizardControllerCellularFirstTest : public WizardControllerFlowTest {
@@ -2873,8 +2873,8 @@
   EXPECT_CALL(*mock_welcome_screen_, SetConfiguration(NonEmptyConfiguration()))
       .Times(1);
   WizardController::default_controller()->AdvanceToScreen(
-      OobeScreen::SCREEN_OOBE_WELCOME);
-  CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
+      WelcomeView::kScreenId);
+  CheckCurrentScreen(WelcomeView::kScreenId);
 }
 
 // TODO(dzhioev): Add test emulating device with wrong HWID.
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 5170431..9dea24f4 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -86,6 +86,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/grit/chromium_strings.h"
@@ -2182,7 +2183,7 @@
         chromeos::WizardController::default_controller();
   ASSERT_TRUE(wizard_controller);
   ASSERT_TRUE(wizard_controller->current_screen());
-  EXPECT_EQ(chromeos::OobeScreen::SCREEN_TERMS_OF_SERVICE.AsId(),
+  EXPECT_EQ(chromeos::TermsOfServiceScreenView::kScreenId.AsId(),
             wizard_controller->current_screen()->screen_id());
 
   // Wait for the Terms of Service to finish downloading.
@@ -2638,7 +2639,7 @@
         chromeos::WizardController::default_controller();
   ASSERT_TRUE(wizard_controller);
   ASSERT_TRUE(wizard_controller->current_screen());
-  EXPECT_EQ(chromeos::OobeScreen::SCREEN_TERMS_OF_SERVICE.AsId(),
+  EXPECT_EQ(chromeos::TermsOfServiceScreenView::kScreenId.AsId(),
             wizard_controller->current_screen()->screen_id());
 
   // Wait for the Terms of Service to finish downloading, then get the status of
@@ -2784,7 +2785,7 @@
       chromeos::WizardController::default_controller();
   ASSERT_TRUE(wizard_controller);
   ASSERT_TRUE(wizard_controller->current_screen());
-  EXPECT_EQ(chromeos::OobeScreen::SCREEN_TERMS_OF_SERVICE.AsId(),
+  EXPECT_EQ(chromeos::TermsOfServiceScreenView::kScreenId.AsId(),
             wizard_controller->current_screen()->screen_id());
 
   // Click the back button.
diff --git a/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.cc b/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.cc
index 2995687..1cb34c8 100644
--- a/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.cc
+++ b/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.cc
@@ -4,18 +4,18 @@
 
 #include "chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.h"
 
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
 #include "components/policy/policy_constants.h"
 
 namespace policy {
 
 namespace {
 
-chromeos::DiagnosticsdManager* GetDiagnosticsdManager() {
-  chromeos::DiagnosticsdManager* const diagnosticsd_manager =
-      chromeos::DiagnosticsdManager::Get();
-  DCHECK(diagnosticsd_manager);
-  return diagnosticsd_manager;
+chromeos::WilcoDtcSupportdManager* GetWilcoDtcSupportdManager() {
+  chromeos::WilcoDtcSupportdManager* const wilco_dtc_supportd_manager =
+      chromeos::WilcoDtcSupportdManager::Get();
+  DCHECK(wilco_dtc_supportd_manager);
+  return wilco_dtc_supportd_manager;
 }
 
 }  // namespace
@@ -32,14 +32,14 @@
 
 void DeviceWilcoDtcConfigurationHandler::OnDeviceExternalDataCleared(
     const std::string& policy) {
-  GetDiagnosticsdManager()->SetConfigurationData(nullptr);
+  GetWilcoDtcSupportdManager()->SetConfigurationData(nullptr);
 }
 
 void DeviceWilcoDtcConfigurationHandler::OnDeviceExternalDataFetched(
     const std::string& policy,
     std::unique_ptr<std::string> data,
     const base::FilePath& file_path) {
-  GetDiagnosticsdManager()->SetConfigurationData(std::move(data));
+  GetWilcoDtcSupportdManager()->SetConfigurationData(std::move(data));
 }
 
 void DeviceWilcoDtcConfigurationHandler::Shutdown() {
diff --git a/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc b/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc
index 63f4005..5edcf48 100644
--- a/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc
+++ b/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "ash/public/cpp/ash_switches.h"
 #include "ash/shell.h"
 #include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
@@ -49,6 +50,11 @@
     return CreateBrowser(profile);
   }
 
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    LoginPolicyTestBase::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ForceMaximizeOnFirstRunTest);
 };
diff --git a/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc b/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc
index 8417015..916dd16 100644
--- a/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc
+++ b/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc
@@ -5,6 +5,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/public/cpp/ash_switches.h"
 #include "base/macros.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -35,6 +36,7 @@
 
   // LoginPolicyTestBase:
   void GetMandatoryPoliciesValue(base::DictionaryValue* policy) const override;
+  void SetUpCommandLine(base::CommandLine* command_line) override;
 
   void LogInAndVerifyStartUpURLs();
 
@@ -55,6 +57,12 @@
   policy->Set(key::kRestoreOnStartupURLs, std::move(urls));
 }
 
+void RestoreOnStartupTestChromeOS::SetUpCommandLine(
+    base::CommandLine* command_line) {
+  LoginPolicyTestBase::SetUpCommandLine(command_line);
+  command_line->AppendSwitch(ash::switches::kShowWebUiLogin);
+}
+
 void RestoreOnStartupTestChromeOS::LogInAndVerifyStartUpURLs() {
   LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 107de11..7792926 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/base/locale_util.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/input_method/input_method_syncer.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
@@ -960,10 +961,12 @@
       reason != REASON_PREF_CHANGED) {
     const base::Value* value =
         prefs_->GetDictionary(prefs::kParentAccessCodeConfig);
-    if (value && prefs_->IsManagedPreference(prefs::kParentAccessCodeConfig)) {
+    if (value && prefs_->IsManagedPreference(prefs::kParentAccessCodeConfig) &&
+        user_->IsChild()) {
       user_manager::known_user::SetPref(user_->GetAccountId(),
                                         prefs::kKnownUserParentAccessCodeConfig,
                                         value->Clone());
+      parent_access::ParentAccessService::Get().LoadConfigForUser(user_);
     } else {
       user_manager::known_user::RemovePref(
           user_->GetAccountId(), prefs::kKnownUserParentAccessCodeConfig);
diff --git a/chrome/browser/chromeos/system/device_disabling_browsertest.cc b/chrome/browser/chromeos/system/device_disabling_browsertest.cc
index ef2a4db..436fd88b 100644
--- a/chrome/browser/chromeos/system/device_disabling_browsertest.cc
+++ b/chrome/browser/chromeos/system/device_disabling_browsertest.cc
@@ -21,6 +21,8 @@
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
@@ -49,8 +51,9 @@
   WizardController* const wizard_controller =
       WizardController::default_controller();
   EXPECT_TRUE(wizard_controller);
-  return wizard_controller && wizard_controller->current_screen() ==
-         wizard_controller->GetScreen(OobeScreen::SCREEN_DEVICE_DISABLED);
+  return wizard_controller &&
+         wizard_controller->current_screen() ==
+             wizard_controller->GetScreen(DeviceDisabledScreenView::kScreenId);
 }
 
 }  // namespace
@@ -172,7 +175,7 @@
   WizardController* wizard_controller = WizardController::default_controller();
   ASSERT_TRUE(wizard_controller);
   wizard_controller->SkipToLoginForTesting(LoginScreenContext());
-  OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  OobeScreenWaiter(GaiaView::kScreenId).Wait();
 
   // Mark the device as disabled and wait until cros settings update.
   MarkDisabledAndWaitForPolicyFetch();
@@ -196,7 +199,7 @@
 
   // Verify that the login screen was not shown and the device disabled screen
   // is still being shown instead.
-  EXPECT_EQ(OobeScreen::SCREEN_DEVICE_DISABLED.name,
+  EXPECT_EQ(DeviceDisabledScreenView::kScreenId.name,
             GetCurrentScreenName(web_contents));
 
   // Disconnect from the fake Ethernet network.
@@ -219,7 +222,7 @@
 
   // Verify that the offline error screen was not shown and the device disabled
   // screen is still being shown instead.
-  EXPECT_EQ(OobeScreen::SCREEN_DEVICE_DISABLED.name,
+  EXPECT_EQ(DeviceDisabledScreenView::kScreenId.name,
             GetCurrentScreenName(web_contents));
 }
 
diff --git a/chrome/browser/chromeos/system/device_disabling_manager_default_delegate.cc b/chrome/browser/chromeos/system/device_disabling_manager_default_delegate.cc
index a4b3be86..0e733ac 100644
--- a/chrome/browser/chromeos/system/device_disabling_manager_default_delegate.cc
+++ b/chrome/browser/chromeos/system/device_disabling_manager_default_delegate.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h"
 
 namespace chromeos {
 namespace system {
@@ -20,7 +21,7 @@
 
 void DeviceDisablingManagerDefaultDelegate::ShowDeviceDisabledScreen() {
   LoginDisplayHost::default_host()->StartWizard(
-      OobeScreen::SCREEN_DEVICE_DISABLED);
+      DeviceDisabledScreenView::kScreenId);
 }
 
 }  // namespace system
diff --git a/chrome/browser/chromeos/diagnosticsd/OWNERS b/chrome/browser/chromeos/wilco_dtc_supportd/OWNERS
similarity index 100%
rename from chrome/browser/chromeos/diagnosticsd/OWNERS
rename to chrome/browser/chromeos/wilco_dtc_supportd/OWNERS
diff --git a/chrome/browser/chromeos/diagnosticsd/mojo_utils.cc b/chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.cc
similarity index 96%
rename from chrome/browser/chromeos/diagnosticsd/mojo_utils.cc
rename to chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.cc
index 6407313..503acc4a 100644
--- a/chrome/browser/chromeos/diagnosticsd/mojo_utils.cc
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.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/chromeos/diagnosticsd/mojo_utils.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h"
 
 #include <cstdint>
 #include <cstring>
diff --git a/chrome/browser/chromeos/diagnosticsd/mojo_utils.h b/chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h
similarity index 86%
rename from chrome/browser/chromeos/diagnosticsd/mojo_utils.h
rename to chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h
index 27ce5b7..6f6c1b6 100644
--- a/chrome/browser/chromeos/diagnosticsd/mojo_utils.h
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_MOJO_UTILS_H_
-#define CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_MOJO_UTILS_H_
+#ifndef CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_MOJO_UTILS_H_
+#define CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_MOJO_UTILS_H_
 
 #include <memory>
 #include <string>
@@ -37,4 +37,4 @@
 
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_MOJO_UTILS_H_
+#endif  // CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_MOJO_UTILS_H_
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.cc b/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.cc
new file mode 100644
index 0000000..a82ff1b
--- /dev/null
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.cc
@@ -0,0 +1,215 @@
+// 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/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h"
+
+#include <unistd.h>
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_wilco_dtc_supportd_client.h"
+#include "chromeos/dbus/wilco_dtc_supportd_client.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace chromeos {
+
+namespace {
+
+// Testing implementation of the WilcoDtcSupportdServiceFactory Mojo service
+// that allows to stub out the GetService Mojo method and tie it with the
+// testing implementation instead.
+class TestingMojoWilcoDtcSupportdServiceFactory final
+    : public wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactory {
+ public:
+  // |get_service_handler_callback| is the callback that will be run when
+  // GetService() is called.
+  explicit TestingMojoWilcoDtcSupportdServiceFactory(
+      base::RepeatingCallback<void(
+          wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest
+              mojo_wilco_dtc_supportd_service_request,
+          wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr
+              mojo_wilco_dtc_supportd_client)> get_service_handler_callback)
+      : get_service_handler_callback_(std::move(get_service_handler_callback)) {
+  }
+
+  // Completes the Mojo binding of |this| to the given Mojo interface request.
+  // This method allows to redirect to |this| the calls on the
+  // WilcoDtcSupportdServiceFactory interface that are made by the
+  // WilcoDtcSupportdBridge.
+  void Bind(wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactoryRequest
+                mojo_wilco_dtc_supportd_service_factory_request) {
+    // First close the Mojo binding in case it was previously completed, to
+    // allow calling this method multiple times.
+    self_binding_.Close();
+    self_binding_.Bind(
+        std::move(mojo_wilco_dtc_supportd_service_factory_request));
+  }
+
+  // WilcoDtcSupportdServiceFactory overrides:
+
+  void GetService(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest service,
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr client,
+      GetServiceCallback callback) override {
+    DCHECK(service);
+    DCHECK(client);
+    // Redirect to |get_service_handler_callback_| to let
+    // TestingWilcoDtcSupportdBridgeWrapper capture |client| (which points to
+    // the production implementation in WilcoDtcSupportdBridge) and fulfill
+    // |service| (to make it point to the stub implementation of the
+    // WilcoDtcSupportdService Mojo service that was passed to
+    // TestingWilcoDtcSupportdBridgeWrapper).
+    get_service_handler_callback_.Run(std::move(service), std::move(client));
+    std::move(callback).Run();
+  }
+
+ private:
+  // Mojo binding that binds |this| as an implementation of the
+  // WilcoDtcSupportdClient Mojo interface.
+  mojo::Binding<wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactory>
+      self_binding_{this};
+  // The callback to be run when GetService() is called.
+  base::RepeatingCallback<void(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest
+          mojo_wilco_dtc_supportd_service_request,
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr
+          mojo_wilco_dtc_supportd_client)>
+      get_service_handler_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingMojoWilcoDtcSupportdServiceFactory);
+};
+
+// Testing implementation of the WilcoDtcSupportdBridge delegate that stubs out
+// the process of generating the Mojo invitation and tie it with
+// TestingMojoWilcoDtcSupportdServiceFactory instead.
+class TestingWilcoDtcSupportdBridgeWrapperDelegate final
+    : public WilcoDtcSupportdBridge::Delegate {
+ public:
+  explicit TestingWilcoDtcSupportdBridgeWrapperDelegate(
+      std::unique_ptr<TestingMojoWilcoDtcSupportdServiceFactory>
+          mojo_wilco_dtc_supportd_service_factory)
+      : mojo_wilco_dtc_supportd_service_factory_(
+            std::move(mojo_wilco_dtc_supportd_service_factory)) {}
+
+  // WilcoDtcSupportdBridge::Delegate overrides:
+
+  void CreateWilcoDtcSupportdServiceFactoryMojoInvitation(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactoryPtr*
+          wilco_dtc_supportd_service_factory_mojo_ptr,
+      base::ScopedFD* remote_endpoint_fd) override {
+    // Bind the Mojo pointer passed to the bridge with the
+    // TestingMojoWilcoDtcSupportdServiceFactory implementation.
+    mojo_wilco_dtc_supportd_service_factory_->Bind(
+        mojo::MakeRequest(wilco_dtc_supportd_service_factory_mojo_ptr));
+
+    // Return a fake file descriptor - its value is not used in the unit test
+    // environment for anything except comparing with zero.
+    remote_endpoint_fd->reset(HANDLE_EINTR(dup(STDIN_FILENO)));
+    DCHECK(remote_endpoint_fd->is_valid());
+  }
+
+ private:
+  std::unique_ptr<TestingMojoWilcoDtcSupportdServiceFactory>
+      mojo_wilco_dtc_supportd_service_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingWilcoDtcSupportdBridgeWrapperDelegate);
+};
+
+FakeWilcoDtcSupportdClient* GetFakeDbusWilcoDtcSupportdClient() {
+  DCHECK(DBusThreadManager::Get()->IsUsingFakes());
+  WilcoDtcSupportdClient* const wilco_dtc_supportd_client =
+      DBusThreadManager::Get()->GetWilcoDtcSupportdClient();
+  DCHECK(wilco_dtc_supportd_client);
+  return static_cast<FakeWilcoDtcSupportdClient*>(wilco_dtc_supportd_client);
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<TestingWilcoDtcSupportdBridgeWrapper>
+TestingWilcoDtcSupportdBridgeWrapper::Create(
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdService*
+        mojo_wilco_dtc_supportd_service,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    std::unique_ptr<WilcoDtcSupportdBridge>* bridge) {
+  return base::WrapUnique(new TestingWilcoDtcSupportdBridgeWrapper(
+      mojo_wilco_dtc_supportd_service, std::move(url_loader_factory), bridge));
+}
+
+TestingWilcoDtcSupportdBridgeWrapper::~TestingWilcoDtcSupportdBridgeWrapper() =
+    default;
+
+void TestingWilcoDtcSupportdBridgeWrapper::EstablishFakeMojoConnection() {
+  DCHECK(!mojo_wilco_dtc_supportd_client_);
+  DCHECK(!mojo_get_service_handler_);
+
+  // Set up the callback that will handle the GetService Mojo method called
+  // during the bootstrap.
+  base::RunLoop run_loop;
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest
+      intercepted_mojo_wilco_dtc_supportd_service_request;
+  mojo_get_service_handler_ = base::BindLambdaForTesting(
+      [&run_loop, &intercepted_mojo_wilco_dtc_supportd_service_request](
+          wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest
+              mojo_wilco_dtc_supportd_service_request) {
+        intercepted_mojo_wilco_dtc_supportd_service_request =
+            std::move(mojo_wilco_dtc_supportd_service_request);
+        run_loop.Quit();
+      });
+
+  // Trigger the Mojo bootstrapping process by unblocking the corresponding
+  // D-Bus operations.
+  FakeWilcoDtcSupportdClient* const fake_dbus_wilco_dtc_supportd_client =
+      GetFakeDbusWilcoDtcSupportdClient();
+  fake_dbus_wilco_dtc_supportd_client->SetWaitForServiceToBeAvailableResult(
+      true);
+  fake_dbus_wilco_dtc_supportd_client->SetBootstrapMojoConnectionResult(true);
+
+  // Wait till the GetService Mojo method call completes.
+  run_loop.Run();
+  DCHECK(intercepted_mojo_wilco_dtc_supportd_service_request);
+  DCHECK(mojo_wilco_dtc_supportd_client_);
+
+  // First close the Mojo binding in case it was previously completed, to allow
+  // calling this method multiple times.
+  mojo_wilco_dtc_supportd_service_binding_.Close();
+  mojo_wilco_dtc_supportd_service_binding_.Bind(
+      std::move(intercepted_mojo_wilco_dtc_supportd_service_request));
+}
+
+void TestingWilcoDtcSupportdBridgeWrapper::HandleMojoGetService(
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest
+        mojo_wilco_dtc_supportd_service_request,
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr
+        mojo_wilco_dtc_supportd_client) {
+  std::move(mojo_get_service_handler_)
+      .Run(std::move(mojo_wilco_dtc_supportd_service_request));
+  mojo_wilco_dtc_supportd_client_ = std::move(mojo_wilco_dtc_supportd_client);
+}
+
+TestingWilcoDtcSupportdBridgeWrapper::TestingWilcoDtcSupportdBridgeWrapper(
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdService*
+        mojo_wilco_dtc_supportd_service,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    std::unique_ptr<WilcoDtcSupportdBridge>* bridge)
+    : mojo_wilco_dtc_supportd_service_binding_(
+          mojo_wilco_dtc_supportd_service) {
+  *bridge = std::make_unique<WilcoDtcSupportdBridge>(
+      std::make_unique<TestingWilcoDtcSupportdBridgeWrapperDelegate>(
+          std::make_unique<TestingMojoWilcoDtcSupportdServiceFactory>(
+              base::BindRepeating(
+                  &TestingWilcoDtcSupportdBridgeWrapper::HandleMojoGetService,
+                  base::Unretained(this)))),
+      url_loader_factory);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h b/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h
new file mode 100644
index 0000000..aa779f0
--- /dev/null
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h
@@ -0,0 +1,92 @@
+// 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_CHROMEOS_WILCO_DTC_SUPPORTD_TESTING_WILCO_DTC_SUPPORTD_BRIDGE_WRAPPER_H_
+#define CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_TESTING_WILCO_DTC_SUPPORTD_BRIDGE_WRAPPER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h"
+#include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+namespace chromeos {
+
+// Manages a fake instance of WilcoDtcSupportdBridge for unit tests. Mocks out
+// the Mojo communication and provides tools for simulating and handling Mojo
+// requests.
+class TestingWilcoDtcSupportdBridgeWrapper final {
+ public:
+  // |mojo_wilco_dtc_supportd_service| is an unowned pointer that should be a
+  // stub implementation of the WilcoDtcSupportdService Mojo service (which in
+  // production is implemented by the wilco_dtc_supportd daemon). |bridge| is an
+  // unowned bridge instance that holds the stub wilco_dtc_supportd bridge
+  // instance created by the TestingWilcoDtcSupportdBridgeWrapper.
+  static std::unique_ptr<TestingWilcoDtcSupportdBridgeWrapper> Create(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdService*
+          mojo_wilco_dtc_supportd_service,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loade_factory,
+      std::unique_ptr<WilcoDtcSupportdBridge>* bridge);
+
+  ~TestingWilcoDtcSupportdBridgeWrapper();
+
+  // Simulates bootstrapping the Mojo communication between the
+  // wilco_dtc_supportd daemon and the browser.
+  void EstablishFakeMojoConnection();
+
+  // Returns a pointer that allows to simulate Mojo calls to the
+  // WilcoDtcSupportdClient mojo service (which in production is implemented by
+  // the browser and called by the wilco_dtc_supportd daemon).
+  //
+  // Returns null if EstablishFakeMojoConnection() wasn't called yet.
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdClient*
+  mojo_wilco_dtc_supportd_client() {
+    return mojo_wilco_dtc_supportd_client_.get();
+  }
+
+ private:
+  // |mojo_wilco_dtc_supportd_service| is an unowned pointer that should be a
+  // stub implementation of the WilcoDtcSupportdService Mojo service (which in
+  // production is implemented by the wilco_dtc_supportd daemon).
+  TestingWilcoDtcSupportdBridgeWrapper(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdService*
+          mojo_wilco_dtc_supportd_service,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      std::unique_ptr<WilcoDtcSupportdBridge>* bridge);
+
+  // Implements the GetService Mojo method of the WilcoDtcSupportdServiceFactory
+  // interface. Called during the simulated Mojo boostrapping.
+  void HandleMojoGetService(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest
+          mojo_wilco_dtc_supportd_service_request,
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr
+          mojo_wilco_dtc_supportd_client);
+
+  // Mojo binding that binds the WilcoDtcSupportdService implementation (passed
+  // to the constructor) with the other endpoint owned from |bridge_|.
+  mojo::Binding<wilco_dtc_supportd::mojom::WilcoDtcSupportdService>
+      mojo_wilco_dtc_supportd_service_binding_;
+
+  // Mojo pointer that points to the WilcoDtcSupportdClient implementation
+  // (owned by |bridge_|).  Is initialized if the Mojo is bootstrapped by
+  // EstablishFakeMojoConnection().
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr
+      mojo_wilco_dtc_supportd_client_;
+
+  // Temporary callback that allows to deliver the
+  // WilcoDtcSupportdServiceRequest value during the Mojo bootstrapping
+  // simulation by EstablishFakeMojoConnection().
+  base::OnceCallback<void(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest
+          mojo_wilco_dtc_supportd_service_request)>
+      mojo_get_service_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingWilcoDtcSupportdBridgeWrapper);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_TESTING_WILCO_DTC_SUPPORTD_BRIDGE_WRAPPER_H_
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc
new file mode 100644
index 0000000..06dc2788
--- /dev/null
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.cc
@@ -0,0 +1,345 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_piece.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/wilco_dtc_supportd_client.h"
+#include "mojo/public/cpp/bindings/interface_ptr_info.h"
+#include "mojo/public/cpp/platform/platform_channel.h"
+#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
+#include "mojo/public/cpp/platform/platform_handle.h"
+#include "mojo/public/cpp/system/invitation.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "third_party/cros_system_api/dbus/wilco_dtc_supportd/dbus-constants.h"
+
+namespace chromeos {
+
+namespace {
+
+// Interval used between successive connection attempts to the
+// wilco_dtc_supportd. This is a safety measure for avoiding busy loops when the
+// wilco_dtc_supportd is dysfunctional.
+constexpr base::TimeDelta kConnectionAttemptInterval =
+    base::TimeDelta::FromSeconds(1);
+// The maximum number of consecutive connection attempts to the
+// wilco_dtc_supportd before giving up. This is to prevent wasting system
+// resources on hopeless attempts to connect in cases when the
+// wilco_dtc_supportd is dysfunctional.
+constexpr int kMaxConnectionAttemptCount = 10;
+
+WilcoDtcSupportdBridge* g_wilco_dtc_supportd_bridge_instance = nullptr;
+
+// Real implementation of the WilcoDtcSupportdBridge delegate.
+class WilcoDtcSupportdBridgeDelegateImpl final
+    : public WilcoDtcSupportdBridge::Delegate {
+ public:
+  WilcoDtcSupportdBridgeDelegateImpl();
+  ~WilcoDtcSupportdBridgeDelegateImpl() override;
+
+  // Delegate overrides:
+  void CreateWilcoDtcSupportdServiceFactoryMojoInvitation(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactoryPtr*
+          wilco_dtc_supportd_service_factory_mojo_ptr,
+      base::ScopedFD* remote_endpoint_fd) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdBridgeDelegateImpl);
+};
+
+WilcoDtcSupportdBridgeDelegateImpl::WilcoDtcSupportdBridgeDelegateImpl() =
+    default;
+
+WilcoDtcSupportdBridgeDelegateImpl::~WilcoDtcSupportdBridgeDelegateImpl() =
+    default;
+
+void WilcoDtcSupportdBridgeDelegateImpl::
+    CreateWilcoDtcSupportdServiceFactoryMojoInvitation(
+        wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactoryPtr*
+            wilco_dtc_supportd_service_factory_mojo_ptr,
+        base::ScopedFD* remote_endpoint_fd) {
+  mojo::OutgoingInvitation invitation;
+  mojo::PlatformChannel channel;
+  mojo::ScopedMessagePipeHandle server_pipe = invitation.AttachMessagePipe(
+      diagnostics::kWilcoDtcSupportdMojoConnectionChannelToken);
+  mojo::OutgoingInvitation::Send(std::move(invitation),
+                                 base::kNullProcessHandle,
+                                 channel.TakeLocalEndpoint());
+  wilco_dtc_supportd_service_factory_mojo_ptr->Bind(
+      mojo::InterfacePtrInfo<
+          wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactory>(
+          std::move(server_pipe), 0 /* version */));
+  *remote_endpoint_fd =
+      channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD();
+}
+
+}  // namespace
+
+WilcoDtcSupportdBridge::Delegate::~Delegate() = default;
+
+// static
+WilcoDtcSupportdBridge* WilcoDtcSupportdBridge::Get() {
+  return g_wilco_dtc_supportd_bridge_instance;
+}
+
+// static
+base::TimeDelta
+WilcoDtcSupportdBridge::connection_attempt_interval_for_testing() {
+  return kConnectionAttemptInterval;
+}
+
+// static
+int WilcoDtcSupportdBridge::max_connection_attempt_count_for_testing() {
+  return kMaxConnectionAttemptCount;
+}
+
+WilcoDtcSupportdBridge::WilcoDtcSupportdBridge(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : WilcoDtcSupportdBridge(
+          std::make_unique<WilcoDtcSupportdBridgeDelegateImpl>(),
+          std::move(url_loader_factory)) {}
+
+WilcoDtcSupportdBridge::WilcoDtcSupportdBridge(
+    std::unique_ptr<Delegate> delegate,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : delegate_(std::move(delegate)),
+      web_request_service_(std::move(url_loader_factory)) {
+  DCHECK(delegate_);
+  DCHECK(!g_wilco_dtc_supportd_bridge_instance);
+  g_wilco_dtc_supportd_bridge_instance = this;
+  WaitForDBusService();
+}
+
+WilcoDtcSupportdBridge::~WilcoDtcSupportdBridge() {
+  DCHECK_EQ(g_wilco_dtc_supportd_bridge_instance, this);
+  g_wilco_dtc_supportd_bridge_instance = nullptr;
+}
+
+void WilcoDtcSupportdBridge::SetConfigurationData(const std::string* data) {
+  configuration_data_ = data;
+}
+
+const std::string& WilcoDtcSupportdBridge::GetConfigurationDataForTesting() {
+  return configuration_data_ ? *configuration_data_ : base::EmptyString();
+}
+
+void WilcoDtcSupportdBridge::WaitForDBusService() {
+  if (connection_attempt_ >= kMaxConnectionAttemptCount) {
+    DLOG(WARNING)
+        << "Stopping attempts to connect to wilco_dtc_supportd - too many "
+           "unsuccessful attempts in a row";
+    return;
+  }
+  ++connection_attempt_;
+
+  // Cancel any tasks previously created from WaitForDBusService() or
+  // ScheduleWaitingForDBusService().
+  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
+
+  DBusThreadManager::Get()
+      ->GetWilcoDtcSupportdClient()
+      ->WaitForServiceToBeAvailable(
+          base::BindOnce(&WilcoDtcSupportdBridge::OnWaitedForDBusService,
+                         dbus_waiting_weak_ptr_factory_.GetWeakPtr()));
+}
+
+void WilcoDtcSupportdBridge::ScheduleWaitingForDBusService() {
+  // Cancel any tasks previously created from WaitForDBusService() or
+  // ScheduleWaitingForDBusService().
+  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&WilcoDtcSupportdBridge::WaitForDBusService,
+                     dbus_waiting_weak_ptr_factory_.GetWeakPtr()),
+      kConnectionAttemptInterval);
+}
+
+void WilcoDtcSupportdBridge::OnWaitedForDBusService(bool service_is_available) {
+  if (!service_is_available) {
+    DLOG(WARNING) << "The wilco_dtc_supportd D-Bus service is unavailable";
+    return;
+  }
+
+  // Cancel any tasks previously created from WaitForDBusService() or
+  // ScheduleWaitingForDBusService().
+  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
+
+  BootstrapMojoConnection();
+}
+
+void WilcoDtcSupportdBridge::BootstrapMojoConnection() {
+  DCHECK(!wilco_dtc_supportd_service_factory_mojo_ptr_);
+
+  // Create a Mojo message pipe and attach
+  // |wilco_dtc_supportd_service_factory_mojo_ptr_| to its local endpoint.
+  base::ScopedFD remote_endpoint_fd;
+  delegate_->CreateWilcoDtcSupportdServiceFactoryMojoInvitation(
+      &wilco_dtc_supportd_service_factory_mojo_ptr_, &remote_endpoint_fd);
+  DCHECK(wilco_dtc_supportd_service_factory_mojo_ptr_);
+  DCHECK(remote_endpoint_fd.is_valid());
+  wilco_dtc_supportd_service_factory_mojo_ptr_.set_connection_error_handler(
+      base::BindOnce(&WilcoDtcSupportdBridge::OnMojoConnectionError,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  // Queue a call that would establish full-duplex Mojo communication with the
+  // wilco_dtc_supportd daemon by sending an interface pointer to the self
+  // instance.
+  mojo_self_binding_.Close();
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr self_proxy;
+  mojo_self_binding_.Bind(mojo::MakeRequest(&self_proxy));
+  wilco_dtc_supportd_service_factory_mojo_ptr_->GetService(
+      mojo::MakeRequest(&wilco_dtc_supportd_service_mojo_ptr_),
+      std::move(self_proxy),
+      base::BindOnce(&WilcoDtcSupportdBridge::OnMojoGetServiceCompleted,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  // Send the file descriptor with the Mojo message pipe's remote endpoint to
+  // the wilco_dtc_supportd daemon via the D-Bus.
+  DBusThreadManager::Get()
+      ->GetWilcoDtcSupportdClient()
+      ->BootstrapMojoConnection(
+          std::move(remote_endpoint_fd),
+          base::BindOnce(&WilcoDtcSupportdBridge::OnBootstrappedMojoConnection,
+                         weak_ptr_factory_.GetWeakPtr()));
+}
+
+void WilcoDtcSupportdBridge::OnBootstrappedMojoConnection(bool success) {
+  if (success)
+    return;
+  DLOG(ERROR) << "Failed to establish Mojo connection to wilco_dtc_supportd";
+  wilco_dtc_supportd_service_factory_mojo_ptr_.reset();
+  wilco_dtc_supportd_service_mojo_ptr_.reset();
+  ScheduleWaitingForDBusService();
+}
+
+void WilcoDtcSupportdBridge::OnMojoGetServiceCompleted() {
+  DCHECK(wilco_dtc_supportd_service_mojo_ptr_);
+  DVLOG(0) << "Established Mojo communication with wilco_dtc_supportd";
+  // Reset the current connection attempt counter, since a successful
+  // initialization of Mojo communication has completed.
+  connection_attempt_ = 0;
+}
+
+void WilcoDtcSupportdBridge::OnMojoConnectionError() {
+  DLOG(WARNING)
+      << "Mojo connection to the wilco_dtc_supportd daemon got shut down";
+  wilco_dtc_supportd_service_factory_mojo_ptr_.reset();
+  wilco_dtc_supportd_service_mojo_ptr_.reset();
+  ScheduleWaitingForDBusService();
+}
+
+void WilcoDtcSupportdBridge::PerformWebRequest(
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod http_method,
+    mojo::ScopedHandle url,
+    std::vector<mojo::ScopedHandle> headers,
+    mojo::ScopedHandle request_body,
+    PerformWebRequestCallback callback) {
+  // Extract a GURL value from a ScopedHandle.
+  GURL gurl;
+  if (url.is_valid()) {
+    std::unique_ptr<base::SharedMemory> shared_memory;
+    gurl = GURL(GetStringPieceFromMojoHandle(std::move(url), &shared_memory));
+    if (!shared_memory) {
+      LOG(ERROR) << "Failed to read data from mojo handle";
+      std::move(callback).Run(
+          wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+              kNetworkError,
+          0 /* http_status */, mojo::ScopedHandle() /* response_body */);
+      return;
+    }
+  }
+
+  // Extract headers from ScopedHandle's.
+  std::vector<base::StringPiece> header_contents;
+  std::vector<std::unique_ptr<base::SharedMemory>> shared_memories;
+  for (auto& header : headers) {
+    if (!header.is_valid()) {
+      header_contents.push_back("");
+      continue;
+    }
+    shared_memories.push_back(nullptr);
+    header_contents.push_back(GetStringPieceFromMojoHandle(
+        std::move(header), &shared_memories.back()));
+    if (!shared_memories.back()) {
+      LOG(ERROR) << "Failed to read data from mojo handle";
+      std::move(callback).Run(
+          wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+              kNetworkError,
+          0 /* http_status */, mojo::ScopedHandle() /* response_body */);
+      return;
+    }
+  }
+
+  // Extract a string value from a ScopedHandle.
+  std::string request_body_content;
+  if (request_body.is_valid()) {
+    std::unique_ptr<base::SharedMemory> shared_memory;
+    request_body_content = std::string(
+        GetStringPieceFromMojoHandle(std::move(request_body), &shared_memory));
+    if (!shared_memory) {
+      LOG(ERROR) << "Failed to read data from mojo handle";
+      std::move(callback).Run(
+          wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+              kNetworkError,
+          0 /* http_status */, mojo::ScopedHandle() /* response_body */);
+      return;
+    }
+  }
+
+  web_request_service_.PerformRequest(
+      http_method, std::move(gurl), std::move(header_contents),
+      std::move(request_body_content), std::move(callback));
+}
+
+void WilcoDtcSupportdBridge::GetConfigurationData(
+    GetConfigurationDataCallback callback) {
+  std::move(callback).Run(configuration_data_ ? *configuration_data_
+                                              : std::string());
+}
+
+void WilcoDtcSupportdBridge::SendWilcoDtcMessageToUi(
+    mojo::ScopedHandle json_message,
+    SendWilcoDtcMessageToUiCallback callback) {
+  // Extract the string value of the received message.
+  DCHECK(json_message);
+  std::unique_ptr<base::SharedMemory> json_message_shared_memory;
+  base::StringPiece json_message_string = GetStringPieceFromMojoHandle(
+      std::move(json_message), &json_message_shared_memory);
+  if (json_message_string.empty()) {
+    LOG(ERROR) << "Failed to read data from mojo handle";
+    std::move(callback).Run(mojo::ScopedHandle() /* response_json_message */);
+    return;
+  }
+
+  DeliverWilcoDtcSupportdUiMessageToExtensions(
+      json_message_string.as_string(),
+      base::BindOnce(
+          [](SendWilcoDtcMessageToUiCallback callback,
+             const std::string& response) {
+            mojo::ScopedHandle response_mojo_handle;
+            if (!response.empty()) {
+              response_mojo_handle =
+                  CreateReadOnlySharedMemoryMojoHandle(response);
+              if (!response_mojo_handle)
+                LOG(ERROR) << "Failed to create mojo handle for string";
+            }
+            std::move(callback).Run(std::move(response_mojo_handle));
+          },
+          std::move(callback)));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h
new file mode 100644
index 0000000..6fa7803
--- /dev/null
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h
@@ -0,0 +1,152 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_BRIDGE_H_
+#define CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_BRIDGE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.h"
+#include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/buffer.h"
+
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
+namespace chromeos {
+
+// Establishes Mojo communication to the wilco_dtc_supportd daemon. The Mojo
+// pipe gets bootstrapped via D-Bus, and the class takes care of waiting until
+// the wilco_dtc_supportd D-Bus service gets started and of repeating the
+// bootstrapping after the daemon gets restarted.
+class WilcoDtcSupportdBridge final
+    : public wilco_dtc_supportd::mojom::WilcoDtcSupportdClient {
+ public:
+  // Delegate class, allowing to stub out unwanted operations in unit tests.
+  class Delegate {
+   public:
+    virtual ~Delegate();
+
+    // Creates a Mojo invitation that requests the remote implementation of the
+    // WilcoDtcSupportdServiceFactory interface.
+    // Returns |wilco_dtc_supportd_service_factory_mojo_ptr| - interface pointer
+    // that points to the remote implementation of the interface,
+    // |remote_endpoint_fd| - file descriptor of the remote endpoint to be sent.
+    virtual void CreateWilcoDtcSupportdServiceFactoryMojoInvitation(
+        wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactoryPtr*
+            wilco_dtc_supportd_service_factory_mojo_ptr,
+        base::ScopedFD* remote_endpoint_fd) = 0;
+  };
+
+  // Returns the global singleton instance.
+  static WilcoDtcSupportdBridge* Get();
+
+  static base::TimeDelta connection_attempt_interval_for_testing();
+  static int max_connection_attempt_count_for_testing();
+
+  explicit WilcoDtcSupportdBridge(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+  // For use in tests.
+  WilcoDtcSupportdBridge(
+      std::unique_ptr<Delegate> delegate,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+
+  ~WilcoDtcSupportdBridge() override;
+
+  // Sets the Wilco DTC configuration data, passed and owned by the
+  // |WilcoDtcSupportdManager| from the device policy.
+  // The nullptr should be passed to clear it.
+  void SetConfigurationData(const std::string* data);
+  const std::string& GetConfigurationDataForTesting();
+
+  // Mojo proxy to the WilcoDtcSupportdService implementation in the
+  // wilco_dtc_supportd daemon. Returns null when bootstrapping of Mojo
+  // connection hasn't started yet. Note that, however, non-null is already
+  // returned before the bootstrapping fully completes.
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceProxy*
+  wilco_dtc_supportd_service_mojo_proxy() {
+    return wilco_dtc_supportd_service_mojo_ptr_
+               ? wilco_dtc_supportd_service_mojo_ptr_.get()
+               : nullptr;
+  }
+
+ private:
+  // Starts waiting until the wilco_dtc_supportd D-Bus service becomes available
+  // (or until this waiting fails).
+  void WaitForDBusService();
+  // Schedules a postponed execution of WaitForDBusService().
+  void ScheduleWaitingForDBusService();
+  // Called once waiting for the D-Bus service, started by WaitForDBusService(),
+  // finishes.
+  void OnWaitedForDBusService(bool service_is_available);
+  // Triggers Mojo bootstrapping via a D-Bus to the wilco_dtc_supportd daemon.
+  void BootstrapMojoConnection();
+  // Called once the result of the D-Bus call, made from
+  // BootstrapMojoConnection(), arrives.
+  void OnBootstrappedMojoConnection(bool success);
+  // Called once the GetService() Mojo request completes.
+  void OnMojoGetServiceCompleted();
+  // Called when Mojo signals a connection error.
+  void OnMojoConnectionError();
+
+  // wilco_dtc_supportd::mojom::WilcoDtcSupportdClient overrides.
+  void PerformWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod
+          http_method,
+      mojo::ScopedHandle url,
+      std::vector<mojo::ScopedHandle> headers,
+      mojo::ScopedHandle request_body,
+      PerformWebRequestCallback callback) override;
+  void SendWilcoDtcMessageToUi(
+      mojo::ScopedHandle json_message,
+      SendWilcoDtcMessageToUiCallback callback) override;
+  void GetConfigurationData(GetConfigurationDataCallback callback) override;
+
+  std::unique_ptr<Delegate> delegate_;
+
+  // Mojo binding that binds |this| as an implementation of the
+  // WilcoDtcSupportdClient Mojo interface.
+  mojo::Binding<wilco_dtc_supportd::mojom::WilcoDtcSupportdClient>
+      mojo_self_binding_{this};
+
+  // Current consecutive connection attempt number.
+  int connection_attempt_ = 0;
+
+  // Interface pointers to the Mojo services exposed by the wilco_dtc_supportd
+  // daemon.
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactoryPtr
+      wilco_dtc_supportd_service_factory_mojo_ptr_;
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdServicePtr
+      wilco_dtc_supportd_service_mojo_ptr_;
+
+  // The service to perform diagnostics_processor's web requests.
+  WilcoDtcSupportdWebRequestService web_request_service_;
+
+  // The Wilco DTC configuration data blob, passed from the device policy, is
+  // stored and owned by |WilcoDtcSupportdManager|.
+  // nullptr if there is no available configuration data for the Wilco DTC.
+  const std::string* configuration_data_ = nullptr;
+
+  // These weak pointer factories must be the last members:
+
+  // Used for cancelling previously posted tasks that wait for the D-Bus service
+  // availability.
+  base::WeakPtrFactory<WilcoDtcSupportdBridge> dbus_waiting_weak_ptr_factory_{
+      this};
+  base::WeakPtrFactory<WilcoDtcSupportdBridge> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdBridge);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_BRIDGE_H_
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge_unittest.cc
new file mode 100644
index 0000000..ee55f63
--- /dev/null
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge_unittest.cc
@@ -0,0 +1,414 @@
+// 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 <unistd.h>
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/test/scoped_task_environment.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h"
+#include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_wilco_dtc_supportd_client.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace {
+
+class MockMojoWilcoDtcSupportdService
+    : public wilco_dtc_supportd::mojom::WilcoDtcSupportdService {
+ public:
+  MOCK_METHOD2(SendUiMessageToWilcoDtc,
+               void(mojo::ScopedHandle, SendUiMessageToWilcoDtcCallback));
+  MOCK_METHOD0(NotifyConfigurationDataChanged, void());
+};
+
+// Fake implementation of the WilcoDtcSupportdServiceFactory Mojo interface that
+// holds up method calls and allows to complete them afterwards.
+class FakeMojoWilcoDtcSupportdServiceFactory final
+    : public wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactory {
+ public:
+  // WilcoDtcSupportdServiceFactory overrides:
+
+  void GetService(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest service,
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr client,
+      GetServiceCallback callback) override {
+    EXPECT_FALSE(pending_get_service_call_);
+    pending_get_service_call_ = PendingGetServiceCall{
+        std::move(service), std::move(client), std::move(callback)};
+  }
+
+  // Completes the Mojo binding of this instance to the given Mojo interface
+  // request.
+  void Bind(wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactoryRequest
+                request) {
+    // Close the Mojo binding in case it was previously completed, to allow
+    // calling this method multiple times.
+    self_binding_.Close();
+
+    self_binding_.Bind(std::move(request));
+
+    self_binding_.set_connection_error_handler(
+        base::BindOnce(&FakeMojoWilcoDtcSupportdServiceFactory::OnBindingError,
+                       base::Unretained(this)));
+  }
+
+  // Closes the Mojo binding of this instance.
+  void CloseBinding() {
+    self_binding_.Close();
+
+    // Drop the current pending GetService call, if there was any, to allow our
+    // instance to be used for new GetService calls after this instance gets
+    // bound again.
+    pending_get_service_call_.reset();
+  }
+
+  // Whether there's a pending GetService call.
+  bool is_get_service_call_in_flight() const {
+    return pending_get_service_call_.has_value();
+  }
+
+  // Respond to the current pending GetService call.
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr RespondToGetServiceCall(
+      mojo::Binding<wilco_dtc_supportd::mojom::WilcoDtcSupportdService>*
+          mojo_wilco_dtc_supportd_service_binding) {
+    DCHECK(pending_get_service_call_);
+    PendingGetServiceCall pending_call = std::move(*pending_get_service_call_);
+    pending_get_service_call_.reset();
+    mojo_wilco_dtc_supportd_service_binding->Bind(
+        std::move(pending_call.service));
+    std::move(pending_call.callback).Run();
+    return std::move(pending_call.client);
+  }
+
+ private:
+  struct PendingGetServiceCall {
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceRequest service;
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr client;
+    GetServiceCallback callback;
+  };
+
+  void OnBindingError() {
+    // Drop the current pending GetService call, if there was any, to allow our
+    // instance to be used for new GetService calls after this instance gets
+    // bound again.
+    pending_get_service_call_.reset();
+  }
+
+  mojo::Binding<wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactory>
+      self_binding_{this};
+
+  base::Optional<PendingGetServiceCall> pending_get_service_call_;
+};
+
+// Fake implementation of the WilcoDtcSupportdBridge delegate that simulates
+// Mojo operations that are impossible in the unit test.
+class FakeWilcoDtcSupportdBridgeDelegate final
+    : public WilcoDtcSupportdBridge::Delegate {
+ public:
+  explicit FakeWilcoDtcSupportdBridgeDelegate(
+      FakeMojoWilcoDtcSupportdServiceFactory*
+          mojo_wilco_dtc_supportd_service_factory)
+      : mojo_wilco_dtc_supportd_service_factory_(
+            mojo_wilco_dtc_supportd_service_factory) {}
+
+  void CreateWilcoDtcSupportdServiceFactoryMojoInvitation(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceFactoryPtr*
+          wilco_dtc_supportd_service_factory_mojo_ptr,
+      base::ScopedFD* remote_endpoint_fd) override {
+    // Bind the Mojo pointer passed to the bridge with the
+    // FakeMojoWilcoDtcSupportdServiceFactory implementation.
+    mojo_wilco_dtc_supportd_service_factory_->Bind(
+        mojo::MakeRequest(wilco_dtc_supportd_service_factory_mojo_ptr));
+
+    // Return a fake file descriptor - its value is not used in the unit test
+    // environment for anything except comparing with zero.
+    remote_endpoint_fd->reset(HANDLE_EINTR(dup(STDIN_FILENO)));
+    DCHECK(remote_endpoint_fd->is_valid());
+  }
+
+ private:
+  FakeMojoWilcoDtcSupportdServiceFactory* const
+      mojo_wilco_dtc_supportd_service_factory_;
+};
+
+// Tests for the WilcoDtcSupportdBridge class.
+class WilcoDtcSupportdBridgeTest : public testing::Test {
+ protected:
+  WilcoDtcSupportdBridgeTest() {
+    DBusThreadManager::Initialize();
+    CHECK(DBusThreadManager::Get()->IsUsingFakes());
+
+    wilco_dtc_supportd_bridge_ = std::make_unique<WilcoDtcSupportdBridge>(
+        std::make_unique<FakeWilcoDtcSupportdBridgeDelegate>(
+            &mojo_wilco_dtc_supportd_service_factory_),
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            &test_url_loader_factory_));
+  }
+
+  ~WilcoDtcSupportdBridgeTest() override {
+    wilco_dtc_supportd_bridge_.reset();
+    DBusThreadManager::Shutdown();
+  }
+
+  WilcoDtcSupportdBridge* wilco_dtc_supportd_bridge() {
+    return wilco_dtc_supportd_bridge_.get();
+  }
+
+  FakeWilcoDtcSupportdClient* wilco_dtc_supportd_dbus_client() {
+    WilcoDtcSupportdClient* const wilco_dtc_supportd_client =
+        DBusThreadManager::Get()->GetWilcoDtcSupportdClient();
+    DCHECK(wilco_dtc_supportd_client);
+    return static_cast<FakeWilcoDtcSupportdClient*>(wilco_dtc_supportd_client);
+  }
+
+  // Whether there's a pending GetService Mojo call held up by the fake.
+  bool is_mojo_factory_get_service_call_in_flight() const {
+    return mojo_wilco_dtc_supportd_service_factory_
+        .is_get_service_call_in_flight();
+  }
+
+  // Reply to the pending GetService Mojo call held up by the fake.
+  void RespondToMojoFactoryGetServiceCall() {
+    // Close the binding, if it was completed, to allow calling this method
+    // multiple times.
+    mojo_wilco_dtc_supportd_service_binding_.Close();
+
+    mojo_wilco_dtc_supportd_client_ =
+        mojo_wilco_dtc_supportd_service_factory_.RespondToGetServiceCall(
+            &mojo_wilco_dtc_supportd_service_binding_);
+  }
+
+  // Simulates Mojo connection error.
+  void AbortMojoConnection() {
+    mojo_wilco_dtc_supportd_service_factory_.CloseBinding();
+  }
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
+
+ private:
+  FakeMojoWilcoDtcSupportdServiceFactory
+      mojo_wilco_dtc_supportd_service_factory_;
+
+  MockMojoWilcoDtcSupportdService mojo_wilco_dtc_supportd_service_;
+  mojo::Binding<wilco_dtc_supportd::mojom::WilcoDtcSupportdService>
+      mojo_wilco_dtc_supportd_service_binding_{
+          &mojo_wilco_dtc_supportd_service_};
+
+  std::unique_ptr<WilcoDtcSupportdBridge> wilco_dtc_supportd_bridge_;
+
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdClientPtr
+      mojo_wilco_dtc_supportd_client_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+};
+
+}  // namespace
+
+// Test successful Mojo bootstrapping scenario.
+TEST_F(WilcoDtcSupportdBridgeTest, SuccessfulBootstrap) {
+  // Initially the bridge is blocked on the WaitForServiceToBeAvailable call.
+  EXPECT_EQ(1, wilco_dtc_supportd_dbus_client()
+                   ->wait_for_service_to_be_available_in_flight_call_count());
+  EXPECT_FALSE(wilco_dtc_supportd_dbus_client()
+                   ->bootstrap_mojo_connection_in_flight_call_count());
+
+  // Resolve the pending WaitForServiceToBeAvailable call. Verify the bridge
+  // makes the BootstrapMojoConnection D-Bus call.
+  wilco_dtc_supportd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
+  EXPECT_EQ(1, wilco_dtc_supportd_dbus_client()
+                   ->bootstrap_mojo_connection_in_flight_call_count());
+
+  // Resolve the pending BootstrapMojoConnection D-Bus call (but then revert the
+  // fake in order to hold up its subsequent calls). Verify the bridge makes the
+  // GetService Mojo call on the WilcoDtcSupportdServiceFactory interface.
+  wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(true);
+  wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(
+      base::nullopt);
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
+
+  // Resolve the pending GetService Mojo call. Verify the bridge exposes the
+  // obtained WilcoDtcSupportdService Mojo interface pointer.
+  RespondToMojoFactoryGetServiceCall();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_TRUE(
+      wilco_dtc_supportd_bridge()->wilco_dtc_supportd_service_mojo_proxy());
+
+  // Verify that no extra D-Bus or Mojo calls are made.
+  EXPECT_FALSE(wilco_dtc_supportd_dbus_client()
+                   ->bootstrap_mojo_connection_in_flight_call_count());
+  EXPECT_FALSE(is_mojo_factory_get_service_call_in_flight());
+}
+
+// Test the case when the D-Bus service is permanently unavailable - the bridge
+// should be just blocked on a single WaitForServiceToBeAvailable call.
+TEST_F(WilcoDtcSupportdBridgeTest, DBusServiceNotBringingUpError) {
+  EXPECT_EQ(1, wilco_dtc_supportd_dbus_client()
+                   ->wait_for_service_to_be_available_in_flight_call_count());
+
+  // Verify that no extra WaitForServiceToBeAvailable calls are made.
+  scoped_task_environment_.FastForwardBy(
+      WilcoDtcSupportdBridge::connection_attempt_interval_for_testing());
+  EXPECT_EQ(1, wilco_dtc_supportd_dbus_client()
+                   ->wait_for_service_to_be_available_in_flight_call_count());
+}
+
+// Test the case when the BootstrapMojoConnection D-Bus method fails
+// permanently - the bridge should give up making attempts after a few retries.
+TEST_F(WilcoDtcSupportdBridgeTest, DBusBootstrapMojoConnectionError) {
+  wilco_dtc_supportd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
+
+  for (int attempt_number = 0;
+       attempt_number <
+       WilcoDtcSupportdBridge::max_connection_attempt_count_for_testing();
+       ++attempt_number) {
+    // Fail the pending BootstrapMojoConnection call, but then revert the fake
+    // in order to hold up its subsequent calls.
+    EXPECT_EQ(1, wilco_dtc_supportd_dbus_client()
+                     ->bootstrap_mojo_connection_in_flight_call_count());
+    wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(false);
+    wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(
+        base::nullopt);
+    scoped_task_environment_.RunUntilIdle();
+
+    // Verify that no new BootstrapMojoConnection call is made immediately after
+    // the previous one failed.
+    EXPECT_FALSE(wilco_dtc_supportd_dbus_client()
+                     ->bootstrap_mojo_connection_in_flight_call_count());
+
+    // Fast forward the clock till the next attempt should occur.
+    scoped_task_environment_.FastForwardBy(
+        WilcoDtcSupportdBridge::connection_attempt_interval_for_testing());
+  }
+
+  // No new BootstrapMojoConnection calls are made after the retry limit
+  // exceeded.
+  EXPECT_FALSE(wilco_dtc_supportd_dbus_client()
+                   ->bootstrap_mojo_connection_in_flight_call_count());
+}
+
+// Test the case when the Mojo connection gets aborted before the first Mojo
+// call (GetService on the WilcoDtcSupportdServiceFactory interface) completes -
+// the bridge should give up making attempts after a few retries.
+TEST_F(WilcoDtcSupportdBridgeTest, ImmediateMojoDisconnectionError) {
+  wilco_dtc_supportd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
+  wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(true);
+  scoped_task_environment_.RunUntilIdle();
+
+  for (int attempt_number = 0;
+       attempt_number <
+       WilcoDtcSupportdBridge::max_connection_attempt_count_for_testing();
+       ++attempt_number) {
+    // Verify that the bridge made the GetService Mojo call (on the
+    // WilcoDtcSupportdServiceFactory interface). Abort the Mojo binding without
+    // responding to the call. Verify that no new call happens immediately.
+    EXPECT_TRUE(is_mojo_factory_get_service_call_in_flight());
+    AbortMojoConnection();
+    scoped_task_environment_.RunUntilIdle();
+    EXPECT_FALSE(is_mojo_factory_get_service_call_in_flight());
+
+    // Fast forward the clock till the next attempt should occur.
+    scoped_task_environment_.FastForwardBy(
+        WilcoDtcSupportdBridge::connection_attempt_interval_for_testing());
+  }
+
+  // No new connection attempts are made after the retry limit exceeded.
+  EXPECT_FALSE(is_mojo_factory_get_service_call_in_flight());
+}
+
+// Test that the Mojo connection gets bootstrapped again after the previous one
+// got aborted.
+TEST_F(WilcoDtcSupportdBridgeTest, Reestablishing) {
+  // Let the bootstrapping succeed on the first attempt.
+  wilco_dtc_supportd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
+  wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(true);
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
+  RespondToMojoFactoryGetServiceCall();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_TRUE(
+      wilco_dtc_supportd_bridge()->wilco_dtc_supportd_service_mojo_proxy());
+
+  // Abort the Mojo binding. Verify that no new connection attempt happens
+  // immediately.
+  AbortMojoConnection();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_FALSE(
+      wilco_dtc_supportd_bridge()->wilco_dtc_supportd_service_mojo_proxy());
+  EXPECT_FALSE(is_mojo_factory_get_service_call_in_flight());
+
+  // Fast forward the clock till the next connection attempt.
+  scoped_task_environment_.FastForwardBy(
+      WilcoDtcSupportdBridge::connection_attempt_interval_for_testing());
+
+  // Let the bootstrapping succeed again.
+  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
+  RespondToMojoFactoryGetServiceCall();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_TRUE(
+      wilco_dtc_supportd_bridge()->wilco_dtc_supportd_service_mojo_proxy());
+}
+
+// Test that the bridge resets its retry counter after a successful
+// bootstrapping takes place.
+TEST_F(WilcoDtcSupportdBridgeTest, RetryCounterReset) {
+  wilco_dtc_supportd_dbus_client()->SetWaitForServiceToBeAvailableResult(true);
+
+  // Fail the first few connection attempts, leaving only one attempt left.
+  wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(false);
+  scoped_task_environment_.FastForwardBy(
+      WilcoDtcSupportdBridge::connection_attempt_interval_for_testing() *
+      (WilcoDtcSupportdBridge::max_connection_attempt_count_for_testing() - 2));
+
+  // Let the bootstrapping succeed on the new attempt (the last allowed one in
+  // this serie).
+  wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(true);
+  scoped_task_environment_.FastForwardBy(
+      WilcoDtcSupportdBridge::connection_attempt_interval_for_testing());
+  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
+  RespondToMojoFactoryGetServiceCall();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_TRUE(
+      wilco_dtc_supportd_bridge()->wilco_dtc_supportd_service_mojo_proxy());
+
+  // Abort the Mojo binding.
+  AbortMojoConnection();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_FALSE(
+      wilco_dtc_supportd_bridge()->wilco_dtc_supportd_service_mojo_proxy());
+
+  // Fail again a few attempts as before.
+  wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(false);
+  scoped_task_environment_.FastForwardBy(
+      WilcoDtcSupportdBridge::connection_attempt_interval_for_testing() *
+      (WilcoDtcSupportdBridge::max_connection_attempt_count_for_testing() - 1));
+
+  // Let the bootstrapping succeed again as before. Note that this verifies that
+  // the retry attempts made before the previous successful bootstrap were
+  // ignored.
+  wilco_dtc_supportd_dbus_client()->SetBootstrapMojoConnectionResult(true);
+  scoped_task_environment_.FastForwardBy(
+      WilcoDtcSupportdBridge::connection_attempt_interval_for_testing());
+  ASSERT_TRUE(is_mojo_factory_get_service_call_in_flight());
+  RespondToMojoFactoryGetServiceCall();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_TRUE(
+      wilco_dtc_supportd_bridge()->wilco_dtc_supportd_service_mojo_proxy());
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.cc
new file mode 100644
index 0000000..61d3288f
--- /dev/null
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.cc
@@ -0,0 +1,187 @@
+// 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/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h"
+#include "chrome/browser/net/system_network_context_manager.h"
+#include "chromeos/dbus/upstart/upstart_client.h"
+#include "components/session_manager/core/session_manager.h"
+#include "components/session_manager/session_manager_types.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_manager.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+namespace chromeos {
+
+namespace {
+
+WilcoDtcSupportdManager* g_wilco_dtc_supportd_manager_instance = nullptr;
+
+class WilcoDtcSupportdManagerDelegateImpl final
+    : public WilcoDtcSupportdManager::Delegate {
+ public:
+  WilcoDtcSupportdManagerDelegateImpl();
+  ~WilcoDtcSupportdManagerDelegateImpl() override;
+
+  // Delegate overrides:
+  std::unique_ptr<WilcoDtcSupportdBridge> CreateWilcoDtcSupportdBridge()
+      override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdManagerDelegateImpl);
+};
+
+WilcoDtcSupportdManagerDelegateImpl::WilcoDtcSupportdManagerDelegateImpl() =
+    default;
+
+WilcoDtcSupportdManagerDelegateImpl::~WilcoDtcSupportdManagerDelegateImpl() =
+    default;
+
+std::unique_ptr<WilcoDtcSupportdBridge>
+WilcoDtcSupportdManagerDelegateImpl::CreateWilcoDtcSupportdBridge() {
+  return std::make_unique<WilcoDtcSupportdBridge>(
+      g_browser_process->system_network_context_manager()
+          ->GetSharedURLLoaderFactory());
+}
+
+// Returns true if only affiliated users are logged-in.
+bool AreOnlyAffiliatedUsersLoggedIn() {
+  const user_manager::UserList logged_in_users =
+      user_manager::UserManager::Get()->GetLoggedInUsers();
+  for (user_manager::User* user : logged_in_users) {
+    if (!user->IsAffiliated()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+WilcoDtcSupportdManager::Delegate::~Delegate() = default;
+
+// static
+WilcoDtcSupportdManager* WilcoDtcSupportdManager::Get() {
+  return g_wilco_dtc_supportd_manager_instance;
+}
+
+WilcoDtcSupportdManager::WilcoDtcSupportdManager()
+    : WilcoDtcSupportdManager(
+          std::make_unique<WilcoDtcSupportdManagerDelegateImpl>()) {}
+
+WilcoDtcSupportdManager::WilcoDtcSupportdManager(
+    std::unique_ptr<Delegate> delegate)
+    : delegate_(std::move(delegate)),
+      callback_weak_ptr_factory_(this),
+      weak_ptr_factory_(this) {
+  DCHECK(delegate_);
+  DCHECK(!g_wilco_dtc_supportd_manager_instance);
+  g_wilco_dtc_supportd_manager_instance = this;
+  wilco_dtc_allowed_observer_ = CrosSettings::Get()->AddSettingsObserver(
+      kDeviceWilcoDtcAllowed,
+      base::BindRepeating(&WilcoDtcSupportdManager::StartOrStopWilcoDtc,
+                          weak_ptr_factory_.GetWeakPtr()));
+
+  session_manager::SessionManager::Get()->AddObserver(this);
+
+  StartOrStopWilcoDtc();
+}
+
+WilcoDtcSupportdManager::~WilcoDtcSupportdManager() {
+  DCHECK_EQ(g_wilco_dtc_supportd_manager_instance, this);
+  g_wilco_dtc_supportd_manager_instance = nullptr;
+
+  // The destruction may mean that non-affiliated user is logging out.
+  StartOrStopWilcoDtc();
+
+  session_manager::SessionManager::Get()->RemoveObserver(this);
+}
+
+void WilcoDtcSupportdManager::SetConfigurationData(
+    std::unique_ptr<std::string> data) {
+  configuration_data_ = std::move(data);
+
+  if (!wilco_dtc_supportd_bridge_) {
+    VLOG(0) << "Cannot send notification - no bridge to the daemon";
+    return;
+  }
+  wilco_dtc_supportd_bridge_->SetConfigurationData(configuration_data_.get());
+
+  wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceProxy* const
+      wilco_dtc_supportd_mojo_proxy =
+          wilco_dtc_supportd_bridge_->wilco_dtc_supportd_service_mojo_proxy();
+  if (!wilco_dtc_supportd_mojo_proxy) {
+    VLOG(0) << "Cannot send message - Mojo connection to the daemon isn't "
+               "bootstrapped yet";
+    return;
+  }
+  wilco_dtc_supportd_mojo_proxy->NotifyConfigurationDataChanged();
+}
+
+void WilcoDtcSupportdManager::OnSessionStateChanged() {
+  session_manager::SessionState session_state =
+      session_manager::SessionManager::Get()->session_state();
+  // The user is logged-in and the affiliation is set.
+  if (session_state == session_manager::SessionState::ACTIVE)
+    StartOrStopWilcoDtc();
+}
+
+void WilcoDtcSupportdManager::StartOrStopWilcoDtc() {
+  callback_weak_ptr_factory_.InvalidateWeakPtrs();
+  bool wilco_dtc_allowed;
+  // Start wilco DTC support services only if logged-in users are affiliated
+  // and the wilco DTC is allowed by policy.
+  if (CrosSettings::Get()->GetBoolean(kDeviceWilcoDtcAllowed,
+                                      &wilco_dtc_allowed) &&
+      wilco_dtc_allowed && AreOnlyAffiliatedUsersLoggedIn()) {
+    StartWilcoDtc(base::BindOnce(&WilcoDtcSupportdManager::OnStartWilcoDtc,
+                                 callback_weak_ptr_factory_.GetWeakPtr()));
+  } else {
+    StopWilcoDtc(base::BindOnce(&WilcoDtcSupportdManager::OnStopWilcoDtc,
+                                callback_weak_ptr_factory_.GetWeakPtr()));
+  }
+}
+
+void WilcoDtcSupportdManager::StartWilcoDtc(WilcoDtcCallback callback) {
+  VLOG(1) << "Starting wilco DTC";
+  UpstartClient::Get()->StartWilcoDtcService(std::move(callback));
+}
+
+void WilcoDtcSupportdManager::StopWilcoDtc(WilcoDtcCallback callback) {
+  VLOG(1) << "Stopping wilco DTC";
+  UpstartClient::Get()->StopWilcoDtcService(std::move(callback));
+}
+
+void WilcoDtcSupportdManager::OnStartWilcoDtc(bool success) {
+  if (!success) {
+    DLOG(ERROR) << "Failed to start the wilco DTC";
+  } else {
+    VLOG(1) << "Wilco DTC started";
+    if (!wilco_dtc_supportd_bridge_)
+      wilco_dtc_supportd_bridge_ = delegate_->CreateWilcoDtcSupportdBridge();
+    DCHECK(wilco_dtc_supportd_bridge_);
+
+    // Once the bridge is created, notify it about an available configuration
+    // data blob.
+    wilco_dtc_supportd_bridge_->SetConfigurationData(configuration_data_.get());
+  }
+}
+
+void WilcoDtcSupportdManager::OnStopWilcoDtc(bool success) {
+  if (!success) {
+    DLOG(ERROR) << "Failed to stop wilco DTC";
+  } else {
+    VLOG(1) << "Wilco DTC stopped";
+    wilco_dtc_supportd_bridge_.reset();
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h
similarity index 67%
rename from chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.h
rename to chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h
index 49581e93..547dd4d0 100644
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_manager.h
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_MANAGER_H_
-#define CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_MANAGER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_MANAGER_H_
 
 #include <memory>
 #include <string>
@@ -16,38 +16,40 @@
 
 namespace chromeos {
 
-class DiagnosticsdBridge;
+class WilcoDtcSupportdBridge;
 
 // The class controls the lifetime of the wilco DTC (diagnostics and telemetry
 // controller) support services.
 // The wilco DTC is allowed to be running only when:
 // * The wilco DTC is enabled by policy.
 // * An affiliated user/no user is logged-in.
-class DiagnosticsdManager final
+class WilcoDtcSupportdManager final
     : public session_manager::SessionManagerObserver {
  public:
   using WilcoDtcCallback = base::OnceCallback<void(bool)>;
 
-  // Delegate class, allowing to pass a stub diagnosticsd bridge in unit tests.
+  // Delegate class, allowing to pass a stub wilco_dtc_supportd bridge in unit
+  // tests.
   class Delegate {
    public:
     virtual ~Delegate();
-    // Returns a DiagnosticsdBridge instance.
-    virtual std::unique_ptr<DiagnosticsdBridge> CreateDiagnosticsdBridge() = 0;
+    // Returns a WilcoDtcSupportdBridge instance.
+    virtual std::unique_ptr<WilcoDtcSupportdBridge>
+    CreateWilcoDtcSupportdBridge() = 0;
   };
 
   // Returns the global singleton instance.
-  static DiagnosticsdManager* Get();
+  static WilcoDtcSupportdManager* Get();
 
-  DiagnosticsdManager();
+  WilcoDtcSupportdManager();
   // For use in tests.
-  explicit DiagnosticsdManager(std::unique_ptr<Delegate> delegate);
+  explicit WilcoDtcSupportdManager(std::unique_ptr<Delegate> delegate);
 
-  ~DiagnosticsdManager() override;
+  ~WilcoDtcSupportdManager() override;
 
   // Sets the Wilco DTC configuration data, passed by the device policy.
   // The nullptr should be passed to clear it.
-  // Notifies the |diagnosticsd_bridge_| if it is created.
+  // Notifies the |wilco_dtc_supportd_bridge_| if it is created.
   void SetConfigurationData(std::unique_ptr<std::string> data);
 
  private:
@@ -75,19 +77,19 @@
   // The configuration data blob is stored and owned.
   std::unique_ptr<std::string> configuration_data_;
 
-  std::unique_ptr<DiagnosticsdBridge> diagnosticsd_bridge_;
+  std::unique_ptr<WilcoDtcSupportdBridge> wilco_dtc_supportd_bridge_;
 
   // |callback_weak_factory_ptr_| is used only in Stop/StartWilcoDtc to be able
   // to discard the callbacks for the older requests.
-  base::WeakPtrFactory<DiagnosticsdManager> callback_weak_ptr_factory_;
+  base::WeakPtrFactory<WilcoDtcSupportdManager> callback_weak_ptr_factory_;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<DiagnosticsdManager> weak_ptr_factory_;
+  base::WeakPtrFactory<WilcoDtcSupportdManager> weak_ptr_factory_;
 
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdManager);
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdManager);
 };
 
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_MANAGER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_MANAGER_H_
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager_unittest.cc
new file mode 100644
index 0000000..a3b6867
--- /dev/null
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager_unittest.cc
@@ -0,0 +1,245 @@
+// 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/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
+
+#include "base/barrier_closure.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
+#include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
+#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h"
+#include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/upstart/fake_upstart_client.h"
+#include "components/session_manager/core/session_manager.h"
+#include "components/session_manager/session_manager_types.h"
+#include "components/user_manager/scoped_user_manager.h"
+#include "components/user_manager/user_names.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Invoke;
+using testing::StrictMock;
+
+namespace chromeos {
+
+namespace {
+
+// An implementation of Upstart Client that fakes a start/ stop of wilco DTC
+// services on StartWilcoDtcService() / StopWilcoDtcService() calls.
+class TestUpstartClient final : public FakeUpstartClient {
+ public:
+  // FakeUpstartClient overrides:
+  void StartWilcoDtcService(
+      chromeos::VoidDBusMethodCallback callback) override {
+    std::move(callback).Run(true /* success */);
+  }
+
+  void StopWilcoDtcService(chromeos::VoidDBusMethodCallback callback) override {
+    std::move(callback).Run(true /* success */);
+  }
+};
+
+class MockMojoWilcoDtcSupportdService
+    : public wilco_dtc_supportd::mojom::WilcoDtcSupportdService {
+ public:
+  MOCK_METHOD2(SendUiMessageToWilcoDtc,
+               void(mojo::ScopedHandle, SendUiMessageToWilcoDtcCallback));
+
+  MOCK_METHOD0(NotifyConfigurationDataChanged, void());
+};
+
+// An implementation of the WilcoDtcSupportdManager::Delegate that owns the
+// testing instance of the WilcoDtcSupportdBridge.
+class FakeWilcoDtcSupportdManagerDelegate final
+    : public WilcoDtcSupportdManager::Delegate {
+ public:
+  FakeWilcoDtcSupportdManagerDelegate(
+      MockMojoWilcoDtcSupportdService* mojo_wilco_dtc_supportd_service)
+      : mojo_wilco_dtc_supportd_service_(mojo_wilco_dtc_supportd_service) {}
+
+  // WilcoDtcSupportdManager::Delegate overrides:
+  std::unique_ptr<WilcoDtcSupportdBridge> CreateWilcoDtcSupportdBridge()
+      override {
+    std::unique_ptr<WilcoDtcSupportdBridge> wilco_dtc_supportd_bridge;
+    testing_wilco_dtc_supportd_bridge_wrapper_ =
+        TestingWilcoDtcSupportdBridgeWrapper::Create(
+            mojo_wilco_dtc_supportd_service_,
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_),
+            &wilco_dtc_supportd_bridge);
+    DCHECK(wilco_dtc_supportd_bridge);
+    testing_wilco_dtc_supportd_bridge_wrapper_->EstablishFakeMojoConnection();
+    return wilco_dtc_supportd_bridge;
+  }
+
+ private:
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  std::unique_ptr<TestingWilcoDtcSupportdBridgeWrapper>
+      testing_wilco_dtc_supportd_bridge_wrapper_;
+  MockMojoWilcoDtcSupportdService* mojo_wilco_dtc_supportd_service_;
+};
+
+// Tests WilcoDtcSupportdManager class instance.
+class WilcoDtcSupportdManagerTest : public testing::Test {
+ protected:
+  WilcoDtcSupportdManagerTest() {
+    DBusThreadManager::Initialize();
+    upstart_client_ = std::make_unique<TestUpstartClient>();
+  }
+
+  ~WilcoDtcSupportdManagerTest() override { DBusThreadManager::Shutdown(); }
+
+  std::unique_ptr<WilcoDtcSupportdManager::Delegate> CreateDelegate() {
+    return std::make_unique<FakeWilcoDtcSupportdManagerDelegate>(
+        &mojo_wilco_dtc_supportd_service_);
+  }
+
+  void SetWilcoDtcAllowedPolicy(bool wilco_dtc_allowed) {
+    scoped_testing_cros_settings_.device_settings()->SetBoolean(
+        kDeviceWilcoDtcAllowed, wilco_dtc_allowed);
+  }
+
+  void LogInUser(bool is_affiliated) {
+    AccountId account_id =
+        AccountId::FromUserEmail(user_manager::kStubUserEmail);
+    fake_user_manager_->AddUserWithAffiliation(account_id, is_affiliated);
+    fake_user_manager_->LoginUser(account_id);
+    session_manager_.SetSessionState(session_manager::SessionState::ACTIVE);
+  }
+
+  MockMojoWilcoDtcSupportdService* mojo_wilco_dtc_supportd_service() {
+    return &mojo_wilco_dtc_supportd_service_;
+  }
+
+ private:
+  base::MessageLoop message_loop_;
+  ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  std::unique_ptr<TestUpstartClient> upstart_client_;
+  FakeChromeUserManager* fake_user_manager_{new FakeChromeUserManager()};
+  user_manager::ScopedUserManager scoped_user_manager_{
+      base::WrapUnique(fake_user_manager_)};
+  session_manager::SessionManager session_manager_;
+  StrictMock<MockMojoWilcoDtcSupportdService> mojo_wilco_dtc_supportd_service_;
+};
+
+// Test that wilco DTC support services are not started on enterprise enrolled
+// devices with a certain device policy unset.
+TEST_F(WilcoDtcSupportdManagerTest, EnterpriseiWilcoDtcBasic) {
+  WilcoDtcSupportdManager wilco_dtc_supportd_manager(CreateDelegate());
+  EXPECT_FALSE(WilcoDtcSupportdBridge::Get());
+}
+
+// Test that wilco DTC support services are not started if disabled by device
+// policy.
+TEST_F(WilcoDtcSupportdManagerTest, EnterpriseWilcoDtcDisabled) {
+  WilcoDtcSupportdManager wilco_dtc_supportd_manager(CreateDelegate());
+  EXPECT_FALSE(WilcoDtcSupportdBridge::Get());
+
+  SetWilcoDtcAllowedPolicy(false);
+  EXPECT_FALSE(WilcoDtcSupportdBridge::Get());
+}
+
+// Test that wilco DTC support services are started if enabled by policy.
+TEST_F(WilcoDtcSupportdManagerTest, EnterpriseWilcoDtcAllowed) {
+  SetWilcoDtcAllowedPolicy(true);
+  WilcoDtcSupportdManager wilco_dtc_supportd_manager(CreateDelegate());
+  EXPECT_TRUE(WilcoDtcSupportdBridge::Get());
+}
+
+// Test that wilco DTC support services are not started if non-affiliated user
+// is logged-in.
+TEST_F(WilcoDtcSupportdManagerTest, EnterpriseNonAffiliatedUserLoggedIn) {
+  WilcoDtcSupportdManager wilco_dtc_supportd_manager(CreateDelegate());
+  EXPECT_FALSE(WilcoDtcSupportdBridge::Get());
+
+  SetWilcoDtcAllowedPolicy(true);
+  EXPECT_TRUE(WilcoDtcSupportdBridge::Get());
+
+  LogInUser(false);
+  EXPECT_FALSE(WilcoDtcSupportdBridge::Get());
+}
+
+// Test that wilco DTC support services are started if enabled by device policy
+// and affiliated user is logged-in.
+TEST_F(WilcoDtcSupportdManagerTest, EnterpriseAffiliatedUserLoggedIn) {
+  SetWilcoDtcAllowedPolicy(true);
+  WilcoDtcSupportdManager wilco_dtc_supportd_manager(CreateDelegate());
+  EXPECT_TRUE(WilcoDtcSupportdBridge::Get());
+
+  LogInUser(true);
+  EXPECT_TRUE(WilcoDtcSupportdBridge::Get());
+}
+
+// Test that wilco DTC support services are not started if non-affiliated user
+// is logged-in before the construction.
+TEST_F(WilcoDtcSupportdManagerTest, EnterpriseNonAffiliatedUserLoggedInBefore) {
+  SetWilcoDtcAllowedPolicy(true);
+  LogInUser(false);
+  WilcoDtcSupportdManager wilco_dtc_supportd_manager(CreateDelegate());
+
+  EXPECT_FALSE(WilcoDtcSupportdBridge::Get());
+}
+
+// Test that wilco DTC support services are properly notified about the changes
+// of configuration data.
+TEST_F(WilcoDtcSupportdManagerTest, ConfigurationData) {
+  constexpr char kFakeConfigurationData[] =
+      "{\"fake-message\": \"Fake JSON configuration data\"}";
+
+  WilcoDtcSupportdManager wilco_dtc_supportd_manager(CreateDelegate());
+  EXPECT_FALSE(WilcoDtcSupportdBridge::Get());
+
+  SetWilcoDtcAllowedPolicy(true);
+  EXPECT_TRUE(WilcoDtcSupportdBridge::Get());
+  // An empty configuration data by default.
+  EXPECT_TRUE(
+      WilcoDtcSupportdBridge::Get()->GetConfigurationDataForTesting().empty());
+
+  // Set a non-empty configuration data.
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(*mojo_wilco_dtc_supportd_service(),
+                NotifyConfigurationDataChanged())
+        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+
+    wilco_dtc_supportd_manager.SetConfigurationData(
+        std::make_unique<std::string>(kFakeConfigurationData));
+    EXPECT_EQ(kFakeConfigurationData,
+              WilcoDtcSupportdBridge::Get()->GetConfigurationDataForTesting());
+    run_loop.Run();
+  }
+
+  // Restart the bridge.
+  SetWilcoDtcAllowedPolicy(false);
+  EXPECT_FALSE(WilcoDtcSupportdBridge::Get());
+  SetWilcoDtcAllowedPolicy(true);
+  EXPECT_TRUE(WilcoDtcSupportdBridge::Get());
+
+  // The configuration data has not been changed.
+  EXPECT_EQ(kFakeConfigurationData,
+            WilcoDtcSupportdBridge::Get()->GetConfigurationDataForTesting());
+
+  // Clear the configuration data.
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(*mojo_wilco_dtc_supportd_service(),
+                NotifyConfigurationDataChanged())
+        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+    wilco_dtc_supportd_manager.SetConfigurationData(nullptr);
+    EXPECT_TRUE(WilcoDtcSupportdBridge::Get()
+                    ->GetConfigurationDataForTesting()
+                    .empty());
+    run_loop.Run();
+  }
+}
+
+}  // namespace
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc
similarity index 75%
rename from chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.cc
rename to chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc
index bbf008e..58d7dd95 100644
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.cc
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.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/chromeos/diagnosticsd/diagnosticsd_messaging.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h"
 
 #include <algorithm>
 #include <utility>
@@ -18,11 +18,11 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/unguessable_token.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h"
-#include "chrome/browser/chromeos/diagnosticsd/mojo_utils.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h"
 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
+#include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h"
 #include "extensions/browser/api/messaging/channel_endpoint.h"
 #include "extensions/browser/api/messaging/message_service.h"
 #include "extensions/browser/api/messaging/native_message_host.h"
@@ -37,23 +37,23 @@
 namespace chromeos {
 
 // Native application name that is used for passing UI messages between the
-// diagnostics_processor daemon and extensions.
-const char kDiagnosticsdUiMessageHost[] = "com.google.wilco_dtc";
+// wilco_dtc daemon and extensions.
+const char kWilcoDtcSupportdUiMessageHost[] = "com.google.wilco_dtc";
 
 // Error messages sent to the extension:
-const char kDiagnosticsdUiMessageTooBigExtensionsError[] =
+const char kWilcoDtcSupportdUiMessageTooBigExtensionsError[] =
     "Message is too big.";
-const char kDiagnosticsdUiExtraMessagesExtensionsError[] =
+const char kWilcoDtcSupportdUiExtraMessagesExtensionsError[] =
     "At most one message must be sent through the message channel.";
 
-// Maximum allowed size of UI messages passed between the diagnostics_processor
-// daemon and extensions.
-const int kDiagnosticsdUiMessageMaxSize = 1000000;
+// Maximum allowed size of UI messages passed between the wilco_dtc daemon and
+// extensions.
+const int kWilcoDtcSupportdUiMessageMaxSize = 1000000;
 
 namespace {
 
-// List of extension IDs that will receive UI messages from the
-// diagnostics_processor through the extensions native messaging system.
+// List of extension IDs that will receive UI messages from the wilco_dtc
+// through the extensions native messaging system.
 //
 // Note: the list must be kept in sync with the allowed origins list in
 // src/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc.
@@ -63,16 +63,16 @@
 const char* const kAllowedExtensionIds[] = {};
 
 // Extensions native message host implementation that is used when an
-// extension requests a message channel to the diagnostics_processor daemon.
+// extension requests a message channel to the wilco_dtc daemon.
 //
-// The message is transmitted via the diagnosticsd daemon. One instance of this
-// class allows only one message to be sent; at most one message will be sent in
-// the reverse direction: it will contain the daemon's response.
-class DiagnosticsdExtensionOwnedMessageHost final
+// The message is transmitted via the wilco_dtc_supportd daemon. One instance of
+// this class allows only one message to be sent; at most one message will be
+// sent in the reverse direction: it will contain the daemon's response.
+class WilcoDtcSupportdExtensionOwnedMessageHost final
     : public extensions::NativeMessageHost {
  public:
-  DiagnosticsdExtensionOwnedMessageHost() = default;
-  ~DiagnosticsdExtensionOwnedMessageHost() override = default;
+  WilcoDtcSupportdExtensionOwnedMessageHost() = default;
+  ~WilcoDtcSupportdExtensionOwnedMessageHost() override = default;
 
   // extensions::NativeMessageHost:
 
@@ -94,27 +94,28 @@
     if (message_from_extension_received_) {
       // Our implementation doesn't allow sending multiple messages from the
       // extension over the same instance.
-      DisposeSelf(kDiagnosticsdUiExtraMessagesExtensionsError);
+      DisposeSelf(kWilcoDtcSupportdUiExtraMessagesExtensionsError);
       return;
     }
     message_from_extension_received_ = true;
 
-    if (request_string.size() > kDiagnosticsdUiMessageMaxSize) {
-      DisposeSelf(kDiagnosticsdUiMessageTooBigExtensionsError);
+    if (request_string.size() > kWilcoDtcSupportdUiMessageMaxSize) {
+      DisposeSelf(kWilcoDtcSupportdUiMessageTooBigExtensionsError);
       return;
     }
 
-    DiagnosticsdBridge* const diagnosticsd_bridge = DiagnosticsdBridge::Get();
-    if (!diagnosticsd_bridge) {
+    WilcoDtcSupportdBridge* const wilco_dtc_supportd_bridge =
+        WilcoDtcSupportdBridge::Get();
+    if (!wilco_dtc_supportd_bridge) {
       VLOG(0) << "Cannot send message - no bridge to the daemon";
       DisposeSelf(kNotFoundError);
       return;
     }
 
-    diagnosticsd::mojom::DiagnosticsdServiceProxy* const
-        diagnosticsd_mojo_proxy =
-            diagnosticsd_bridge->diagnosticsd_service_mojo_proxy();
-    if (!diagnosticsd_mojo_proxy) {
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdServiceProxy* const
+        wilco_dtc_supportd_mojo_proxy =
+            wilco_dtc_supportd_bridge->wilco_dtc_supportd_service_mojo_proxy();
+    if (!wilco_dtc_supportd_mojo_proxy) {
       VLOG(0) << "Cannot send message - Mojo connection to the daemon isn't "
                  "bootstrapped yet";
       DisposeSelf(kNotFoundError);
@@ -129,9 +130,9 @@
       return;
     }
 
-    diagnosticsd_mojo_proxy->SendUiMessageToDiagnosticsProcessor(
+    wilco_dtc_supportd_mojo_proxy->SendUiMessageToWilcoDtc(
         std::move(json_message_mojo_handle),
-        base::BindOnce(&DiagnosticsdExtensionOwnedMessageHost::
+        base::BindOnce(&WilcoDtcSupportdExtensionOwnedMessageHost::
                            OnResponseReceivedFromDaemon,
                        weak_ptr_factory_.GetWeakPtr()));
   }
@@ -155,9 +156,9 @@
     DCHECK(!is_disposed_);
 
     if (!response_json_message) {
-      // The call to the diagnostics_processor daemon failed or the daemon
-      // provided no response, so just close the extension message channel as
-      // it's intended to be used for one-time messages only.
+      // The call to the wilco_dtc daemon failed or the daemon provided no
+      // response, so just close the extension message channel as it's intended
+      // to be used for one-time messages only.
       VLOG(1) << "Empty response, closing the extension message channel";
       DisposeSelf(std::string() /* error_message */);
       return;
@@ -172,13 +173,13 @@
       return;
     }
 
-    if (response_json_string.size() > kDiagnosticsdUiMessageMaxSize) {
+    if (response_json_string.size() > kWilcoDtcSupportdUiMessageMaxSize) {
       LOG(ERROR) << "The message received from the daemon is too big";
-      DisposeSelf(kDiagnosticsdUiMessageTooBigExtensionsError);
+      DisposeSelf(kWilcoDtcSupportdUiMessageTooBigExtensionsError);
       return;
     }
 
-    if (response_json_string.size() > kDiagnosticsdUiMessageMaxSize) {
+    if (response_json_string.size() > kWilcoDtcSupportdUiMessageMaxSize) {
       LOG(ERROR) << "The message received from the daemon is too big";
       client_->CloseChannel(kHostInputOutputError);
       return;
@@ -200,25 +201,23 @@
   bool is_disposed_ = false;
 
   // Must be the last member.
-  base::WeakPtrFactory<DiagnosticsdExtensionOwnedMessageHost> weak_ptr_factory_{
-      this};
+  base::WeakPtrFactory<WilcoDtcSupportdExtensionOwnedMessageHost>
+      weak_ptr_factory_{this};
 
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdExtensionOwnedMessageHost);
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdExtensionOwnedMessageHost);
 };
 
-// Extensions native message host implementation that is used when the
-// diagnostics_processor daemon sends (via the diagnosticsd daemon) a message to
-// the extension.
+// Extensions native message host implementation that is used when the wilco_dtc
+// daemon sends (via the wilco_dtc_supportd daemon) a message to the extension.
 //
 // A new instance of this class should be created for each instance of the
-// extension(s) that are allowed to receive messages from the
-// diagnostics_processor daemon. Once the extension responds by posting a
-// message back to this message channel, |send_response_callback| will be
-// called.
-class DiagnosticsdDaemonOwnedMessageHost final
+// extension(s) that are allowed to receive messages from the wilco_dtc daemon.
+// Once the extension responds by posting a message back to this message
+// channel, |send_response_callback| will be called.
+class WilcoDtcSupportdDaemonOwnedMessageHost final
     : public extensions::NativeMessageHost {
  public:
-  DiagnosticsdDaemonOwnedMessageHost(
+  WilcoDtcSupportdDaemonOwnedMessageHost(
       const std::string& json_message_to_send,
       base::OnceCallback<void(const std::string& response)>
           send_response_callback)
@@ -227,7 +226,7 @@
     DCHECK(send_response_callback_);
   }
 
-  ~DiagnosticsdDaemonOwnedMessageHost() override {
+  ~WilcoDtcSupportdDaemonOwnedMessageHost() override {
     if (send_response_callback_) {
       // If no response was received from the extension, pass the empty result
       // to the callback to signal the error.
@@ -251,9 +250,9 @@
       // discard these extra messages.
       return;
     }
-    if (request_string.size() > kDiagnosticsdUiMessageMaxSize) {
+    if (request_string.size() > kWilcoDtcSupportdUiMessageMaxSize) {
       std::move(send_response_callback_).Run(std::string() /* response */);
-      client_->CloseChannel(kDiagnosticsdUiMessageTooBigExtensionsError);
+      client_->CloseChannel(kWilcoDtcSupportdUiMessageTooBigExtensionsError);
       return;
     }
     std::move(send_response_callback_).Run(request_string /* response */);
@@ -272,7 +271,7 @@
   // Unowned.
   Client* client_ = nullptr;
 
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdDaemonOwnedMessageHost);
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdDaemonOwnedMessageHost);
 };
 
 // Helper that wraps the specified OnceCallback and encapsulates logic that
@@ -339,14 +338,15 @@
   extensions::MessageService* const message_service =
       extensions::MessageService::Get(profile);
   auto native_message_host =
-      std::make_unique<DiagnosticsdDaemonOwnedMessageHost>(
+      std::make_unique<WilcoDtcSupportdDaemonOwnedMessageHost>(
           json_message, std::move(send_response_callback));
   auto native_message_port = std::make_unique<extensions::NativeMessagePort>(
       message_service->GetChannelDelegate(), port_id,
       std::move(native_message_host));
   message_service->OpenChannelToExtension(
       extensions::ChannelEndpoint(profile), port_id,
-      extensions::MessagingEndpoint::ForNativeApp(kDiagnosticsdUiMessageHost),
+      extensions::MessagingEndpoint::ForNativeApp(
+          kWilcoDtcSupportdUiMessageHost),
       std::move(native_message_port), extension_id, GURL(),
       std::string() /* channel_name */);
 }
@@ -354,15 +354,15 @@
 }  // namespace
 
 std::unique_ptr<extensions::NativeMessageHost>
-CreateExtensionOwnedDiagnosticsdMessageHost() {
-  return std::make_unique<DiagnosticsdExtensionOwnedMessageHost>();
+CreateExtensionOwnedWilcoDtcSupportdMessageHost() {
+  return std::make_unique<WilcoDtcSupportdExtensionOwnedMessageHost>();
 }
 
-void DeliverDiagnosticsdUiMessageToExtensions(
+void DeliverWilcoDtcSupportdUiMessageToExtensions(
     const std::string& json_message,
     base::OnceCallback<void(const std::string& response)>
         send_response_callback) {
-  if (json_message.size() > kDiagnosticsdUiMessageMaxSize) {
+  if (json_message.size() > kWilcoDtcSupportdUiMessageMaxSize) {
     VLOG(1) << "Message received from the daemon is too big";
     return;
   }
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h
similarity index 64%
rename from chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.h
rename to chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h
index c39561e..f3fcc2a 100644
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.h
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_MESSAGING_H_
-#define CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_MESSAGING_H_
+#ifndef CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_MESSAGING_H_
+#define CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_MESSAGING_H_
 
 #include <memory>
 #include <string>
@@ -16,29 +16,29 @@
 
 namespace chromeos {
 
-extern const char kDiagnosticsdUiMessageHost[];
+extern const char kWilcoDtcSupportdUiMessageHost[];
 
-extern const char kDiagnosticsdUiMessageTooBigExtensionsError[];
-extern const char kDiagnosticsdUiExtraMessagesExtensionsError[];
+extern const char kWilcoDtcSupportdUiMessageTooBigExtensionsError[];
+extern const char kWilcoDtcSupportdUiExtraMessagesExtensionsError[];
 
-extern const int kDiagnosticsdUiMessageMaxSize;
+extern const int kWilcoDtcSupportdUiMessageMaxSize;
 
 // Creates an extensions native message host that talks to the
 // diagnostics_processor daemon. This should be used when the communication is
 // initiated by the extension (i.e., not the daemon).
 std::unique_ptr<extensions::NativeMessageHost>
-CreateExtensionOwnedDiagnosticsdMessageHost();
+CreateExtensionOwnedWilcoDtcSupportdMessageHost();
 
 // Delivers the UI message |json_message| from the diagnostics_processor daemon
 // to the extensions that are allowed to receive it. The delivery is done via
 // creating extensions native message hosts. |send_response_callback| will be
 // called with the response from the extension (the first non-empty one in case
 // of multiple extensions providing some responses).
-void DeliverDiagnosticsdUiMessageToExtensions(
+void DeliverWilcoDtcSupportdUiMessageToExtensions(
     const std::string& json_message,
     base::OnceCallback<void(const std::string& response)>
         send_response_callback);
 
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_MESSAGING_H_
+#endif  // CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_MESSAGING_H_
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc
similarity index 73%
rename from chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging_unittest.cc
rename to chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc
index 6b98724..0131863 100644
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging_unittest.cc
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging_unittest.cc
@@ -13,10 +13,10 @@
 #include "base/memory/shared_memory.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.h"
-#include "chrome/browser/chromeos/diagnosticsd/mojo_utils.h"
-#include "chrome/browser/chromeos/diagnosticsd/testing_diagnosticsd_bridge_wrapper.h"
-#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/testing_wilco_dtc_supportd_bridge_wrapper.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h"
+#include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "extensions/browser/api/messaging/native_message_host.h"
 #include "mojo/public/cpp/system/handle.h"
@@ -70,22 +70,22 @@
   return shared_memory_handle;
 }
 
-using SendUiMessageToDiagnosticsProcessorImplCallback =
+using SendUiMessageToWilcoDtcImplCallback =
     base::RepeatingCallback<void(const std::string& response_json_message)>;
 
-class MockMojoDiagnosticsdService
-    : public diagnosticsd::mojom::DiagnosticsdService {
+class MockMojoWilcoDtcSupportdService
+    : public wilco_dtc_supportd::mojom::WilcoDtcSupportdService {
  public:
-  void SendUiMessageToDiagnosticsProcessor(
+  void SendUiMessageToWilcoDtc(
       mojo::ScopedHandle json_message,
-      SendUiMessageToDiagnosticsProcessorCallback callback) override {
+      SendUiMessageToWilcoDtcCallback callback) override {
     // Redirect the call to the Impl method to workaround GMock's issues with
     // move-only types and to make setting test expectations easier (by using
     // std::string's rather than memory handles).
-    SendUiMessageToDiagnosticsProcessorImpl(
+    SendUiMessageToWilcoDtcImpl(
         AssertGetStringFromMojoHandle(std::move(json_message)),
         base::BindRepeating(
-            [](SendUiMessageToDiagnosticsProcessorCallback original_callback,
+            [](SendUiMessageToWilcoDtcCallback original_callback,
                const std::string& response_json_message) {
               std::move(original_callback)
                   .Run(AssertCreateReadOnlySharedMemoryMojoHandle(
@@ -94,22 +94,22 @@
             base::Passed(&callback)));
   }
 
-  MOCK_METHOD2(SendUiMessageToDiagnosticsProcessorImpl,
+  MOCK_METHOD2(SendUiMessageToWilcoDtcImpl,
                void(const std::string& json_message,
-                    SendUiMessageToDiagnosticsProcessorImplCallback callback));
+                    SendUiMessageToWilcoDtcImplCallback callback));
   MOCK_METHOD0(NotifyConfigurationDataChanged, void());
 };
 
 }  // namespace
 
-// Test that the message channel gets closed if the DiagnosticsdBridge
+// Test that the message channel gets closed if the WilcoDtcSupportdBridge
 // instance isn't created.
-TEST(DiagnosticsdMessagingOpenedByExtensionNoBridgeTest, Test) {
+TEST(WilcoDtcSupportdMessagingOpenedByExtensionNoBridgeTest, Test) {
   base::test::ScopedTaskEnvironment scoped_task_environment;
 
   // Create the message host.
   std::unique_ptr<extensions::NativeMessageHost> message_host =
-      CreateExtensionOwnedDiagnosticsdMessageHost();
+      CreateExtensionOwnedWilcoDtcSupportdMessageHost();
   StrictMock<MockNativeMessageHostClient> message_host_client;
 
   // The message host will close the channel during the OnMessage() call at the
@@ -122,53 +122,54 @@
 
 namespace {
 
-// Test fixture that spins up a testing DiagnosticsdBridge instance.
-class DiagnosticsdMessagingOpenedByExtensionTest : public testing::Test {
+// Test fixture that spins up a testing WilcoDtcSupportdBridge instance.
+class WilcoDtcSupportdMessagingOpenedByExtensionTest : public testing::Test {
  protected:
-  DiagnosticsdMessagingOpenedByExtensionTest() {
+  WilcoDtcSupportdMessagingOpenedByExtensionTest() {
     DBusThreadManager::Initialize();
-    testing_diagnosticsd_bridge_wrapper_ =
-        TestingDiagnosticsdBridgeWrapper::Create(
-            &mojo_diagnosticsd_service_,
+    testing_wilco_dtc_supportd_bridge_wrapper_ =
+        TestingWilcoDtcSupportdBridgeWrapper::Create(
+            &mojo_wilco_dtc_supportd_service_,
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_),
-            &diagnosticsd_bridge_);
+            &wilco_dtc_supportd_bridge_);
   }
 
-  ~DiagnosticsdMessagingOpenedByExtensionTest() override {
-    // Make sure |diagnosticsd_bridge_| is destroyed before DBusThreadManager is
-    // shut down, since the DiagnosticsdBridge class uses the latter.
-    diagnosticsd_bridge_.reset();
+  ~WilcoDtcSupportdMessagingOpenedByExtensionTest() override {
+    // Make sure |wilco_dtc_supportd_bridge_| is destroyed before
+    // DBusThreadManager is shut down, since the WilcoDtcSupportdBridge class
+    // uses the latter.
+    wilco_dtc_supportd_bridge_.reset();
     DBusThreadManager::Shutdown();
   }
 
-  MockMojoDiagnosticsdService* mojo_diagnosticsd_service() {
-    return &mojo_diagnosticsd_service_;
+  MockMojoWilcoDtcSupportdService* mojo_wilco_dtc_supportd_service() {
+    return &mojo_wilco_dtc_supportd_service_;
   }
 
-  TestingDiagnosticsdBridgeWrapper* diagnosticsd_bridge_wrapper() {
-    return testing_diagnosticsd_bridge_wrapper_.get();
+  TestingWilcoDtcSupportdBridgeWrapper* wilco_dtc_supportd_bridge_wrapper() {
+    return testing_wilco_dtc_supportd_bridge_wrapper_.get();
   }
 
   void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
 
  private:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
-  StrictMock<MockMojoDiagnosticsdService> mojo_diagnosticsd_service_;
+  StrictMock<MockMojoWilcoDtcSupportdService> mojo_wilco_dtc_supportd_service_;
   network::TestURLLoaderFactory test_url_loader_factory_;
-  std::unique_ptr<TestingDiagnosticsdBridgeWrapper>
-      testing_diagnosticsd_bridge_wrapper_;
-  std::unique_ptr<DiagnosticsdBridge> diagnosticsd_bridge_;
+  std::unique_ptr<TestingWilcoDtcSupportdBridgeWrapper>
+      testing_wilco_dtc_supportd_bridge_wrapper_;
+  std::unique_ptr<WilcoDtcSupportdBridge> wilco_dtc_supportd_bridge_;
 };
 
 }  // namespace
 
 // Test that the message channel gets closed if there's no Mojo connection to
-// the diagnosticsd daemon.
-TEST_F(DiagnosticsdMessagingOpenedByExtensionTest, NoMojoConnection) {
+// the wilco_dtc_supportd daemon.
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionTest, NoMojoConnection) {
   // Create the message host.
   std::unique_ptr<extensions::NativeMessageHost> message_host =
-      CreateExtensionOwnedDiagnosticsdMessageHost();
+      CreateExtensionOwnedWilcoDtcSupportdMessageHost();
   StrictMock<MockNativeMessageHostClient> message_host_client;
   message_host->Start(&message_host_client);
 
@@ -180,14 +181,15 @@
 
 namespace {
 
-// Test fixture that spins up a testing DiagnosticsdBridge instance and creates
-// and owns a single message host, to simplify testing of basic scenarios.
-class DiagnosticsdMessagingOpenedByExtensionSingleHostTest
-    : public DiagnosticsdMessagingOpenedByExtensionTest {
+// Test fixture that spins up a testing WilcoDtcSupportdBridge instance and
+// creates and owns a single message host, to simplify testing of basic
+// scenarios.
+class WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest
+    : public WilcoDtcSupportdMessagingOpenedByExtensionTest {
  protected:
-  DiagnosticsdMessagingOpenedByExtensionSingleHostTest() {
-    diagnosticsd_bridge_wrapper()->EstablishFakeMojoConnection();
-    message_host_ = CreateExtensionOwnedDiagnosticsdMessageHost();
+  WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest() {
+    wilco_dtc_supportd_bridge_wrapper()->EstablishFakeMojoConnection();
+    message_host_ = CreateExtensionOwnedWilcoDtcSupportdMessageHost();
     message_host_->Start(&message_host_client_);
   }
 
@@ -200,10 +202,10 @@
 
   void ExpectMojoSendMessageCall(
       const std::string& expected_message,
-      SendUiMessageToDiagnosticsProcessorImplCallback* captured_callback,
+      SendUiMessageToWilcoDtcImplCallback* captured_callback,
       base::RunLoop* run_loop) {
-    EXPECT_CALL(*mojo_diagnosticsd_service(),
-                SendUiMessageToDiagnosticsProcessorImpl(expected_message, _))
+    EXPECT_CALL(*mojo_wilco_dtc_supportd_service(),
+                SendUiMessageToWilcoDtcImpl(expected_message, _))
         .WillOnce(DoAll(SaveArg<1>(captured_callback),
                         InvokeWithoutArgs(run_loop, &base::RunLoop::Quit)));
   }
@@ -211,10 +213,10 @@
   void ExpectMojoSendMessageCallAndRespond(
       const std::string& expected_message,
       const std::string& response_message_to_pass) {
-    EXPECT_CALL(*mojo_diagnosticsd_service(),
-                SendUiMessageToDiagnosticsProcessorImpl(expected_message, _))
-        .WillOnce(WithArg<1>(Invoke(
-            [=](SendUiMessageToDiagnosticsProcessorImplCallback callback) {
+    EXPECT_CALL(*mojo_wilco_dtc_supportd_service(),
+                SendUiMessageToWilcoDtcImpl(expected_message, _))
+        .WillOnce(WithArg<1>(
+            Invoke([=](SendUiMessageToWilcoDtcImplCallback callback) {
               std::move(callback).Run(response_message_to_pass);
             })));
   }
@@ -245,10 +247,10 @@
 
 // Test the basic successful scenario when the message is successfully delivered
 // from an extension to the daemon and the response is delivered back.
-TEST_F(DiagnosticsdMessagingOpenedByExtensionSingleHostTest,
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest,
        SingleRequestResponse) {
   // Set up the daemon's Mojo service to expect the message from the extension.
-  SendUiMessageToDiagnosticsProcessorImplCallback mojo_method_callback;
+  SendUiMessageToWilcoDtcImplCallback mojo_method_callback;
   base::RunLoop mojo_method_run_loop;
   ExpectMojoSendMessageCall(kMessageFromExtension /* expected_message */,
                             &mojo_method_callback, &mojo_method_run_loop);
@@ -271,7 +273,8 @@
 
 // Test that when the daemon responds without any message, no message is sent to
 // the extension.
-TEST_F(DiagnosticsdMessagingOpenedByExtensionSingleHostTest, EmptyResponse) {
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest,
+       EmptyResponse) {
   // Set up the daemon's Mojo service to expect the message from the extension
   // and to respond with an empty message.
   ExpectMojoSendMessageCallAndRespond(
@@ -291,10 +294,11 @@
 
 // Test the case when both the extension and the daemon send heavy messages, but
 // which are nevertheless within the acceptable bounds.
-TEST_F(DiagnosticsdMessagingOpenedByExtensionSingleHostTest, HeavyMessages) {
-  const std::string kHeavyMessageFromExtension(kDiagnosticsdUiMessageMaxSize,
-                                               '\1');
-  const std::string kHeavyMessageFromDaemon(kDiagnosticsdUiMessageMaxSize,
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest,
+       HeavyMessages) {
+  const std::string kHeavyMessageFromExtension(
+      kWilcoDtcSupportdUiMessageMaxSize, '\1');
+  const std::string kHeavyMessageFromDaemon(kWilcoDtcSupportdUiMessageMaxSize,
                                             '\2');
 
   // Set up the daemon's Mojo service to expect the message from the extension
@@ -317,15 +321,15 @@
 
 // Test that when the extension sends a too heavy message, it is discarded and
 // the message channel is closed.
-TEST_F(DiagnosticsdMessagingOpenedByExtensionSingleHostTest,
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest,
        ExcessivelyBigRequest) {
-  const std::string kExcessivelyBigMessage(kDiagnosticsdUiMessageMaxSize + 1,
-                                           '\1');
+  const std::string kExcessivelyBigMessage(
+      kWilcoDtcSupportdUiMessageMaxSize + 1, '\1');
 
   base::RunLoop channel_close_run_loop;
-  ExpectChannelClosingWithError(
-      kDiagnosticsdUiMessageTooBigExtensionsError /* expected_error_message */,
-      &channel_close_run_loop);
+  ExpectChannelClosingWithError(kWilcoDtcSupportdUiMessageTooBigExtensionsError
+                                /* expected_error_message */,
+                                &channel_close_run_loop);
 
   message_host()->OnMessage(kExcessivelyBigMessage);
 
@@ -334,10 +338,10 @@
 
 // Test that when the daemon sends a too heavy message, it is discarded and the
 // message channel is closed.
-TEST_F(DiagnosticsdMessagingOpenedByExtensionSingleHostTest,
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest,
        ExcessivelyBigResponse) {
-  const std::string kExcessivelyBigMessage(kDiagnosticsdUiMessageMaxSize + 1,
-                                           '\1');
+  const std::string kExcessivelyBigMessage(
+      kWilcoDtcSupportdUiMessageMaxSize + 1, '\1');
 
   // Set up the daemon's Mojo service to expect the message from the extension
   // and to respond with a heavy message.
@@ -348,9 +352,9 @@
   // Set up the expectation that the message host closes the channel with an
   // empty error message.
   base::RunLoop channel_close_run_loop;
-  ExpectChannelClosingWithError(
-      kDiagnosticsdUiMessageTooBigExtensionsError /* expected_error_message */,
-      &channel_close_run_loop);
+  ExpectChannelClosingWithError(kWilcoDtcSupportdUiMessageTooBigExtensionsError
+                                /* expected_error_message */,
+                                &channel_close_run_loop);
 
   // Send the message from the extension and wait till the channel gets closed.
   message_host()->OnMessage(kMessageFromExtension);
@@ -359,10 +363,10 @@
 
 // Test that extra messages sent by the extension before the daemon's response
 // arrives result in the channel being closed with an error.
-TEST_F(DiagnosticsdMessagingOpenedByExtensionSingleHostTest,
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest,
        ExtraRequestsBeforeResponse) {
   // Set up the daemon's Mojo service to expect the message from the extension.
-  SendUiMessageToDiagnosticsProcessorImplCallback mojo_method_callback;
+  SendUiMessageToWilcoDtcImplCallback mojo_method_callback;
   base::RunLoop mojo_method_run_loop;
   ExpectMojoSendMessageCall(kMessageFromExtension /* expected_message */,
                             &mojo_method_callback, &mojo_method_run_loop);
@@ -373,9 +377,9 @@
   // Send the second message from the extension and wait till the message host
   // closes the channel.
   base::RunLoop channel_close_run_loop;
-  ExpectChannelClosingWithError(
-      kDiagnosticsdUiExtraMessagesExtensionsError /* expected_error_message */,
-      &channel_close_run_loop);
+  ExpectChannelClosingWithError(kWilcoDtcSupportdUiExtraMessagesExtensionsError
+                                /* expected_error_message */,
+                                &channel_close_run_loop);
   message_host()->OnMessage(kMessageFromExtension);
   channel_close_run_loop.Run();
 
@@ -397,7 +401,7 @@
 // Test that extra messages sent by the extension after the daemon's response is
 // delivered are ignored (since the message channel is in the middle of being
 // closed at this point).
-TEST_F(DiagnosticsdMessagingOpenedByExtensionSingleHostTest,
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest,
        ExtraRequestsAfterResponse) {
   // Set up the daemon's Mojo service to expect the message from the extension
   // and to respond with another message.
@@ -427,10 +431,10 @@
 
 // Test the scenario when the message host is destroyed before the response from
 // the daemon arrives.
-TEST_F(DiagnosticsdMessagingOpenedByExtensionSingleHostTest,
+TEST_F(WilcoDtcSupportdMessagingOpenedByExtensionSingleHostTest,
        DestroyBeforeResponse) {
   // Set up the daemon's Mojo service to expect the message from the extension.
-  SendUiMessageToDiagnosticsProcessorImplCallback mojo_method_callback;
+  SendUiMessageToWilcoDtcImplCallback mojo_method_callback;
   base::RunLoop mojo_method_run_loop;
   ExpectMojoSendMessageCall(kMessageFromExtension /* expected_message */,
                             &mojo_method_callback, &mojo_method_run_loop);
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc
new file mode 100644
index 0000000..1936ae2e
--- /dev/null
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc
@@ -0,0 +1,267 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h"
+#include "mojo/public/cpp/system/buffer.h"
+#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
+#include "net/base/url_util.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/url_constants.h"
+
+namespace chromeos {
+
+// Maximum size of the |request_queue_|.
+const int kWilcoDtcSupportdWebRequestQueueMaxSize = 10;
+
+// Maximum size of the web response body.
+const int kWilcoDtcSupportdWebResponseMaxSizeInBytes = 1000000;
+
+namespace {
+
+// Converts mojo HTTP method into string.
+std::string GetHttpMethod(
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod
+        http_method) {
+  switch (http_method) {
+    case wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kGet:
+      return "GET";
+    case wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kHead:
+      return "HEAD";
+    case wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPost:
+      return "POST";
+    case wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPut:
+      return "PUT";
+  }
+}
+
+// Returns true in case of non-error 2xx HTTP status code.
+bool IsHttpOkCode(int code) {
+  return 200 <= code && code < 300;
+}
+
+}  //  namespace
+
+WilcoDtcSupportdWebRequestService::WilcoDtcSupportdWebRequestService(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : url_loader_factory_(std::move(url_loader_factory)) {
+  DCHECK(url_loader_factory_);
+}
+
+WilcoDtcSupportdWebRequestService::~WilcoDtcSupportdWebRequestService() {
+  if (active_request_) {
+    std::move(active_request_->callback)
+        .Run(wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                 kNetworkError,
+             0 /* http_status */, mojo::ScopedHandle() /* response_body */);
+    active_request_.reset();
+  }
+  while (!request_queue_.empty()) {
+    auto request = std::move(request_queue_.front());
+    request_queue_.pop();
+    std::move(request->callback)
+        .Run(wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                 kNetworkError,
+             0 /* http_status */, mojo::ScopedHandle() /* response_body */);
+  }
+  DCHECK(!active_request_);
+}
+
+void WilcoDtcSupportdWebRequestService::PerformRequest(
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod http_method,
+    GURL url,
+    std::vector<base::StringPiece> headers,
+    std::string request_body,
+    PerformWebRequestCallback callback) {
+  // Fail with the kNetworkError if the queue overflows.
+  if (request_queue_.size() == kWilcoDtcSupportdWebRequestQueueMaxSize) {
+    LOG(ERROR)
+        << "Too many incomplete requests in the wilco_dtc_supportd web request"
+        << " queue.";
+    std::move(callback).Run(wilco_dtc_supportd::mojom::
+                                WilcoDtcSupportdWebRequestStatus::kNetworkError,
+                            0 /* http_status */,
+                            mojo::ScopedHandle() /* response_body */);
+    return;
+  }
+
+  // Fail with kNetworkError if the |url| is invalid.
+  if (!url.is_valid()) {
+    LOG(ERROR) << "WilcoDtcSupportd web request URL is invalid.";
+    std::move(callback).Run(wilco_dtc_supportd::mojom::
+                                WilcoDtcSupportdWebRequestStatus::kNetworkError,
+                            0 /* http_status */,
+                            mojo::ScopedHandle() /* response_body */);
+    return;
+  }
+
+  // Fail with kNetworkError for non-HTTPs URL.
+  if (!url.SchemeIs(url::kHttpsScheme)) {
+    LOG(ERROR) << "WilcoDtcSupportd web request URL must have a HTTPS scheme.";
+    std::move(callback).Run(wilco_dtc_supportd::mojom::
+                                WilcoDtcSupportdWebRequestStatus::kNetworkError,
+                            0 /* http_status */,
+                            mojo::ScopedHandle() /* response_body */);
+    return;
+  }
+
+  // request_body must be empty for GET and HEAD HTTP methods.
+  if (!request_body.empty() &&
+      (http_method == wilco_dtc_supportd::mojom::
+                          WilcoDtcSupportdWebRequestHttpMethod::kGet ||
+       http_method == wilco_dtc_supportd::mojom::
+                          WilcoDtcSupportdWebRequestHttpMethod::kHead)) {
+    LOG(ERROR)
+        << "Incorrect wilco_dtc_supportd web request format: require an empty "
+        << "request body for GET and HEAD HTTP methods.";
+    std::move(callback).Run(wilco_dtc_supportd::mojom::
+                                WilcoDtcSupportdWebRequestStatus::kNetworkError,
+                            0 /* http_status */,
+                            mojo::ScopedHandle() /*response_body */);
+    return;
+  }
+
+  // Do not allow local requests.
+  if (net::IsLocalhost(url)) {
+    LOG(ERROR) << "Local requests are not allowed.";
+    std::move(callback).Run(wilco_dtc_supportd::mojom::
+                                WilcoDtcSupportdWebRequestStatus::kNetworkError,
+                            0 /* http_status */,
+                            mojo::ScopedHandle() /*response_body */);
+    return;
+  }
+
+  // Create a web request.
+  auto request = std::make_unique<WebRequest>();
+  request->request = std::make_unique<network::ResourceRequest>();
+  request->request->method = GetHttpMethod(http_method);
+  request->request->url = std::move(url);
+  request->request->allow_credentials = false;
+  request->request->load_flags = net::LOAD_DISABLE_CACHE;
+  for (auto header : headers) {
+    request->request->headers.AddHeaderFromString(header);
+  }
+
+  request->request_body = std::move(request_body);
+  request->callback = std::move(callback);
+
+  request_queue_.push(std::move(request));
+  MaybeStartNextRequest();
+}
+
+WilcoDtcSupportdWebRequestService::WebRequest::WebRequest() = default;
+
+WilcoDtcSupportdWebRequestService::WebRequest::~WebRequest() = default;
+
+void WilcoDtcSupportdWebRequestService::MaybeStartNextRequest() {
+  // Starts the next web requests only if there is nothing pending.
+  if (active_request_ || request_queue_.empty())
+    return;
+
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("wilco_dtc_supportd", R"(
+          semantics {
+            sender: "WilcoDtcSupportd"
+            description: "Perform a web request."
+            trigger:
+                "diagnostics_processor performs a web request to their server."
+            data:
+                "diagnostics_processor's proprietary data."
+            destination: OTHER
+          }
+          policy {
+            cookies_allowed: NO
+          }
+      )");
+
+  // Start new web request.
+  active_request_ = std::move(request_queue_.front());
+  request_queue_.pop();
+
+  url_loader_ = network::SimpleURLLoader::Create(
+      std::move(active_request_->request), traffic_annotation);
+  // Allows non-empty response body in case of HTTP errors.
+  url_loader_->SetAllowHttpErrorResults(true /* allow */);
+
+  if (!active_request_->request_body.empty()) {
+    url_loader_->AttachStringForUpload(active_request_->request_body,
+                                       "text/plain");
+  }
+  // Do not retry.
+  url_loader_->SetRetryOptions(0, network::SimpleURLLoader::RETRY_NEVER);
+  url_loader_->DownloadToString(
+      url_loader_factory_.get(),
+      base::BindOnce(&WilcoDtcSupportdWebRequestService::OnRequestComplete,
+                     base::Unretained(this)),
+      kWilcoDtcSupportdWebResponseMaxSizeInBytes);
+}
+
+void WilcoDtcSupportdWebRequestService::OnRequestComplete(
+    std::unique_ptr<std::string> response_body) {
+  DCHECK(active_request_);
+
+  int response_code = -1;
+  if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
+    response_code = url_loader_->ResponseInfo()->headers->response_code();
+  }
+
+  int net_error = url_loader_->NetError();
+  // Got a network error.
+  if (net_error != net::OK &&
+      (response_code == -1 || IsHttpOkCode(response_code))) {
+    DVLOG(0) << "Web request failed with error: " << net_error
+             << net::ErrorToString(net_error);
+    std::move(active_request_->callback)
+        .Run(wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                 kNetworkError,
+             0 /* http_status */, mojo::ScopedHandle() /* response_body */);
+    active_request_.reset();
+    MaybeStartNextRequest();
+    return;
+  }
+
+  // The response_code cannot be parsed from the web response.
+  if (response_code == -1) {
+    LOG(ERROR) << "Web request response cannot be parsed.";
+    response_code = net::HTTP_INTERNAL_SERVER_ERROR;
+  }
+
+  DCHECK(!response_body ||
+         response_body->size() <= kWilcoDtcSupportdWebResponseMaxSizeInBytes);
+
+  mojo::ScopedHandle response_body_handle;
+  if (response_body)
+    response_body_handle = CreateReadOnlySharedMemoryMojoHandle(*response_body);
+
+  // Got an HTTP error.
+  if (!IsHttpOkCode(response_code)) {
+    std::move(active_request_->callback)
+        .Run(wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                 kHttpError,
+             response_code, std::move(response_body_handle));
+    active_request_.reset();
+    MaybeStartNextRequest();
+    return;
+  }
+
+  // The web request is completed successfully.
+  std::move(active_request_->callback)
+      .Run(wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::kOk,
+           response_code, std::move(response_body_handle));
+  active_request_.reset();
+  MaybeStartNextRequest();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.h
similarity index 64%
rename from chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.h
rename to chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.h
index ec397b18..88092db4 100644
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.h
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_WEB_REQUEST_SERVICE_H_
-#define CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_WEB_REQUEST_SERVICE_H_
+#ifndef CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_WEB_REQUEST_SERVICE_H_
+#define CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_WEB_REQUEST_SERVICE_H_
 
 #include <memory>
 #include <string>
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/strings/string_piece.h"
-#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
+#include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h"
 #include "url/gurl.h"
 
 namespace network {
@@ -27,33 +27,34 @@
 namespace chromeos {
 
 // Max number of supported pending web requests.
-extern const int kDiagnosticsdWebRequestQueueMaxSize;
+extern const int kWilcoDtcSupportdWebRequestQueueMaxSize;
 
 // Max size of web response body in bytes.
-extern const int kDiagnosticsdWebResponseMaxSizeInBytes;
+extern const int kWilcoDtcSupportdWebResponseMaxSizeInBytes;
 
 // This class manages and performs web requests initiated by
-// diagnosticsd_processor. This service performs only one request at a time
-// and queues additional incoming requests. It can handle the limited number of
-// queued web requests. If the web request queue overflows, new web requests
-// fail with kNetworkError.
-class DiagnosticsdWebRequestService final {
+// wilco_dtc_supportd_processor. This service performs only one request at a
+// time and queues additional incoming requests. It can handle the limited
+// number of queued web requests. If the web request queue overflows, new web
+// requests fail with kNetworkError.
+class WilcoDtcSupportdWebRequestService final {
  public:
-  using PerformWebRequestCallback =
-      base::OnceCallback<void(diagnosticsd::mojom::DiagnosticsdWebRequestStatus,
-                              int,
-                              mojo::ScopedHandle)>;
+  using PerformWebRequestCallback = base::OnceCallback<void(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus,
+      int,
+      mojo::ScopedHandle)>;
 
-  explicit DiagnosticsdWebRequestService(
+  explicit WilcoDtcSupportdWebRequestService(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
-  ~DiagnosticsdWebRequestService();
+  ~WilcoDtcSupportdWebRequestService();
 
   // Performs web request. The response is returned by |callback| which is
   // guaranteed to be called. The requests, that were not complete in lifetime
   // of the service, will be canceled and the |callback| will be executed in
   // the destructor and fail with kNetworkError.
   void PerformRequest(
-      diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod http_method,
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod
+          http_method,
       GURL url,
       std::vector<base::StringPiece> headers,
       std::string request_body,
@@ -85,9 +86,9 @@
   base::queue<std::unique_ptr<WebRequest>> request_queue_;
   std::unique_ptr<WebRequest> active_request_;
 
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdWebRequestService);
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdWebRequestService);
 };
 
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_WEB_REQUEST_SERVICE_H_
+#endif  // CHROME_BROWSER_CHROMEOS_WILCO_DTC_SUPPORTD_WILCO_DTC_SUPPORTD_WEB_REQUEST_SERVICE_H_
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc
similarity index 60%
rename from chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service_unittest.cc
rename to chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc
index d64a499..4ad7589 100644
--- a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service_unittest.cc
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc
@@ -14,8 +14,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_piece.h"
-#include "chrome/browser/chromeos/diagnosticsd/mojo_utils.h"
-#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h"
+#include "chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/resource_request.h"
@@ -25,7 +25,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_web_request_service.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.h"
 
 namespace chromeos {
 
@@ -38,13 +38,14 @@
 constexpr char kFakeRequestBody[] = "Fake\0Request\11Body\n\0";
 constexpr char kFakeResponseBody[] = "Fake\11Response\0\0\nBody";
 
-// Tests for the DiagnosticsdWebRequestService class.
-class DiagnosticsdWebRequestServiceTest : public testing::Test {
+// Tests for the WilcoDtcSupportdWebRequestService class.
+class WilcoDtcSupportdWebRequestServiceTest : public testing::Test {
  protected:
   struct WebRequestResult {
-    WebRequestResult(diagnosticsd::mojom::DiagnosticsdWebRequestStatus status,
-                     int http_status,
-                     mojo::ScopedHandle response_body_handle)
+    WebRequestResult(
+        wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus status,
+        int http_status,
+        mojo::ScopedHandle response_body_handle)
         : status(status), http_status(http_status) {
       if (!response_body_handle.is_valid()) {
         response_body = "";
@@ -59,17 +60,17 @@
       }
     }
 
-    diagnosticsd::mojom::DiagnosticsdWebRequestStatus status;
+    wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus status;
     int http_status;
     std::string response_body;
   };
-  DiagnosticsdWebRequestServiceTest() {
-    web_request_service_ = std::make_unique<DiagnosticsdWebRequestService>(
+  WilcoDtcSupportdWebRequestServiceTest() {
+    web_request_service_ = std::make_unique<WilcoDtcSupportdWebRequestService>(
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_));
   }
 
-  ~DiagnosticsdWebRequestServiceTest() override {}
+  ~WilcoDtcSupportdWebRequestServiceTest() override {}
 
   void TearDown() override { test_url_loader_factory_.ClearResponses(); }
 
@@ -82,7 +83,8 @@
   //                      web response.
   // * |run_loop| - the current run loop.
   void StartWebRequest(
-      diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod http_method,
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod
+          http_method,
       const std::string& url,
       const std::string& request_body,
       std::unique_ptr<WebRequestResult>* request_result,
@@ -90,9 +92,9 @@
     web_request_service()->PerformRequest(
         http_method, GURL(url), std::vector<base::StringPiece>() /* headers */,
         request_body,
-        base::BindOnce(&DiagnosticsdWebRequestServiceTest::OnRequestComplete,
-                       base::Unretained(this), request_result,
-                       run_loop->QuitClosure()));
+        base::BindOnce(
+            &WilcoDtcSupportdWebRequestServiceTest::OnRequestComplete,
+            base::Unretained(this), request_result, run_loop->QuitClosure()));
   }
 
   // Injects the web response for |url|.
@@ -111,7 +113,7 @@
 
   void DestroyService() { web_request_service_.reset(); }
 
-  DiagnosticsdWebRequestService* web_request_service() {
+  WilcoDtcSupportdWebRequestService* web_request_service() {
     return web_request_service_.get();
   }
 
@@ -119,7 +121,7 @@
   void OnRequestComplete(
       std::unique_ptr<WebRequestResult>* request_result,
       base::RepeatingClosure callback,
-      diagnosticsd::mojom::DiagnosticsdWebRequestStatus status,
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus status,
       int http_status,
       mojo::ScopedHandle response_body) {
     auto response = std::make_unique<WebRequestResult>(
@@ -128,33 +130,36 @@
     std::move(callback).Run();
   }
 
-  std::unique_ptr<DiagnosticsdWebRequestService> web_request_service_;
+  std::unique_ptr<WilcoDtcSupportdWebRequestService> web_request_service_;
   network::TestURLLoaderFactory test_url_loader_factory_;
   base::MessageLoop message_loop_;
 };
 
 }  // namespace
 
-TEST_F(DiagnosticsdWebRequestServiceTest, HttpMethodGetNonEmptyBody) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, HttpMethodGetNonEmptyBody) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kGet,
-                  kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kGet,
+      kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
   // The test fails with a network error on the same thread.
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, HttpMethodHeadEmptyBody) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, HttpMethodHeadEmptyBody) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kHead,
-                  kFakeUrl, "" /* request_body */, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kHead,
+      kFakeUrl, "" /* request_body */, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(kFakeUrl,
                         std::make_unique<net::HttpStatusCode>(net::HTTP_OK),
@@ -162,17 +167,18 @@
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kOk);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::kOk);
   EXPECT_EQ(request_result->http_status, net::HTTP_OK);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, HttpMethodPostNonEmptyBody) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, HttpMethodPostNonEmptyBody) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPost,
-                  kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPost,
+      kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(kFakeUrl,
                         std::make_unique<net::HttpStatusCode>(net::HTTP_OK),
@@ -180,17 +186,18 @@
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kOk);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::kOk);
   EXPECT_EQ(request_result->http_status, net::HTTP_OK);
   EXPECT_EQ(request_result->response_body, kFakeResponseBody);
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, HttpMethodPutEmptyBody) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, HttpMethodPutEmptyBody) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPut,
-                  kFakeUrl, "" /* request_body */, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPut,
+      kFakeUrl, "" /* request_body */, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(kFakeUrl,
                         std::make_unique<net::HttpStatusCode>(net::HTTP_OK),
@@ -198,51 +205,57 @@
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kOk);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::kOk);
   EXPECT_EQ(request_result->http_status, net::HTTP_OK);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, ResponseCodeParsingError) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, ResponseCodeParsingError) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPost,
-                  kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPost,
+      kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(kFakeUrl, nullptr /* response_status */, net::OK,
                         "" /* response_body */);
   run_loop.Run();
   ASSERT_TRUE(request_result);
-  EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kHttpError);
+  EXPECT_EQ(
+      request_result->status,
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::kHttpError);
   EXPECT_EQ(request_result->http_status, net::HTTP_INTERNAL_SERVER_ERROR);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, ResponseCodeParsingErrorNetError) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest,
+       ResponseCodeParsingErrorNetError) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kGet,
-                  kFakeUrl, "" /* request_body */, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kGet,
+      kFakeUrl, "" /* request_body */, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(kFakeUrl, nullptr /* response_status */,
                         net::ERR_CERT_INVALID, kFakeResponseBody);
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, HttpStatusOkNetError) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, HttpStatusOkNetError) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPost,
-                  kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPost,
+      kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(kFakeUrl,
                         std::make_unique<net::HttpStatusCode>(net::HTTP_OK),
@@ -250,17 +263,19 @@
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, HttpErrorNetError) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, HttpErrorNetError) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPost,
-                  kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPost,
+      kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(
       kFakeUrl, std::make_unique<net::HttpStatusCode>(net::HTTP_BAD_REQUEST),
@@ -268,17 +283,20 @@
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, DestroyServiceWithActiveWebRequest) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest,
+       DestroyServiceWithActiveWebRequest) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPost,
-                  kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPost,
+      kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
   InjectNetworkResponse(kFakeUrl,
                         std::make_unique<net::HttpStatusCode>(net::HTTP_OK),
                         net::OK, kFakeResponseBody);
@@ -288,21 +306,22 @@
 
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, TwoWebRequests) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, TwoWebRequests) {
   constexpr int kNumberOfRequests = 2;
 
   std::unique_ptr<WebRequestResult> request_results[kNumberOfRequests];
   base::RunLoop run_loops[kNumberOfRequests];
 
   for (int i = 0; i < kNumberOfRequests; ++i) {
-    StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPut,
-                    kFakeUrl, kFakeRequestBody, &request_results[i],
-                    &run_loops[i]);
+    StartWebRequest(
+        wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPut,
+        kFakeUrl, kFakeRequestBody, &request_results[i], &run_loops[i]);
     InjectNetworkResponse(kFakeUrl,
                           std::make_unique<net::HttpStatusCode>(net::HTTP_OK),
                           net::OK, kFakeResponseBody);
@@ -320,44 +339,46 @@
   for (const auto& request_result : request_results) {
     ASSERT_TRUE(request_result);
     EXPECT_EQ(request_result->status,
-              diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kOk);
+              wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::kOk);
     EXPECT_EQ(request_result->http_status, net::HTTP_OK);
     EXPECT_EQ(request_result->response_body, kFakeResponseBody);
   }
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, RequestQueueOverflow) {
-  // The number of requests in the queue is kDiagnosticsdRequestQueueMaxSize.
-  // One is already pending.
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, RequestQueueOverflow) {
+  // The number of requests in the queue is
+  // kWilcoDtcSupportdRequestQueueMaxSize. One is already pending.
   std::unique_ptr<WebRequestResult>
-      request_results[kDiagnosticsdWebRequestQueueMaxSize + 1];
-  base::RunLoop run_loops[kDiagnosticsdWebRequestQueueMaxSize + 1];
+      request_results[kWilcoDtcSupportdWebRequestQueueMaxSize + 1];
+  base::RunLoop run_loops[kWilcoDtcSupportdWebRequestQueueMaxSize + 1];
 
-  for (int i = 0; i < kDiagnosticsdWebRequestQueueMaxSize + 1; ++i) {
-    StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPut,
-                    kFakeUrl, kFakeRequestBody, &request_results[i],
-                    &run_loops[i]);
+  for (int i = 0; i < kWilcoDtcSupportdWebRequestQueueMaxSize + 1; ++i) {
+    StartWebRequest(
+        wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPut,
+        kFakeUrl, kFakeRequestBody, &request_results[i], &run_loops[i]);
     InjectNetworkResponse(kFakeUrl,
                           std::make_unique<net::HttpStatusCode>(net::HTTP_OK),
                           net::OK, kFakeResponseBody);
     EXPECT_FALSE(request_results[i]);
   }
-  EXPECT_EQ(kDiagnosticsdWebRequestQueueMaxSize,
+  EXPECT_EQ(kWilcoDtcSupportdWebRequestQueueMaxSize,
             web_request_service()->request_queue_size_for_testing());
 
   // Try to add one more. Should fail with kNetworkError.
   {
     std::unique_ptr<WebRequestResult> request_result;
     base::RunLoop run_loop;
-    StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kPut,
-                    kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
+    StartWebRequest(
+        wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kPut,
+        kFakeUrl, kFakeRequestBody, &request_result, &run_loop);
     InjectNetworkResponse(kFakeUrl,
                           std::make_unique<net::HttpStatusCode>(net::HTTP_OK),
                           net::OK, kFakeResponseBody);
     // The test fails with a network error on the same thread.
     EXPECT_TRUE(request_result);
     EXPECT_EQ(request_result->status,
-              diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+              wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                  kNetworkError);
     EXPECT_EQ(request_result->http_status, 0);
     EXPECT_EQ(request_result->response_body, "");
   }
@@ -367,91 +388,97 @@
   for (const auto& request_result : request_results) {
     EXPECT_TRUE(request_result);
     EXPECT_EQ(request_result->status,
-              diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kOk);
+              wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::kOk);
     EXPECT_EQ(request_result->http_status, net::HTTP_OK);
     EXPECT_EQ(request_result->response_body, kFakeResponseBody);
   }
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, ResponseBodyMaxSize) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, ResponseBodyMaxSize) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kHead,
-                  kFakeUrl, "" /* request_body */, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kHead,
+      kFakeUrl, "" /* request_body */, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(
       kFakeUrl, std::make_unique<net::HttpStatusCode>(net::HTTP_OK), net::OK,
-      std::string(kDiagnosticsdWebResponseMaxSizeInBytes, 'A'));
+      std::string(kWilcoDtcSupportdWebResponseMaxSizeInBytes, 'A'));
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kOk);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::kOk);
   EXPECT_EQ(request_result->http_status, net::HTTP_OK);
   EXPECT_EQ(request_result->response_body,
-            std::string(kDiagnosticsdWebResponseMaxSizeInBytes, 'A'));
+            std::string(kWilcoDtcSupportdWebResponseMaxSizeInBytes, 'A'));
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, ResponseBodyOverflow) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, ResponseBodyOverflow) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kHead,
-                  kFakeUrl, "" /* request_body */, &request_result, &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kHead,
+      kFakeUrl, "" /* request_body */, &request_result, &run_loop);
   EXPECT_FALSE(request_result);
   InjectNetworkResponse(
       kFakeUrl, std::make_unique<net::HttpStatusCode>(net::HTTP_OK), net::OK,
-      std::string(kDiagnosticsdWebResponseMaxSizeInBytes + 1, 'A'));
+      std::string(kWilcoDtcSupportdWebResponseMaxSizeInBytes + 1, 'A'));
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, LocalhostRequestNetworkError) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, LocalhostRequestNetworkError) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kHead,
-                  kLocalhostUrl, "" /* request_body */, &request_result,
-                  &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kHead,
+      kLocalhostUrl, "" /* request_body */, &request_result, &run_loop);
   // The test fails with a network error on the same thread.
   run_loop.Run();
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, HttpUrlNetworkError) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, HttpUrlNetworkError) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kHead,
-                  kIncorrectHttpUrl, "" /* request_body */, &request_result,
-                  &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kHead,
+      kIncorrectHttpUrl, "" /* request_body */, &request_result, &run_loop);
   // The test fails with a network error on the same thread.
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
 
-TEST_F(DiagnosticsdWebRequestServiceTest, InvalidUrlNetworkError) {
+TEST_F(WilcoDtcSupportdWebRequestServiceTest, InvalidUrlNetworkError) {
   std::unique_ptr<WebRequestResult> request_result;
   base::RunLoop run_loop;
 
-  StartWebRequest(diagnosticsd::mojom::DiagnosticsdWebRequestHttpMethod::kHead,
-                  kInvalidUrl, "" /* request_body */, &request_result,
-                  &run_loop);
+  StartWebRequest(
+      wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestHttpMethod::kHead,
+      kInvalidUrl, "" /* request_body */, &request_result, &run_loop);
   // The test fails with a network error on the same thread.
   ASSERT_TRUE(request_result);
   EXPECT_EQ(request_result->status,
-            diagnosticsd::mojom::DiagnosticsdWebRequestStatus::kNetworkError);
+            wilco_dtc_supportd::mojom::WilcoDtcSupportdWebRequestStatus::
+                kNetworkError);
   EXPECT_EQ(request_result->http_status, 0);
   EXPECT_EQ(request_result->response_body, "");
 }
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index be0a75a4..101825e 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -756,10 +756,6 @@
   ]
   defines = []
 
-  if (is_chromeos && enable_kiosk_next) {
-    defines += [ "KIOSK_NEXT" ]
-  }
-
   allow_circular_includes_from = [
     # Lots of APIs use headers from the list above.
     "//chrome/browser/extensions/api:api_registration",
@@ -982,7 +978,6 @@
     }
     deps += [
       "//ash/public/cpp",
-      "//chrome/browser/chromeos/kiosk_next_home/mojom",
       "//chrome/browser/resources/chromeos/camera:chrome_camera_app",
       "//chromeos",
       "//chromeos/attestation",
@@ -1021,6 +1016,13 @@
       "//ui/ozone",
       "//ui/views",
     ]
+    if (enable_kiosk_next) {
+      defines += [ "KIOSK_NEXT" ]
+      deps += [ "//chrome/browser/chromeos/kiosk_next_home/mojom" ]
+      if (is_chrome_branded) {
+        deps += [ "//chrome/browser/resources:kiosk_next_internal_resources" ]
+      }
+    }
     if (enable_nacl) {
       deps += [ "//chrome/browser/resources/chromeos/zip_archiver" ]
     }
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
index be7b9253..79319a9 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "base/containers/flat_set.h"
-#include "base/feature_list.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_split.h"
@@ -233,12 +232,9 @@
     if (entry.supports_translate) {
       language.supports_translate.reset(new bool(true));
     }
-    if (base::FeatureList::IsEnabled(translate::kRegionalLocalesAsDisplayUI)) {
-      std::string temp_locale = entry.code;
-      if (language::ConvertToActualUILocale(&temp_locale)) {
-        language.supports_ui.reset(new bool(true));
-      }
-    } else if (base::ContainsKey(locale_set, entry.code)) {
+
+    std::string temp_locale = entry.code;
+    if (language::ConvertToActualUILocale(&temp_locale)) {
       language.supports_ui.reset(new bool(true));
     }
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
index 8c33f17..e4116adad 100644
--- a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
@@ -20,7 +20,7 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/arc/extensions/arc_support_message_host.h"
-#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_messaging.h"
+#include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/constants.h"
@@ -127,8 +127,8 @@
     {arc::ArcSupportMessageHost::kHostName,
      arc::ArcSupportMessageHost::kHostOrigin, 1,
      &arc::ArcSupportMessageHost::Create},
-    {chromeos::kDiagnosticsdUiMessageHost, nullptr, 0,
-     &chromeos::CreateExtensionOwnedDiagnosticsdMessageHost},
+    {chromeos::kWilcoDtcSupportdUiMessageHost, nullptr, 0,
+     &chromeos::CreateExtensionOwnedWilcoDtcSupportdMessageHost},
 };
 
 bool MatchesSecurityOrigin(const BuiltInHost& host,
diff --git a/chrome/browser/extensions/api/preference/preference_api.cc b/chrome/browser/extensions/api/preference/preference_api.cc
index a66fafe..346eeb9 100644
--- a/chrome/browser/extensions/api/preference/preference_api.cc
+++ b/chrome/browser/extensions/api/preference/preference_api.cc
@@ -159,6 +159,9 @@
     {"screenMagnifier", ash::prefs::kAccessibilityScreenMagnifierEnabled,
      APIPermission::kAccessibilityFeaturesRead,
      APIPermission::kAccessibilityFeaturesModify},
+    {"selectToSpeak", ash::prefs::kAccessibilitySelectToSpeakEnabled,
+     APIPermission::kAccessibilityFeaturesRead,
+     APIPermission::kAccessibilityFeaturesModify},
     {"spokenFeedback", ash::prefs::kAccessibilitySpokenFeedbackEnabled,
      APIPermission::kAccessibilityFeaturesRead,
      APIPermission::kAccessibilityFeaturesModify},
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
index fdee193e..cbfa7b3 100644
--- a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
+++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
@@ -26,6 +26,10 @@
 #include "ui/keyboard/resources/keyboard_resource_util.h"
 #endif
 
+#if defined(KIOSK_NEXT) && defined(GOOGLE_CHROME_BUILD)
+#include "chrome/grit/kiosk_next_internal_resources_map.h"
+#endif
+
 namespace extensions {
 
 ChromeComponentExtensionResourceManager::
@@ -86,6 +90,11 @@
       keyboard_resources,
       keyboard_resource_size);
 #endif
+
+#if defined(KIOSK_NEXT) && defined(GOOGLE_CHROME_BUILD)
+  AddComponentResourceEntries(kKioskNextInternalResources,
+                              kKioskNextInternalResourcesSize);
+#endif
 }
 
 ChromeComponentExtensionResourceManager::
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 8622a40..d5d9373 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -54,6 +54,12 @@
     "expiry_milestone": 76
   },
   {
+    "name": "allow-popups-during-page-unload",
+    "owners": [ "avi", "pastarmovj" ],
+    // Bound to the timelene of the AllowPopupsDuringPageUnload policy.
+    "expiry_milestone": 82
+  },
+  {
     "name": "allow-previews",
     "owners": [ "//components/data_reduction_proxy/OWNERS" ],
     "expiry_milestone": 76
@@ -1082,11 +1088,6 @@
     "expiry_milestone": 76
   },
   {
-    "name": "enable-font-cache-scaling",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "enable-fs-nosymfollow",
     "owners": [ "mortonm@chromium.org" ],
     "expiry_milestone": 76
@@ -2610,7 +2611,7 @@
   },
   {
     "name": "omnibox-zero-suggestions-on-ntp",
-    "omners": [ "chrome-android-omnibox-team@google.com" ],
+    "owners": [ "chrome-android-omnibox-team@google.com" ],
     "expiry_milestone": 81
   },
   {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 19aa113f4..82d496e7 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -24,6 +24,12 @@
     "Allows requests to localhost over HTTPS even when an invalid certificate "
     "is presented.";
 
+const char kAllowPopupsDuringPageUnloadName[] =
+    "Allows a page to show popups during its unloading";
+const char kAllowPopupsDuringPageUnloadDescription[] =
+    "When the flag is set to enabled, pages are allowed to show popups while "
+    "they are being unloaded.";
+
 const char kAllowSignedHTTPExchangeCertsWithoutExtensionName[] =
     "Allow Signed HTTP Exchange certificates without extension";
 const char kAllowSignedHTTPExchangeCertsWithoutExtensionDescription[] =
@@ -282,8 +288,7 @@
 extern const char kCookiesWithoutSameSiteMustBeSecureDescription[] =
     "If enabled, cookies without SameSite restrictions must also be Secure. If "
     "a cookie without SameSite restrictions is set without the Secure "
-    "attribute, it will be treated as Secure (if set from a secure URL), or "
-    "rejected (if set from an insecure URL). This flag only has an effect if "
+    "attribute, it will be rejected. This flag only has an effect if "
     "\"SameSite by default cookies\" is also enabled.";
 
 const char kCreditCardAssistName[] = "Credit Card Assisted Filling";
@@ -3000,10 +3005,6 @@
     "Disable tablet mode autohide titlebars functionality. The user will be "
     "able to see the titlebar in tablet mode.";
 
-const char kDisableTabletSplitViewName[] = "Disable split view in Tablet mode";
-const char kDisableTabletSplitViewDescription[] =
-    "Disable split view for Chrome OS tablet mode.";
-
 const char kDoubleTapToZoomInTabletModeName[] =
     "Double-tap to zoom in tablet mode";
 const char kDoubleTapToZoomInTabletModeDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 8384ee8..28e51a8 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -49,6 +49,9 @@
 extern const char kAllowInsecureLocalhostName[];
 extern const char kAllowInsecureLocalhostDescription[];
 
+extern const char kAllowPopupsDuringPageUnloadName[];
+extern const char kAllowPopupsDuringPageUnloadDescription[];
+
 extern const char kAllowSignedHTTPExchangeCertsWithoutExtensionName[];
 extern const char kAllowSignedHTTPExchangeCertsWithoutExtensionDescription[];
 
@@ -1807,9 +1810,6 @@
 extern const char kDisableTabletAutohideTitlebarsName[];
 extern const char kDisableTabletAutohideTitlebarsDescription[];
 
-extern const char kDisableTabletSplitViewName[];
-extern const char kDisableTabletSplitViewDescription[];
-
 extern const char kDoubleTapToZoomInTabletModeName[];
 extern const char kDoubleTapToZoomInTabletModeDescription[];
 
diff --git a/chrome/browser/offline_pages/android/auto_fetch_notifier.cc b/chrome/browser/offline_pages/android/auto_fetch_notifier.cc
index 99be596..5f0527f1 100644
--- a/chrome/browser/offline_pages/android/auto_fetch_notifier.cc
+++ b/chrome/browser/offline_pages/android/auto_fetch_notifier.cc
@@ -58,6 +58,7 @@
 }
 
 void ShowAutoFetchCompleteNotification(const base::string16& pageTitle,
+                                       const std::string& original_url,
                                        const std::string& final_url,
                                        int android_tab_id,
                                        int64_t offline_id) {
@@ -65,6 +66,7 @@
   Java_AutoFetchNotifier_showCompleteNotification(
       env,
       base::android::ConvertUTF8ToJavaString(env, base::UTF16ToUTF8(pageTitle)),
+      base::android::ConvertUTF8ToJavaString(env, original_url),
       base::android::ConvertUTF8ToJavaString(env, final_url), android_tab_id,
       offline_id);
 }
diff --git a/chrome/browser/offline_pages/android/auto_fetch_notifier.h b/chrome/browser/offline_pages/android/auto_fetch_notifier.h
index ef8cd11..d5811132 100644
--- a/chrome/browser/offline_pages/android/auto_fetch_notifier.h
+++ b/chrome/browser/offline_pages/android/auto_fetch_notifier.h
@@ -26,6 +26,7 @@
 
 // Triggers the auto-fetch complete notification. See AutoFetchNotifier.java.
 void ShowAutoFetchCompleteNotification(const base::string16& page_title,
+                                       const std::string& original_url,
                                        const std::string& final_url,
                                        int android_tab_id,
                                        int64_t offline_id);
diff --git a/chrome/browser/offline_pages/android/cct_origin_observer.cc b/chrome/browser/offline_pages/android/cct_origin_observer.cc
index d4f86d4..2edba95 100644
--- a/chrome/browser/offline_pages/android/cct_origin_observer.cc
+++ b/chrome/browser/offline_pages/android/cct_origin_observer.cc
@@ -40,12 +40,11 @@
       ConvertUTF8ToJavaString(env, added_page.url.spec()));
 }
 
-void CctOriginObserver::OfflinePageDeleted(
-    const OfflinePageModel::DeletedPageInfo& page_info) {
+void CctOriginObserver::OfflinePageDeleted(const OfflinePageItem& item) {
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_CctOfflinePageModelObserver_onPageChanged(
-      env, ConvertUTF8ToJavaString(env, page_info.request_origin), false,
-      ConvertUTF8ToJavaString(env, page_info.url.spec()));
+      env, ConvertUTF8ToJavaString(env, item.request_origin), false,
+      ConvertUTF8ToJavaString(env, item.url.spec()));
 }
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/android/cct_origin_observer.h b/chrome/browser/offline_pages/android/cct_origin_observer.h
index 3d1417d..83745b0 100644
--- a/chrome/browser/offline_pages/android/cct_origin_observer.h
+++ b/chrome/browser/offline_pages/android/cct_origin_observer.h
@@ -25,8 +25,7 @@
   void OfflinePageModelLoaded(OfflinePageModel* model) override;
   void OfflinePageAdded(OfflinePageModel* model,
                         const OfflinePageItem& added_page) override;
-  void OfflinePageDeleted(
-      const OfflinePageModel::DeletedPageInfo& page_info) override;
+  void OfflinePageDeleted(const OfflinePageItem& item) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(CctOriginObserver);
diff --git a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
index 00c7c94..e867740 100644
--- a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
+++ b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
@@ -249,7 +249,7 @@
     const OfflinePageItem& added_page) {}
 
 void OfflinePageEvaluationBridge::OfflinePageDeleted(
-    const OfflinePageModel::DeletedPageInfo& page_info) {}
+    const OfflinePageItem& item) {}
 
 // Implement RequestCoordinator::Observer
 void OfflinePageEvaluationBridge::OnAdded(const SavePageRequest& request) {
diff --git a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.h b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.h
index 4660a31..d23e5b2 100644
--- a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.h
+++ b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.h
@@ -41,8 +41,7 @@
   void OfflinePageModelLoaded(OfflinePageModel* model) override;
   void OfflinePageAdded(OfflinePageModel* model,
                         const OfflinePageItem& added_page) override;
-  void OfflinePageDeleted(
-      const OfflinePageModel::DeletedPageInfo& page_info) override;
+  void OfflinePageDeleted(const OfflinePageItem& item) override;
 
   // RequestCoordinator::Observer implementation.
   void OnAdded(const SavePageRequest& request) override;
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.cc
index a7fb946..52a42cb4 100644
--- a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.cc
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.cc
@@ -173,9 +173,9 @@
   if (!metadata)
     return;
 
-  delegate_->ShowAutoFetchCompleteNotification(page->title, page->url.spec(),
-                                               metadata.value().android_tab_id,
-                                               page->offline_id);
+  delegate_->ShowAutoFetchCompleteNotification(
+      page->title, page->GetOriginalUrl().spec(), page->url.spec(),
+      metadata.value().android_tab_id, page->offline_id);
 }
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h
index 2785f7f..50ad1f7 100644
--- a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h
@@ -7,11 +7,13 @@
 
 #include <memory>
 #include <queue>
+#include <string>
 #include <utility>
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
 #include "chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.h"
 #include "chrome/common/offline_page_auto_fetcher.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -65,7 +67,8 @@
     // Calls |offline_pages::ShowAutoFetchCompleteNotification()|.
     virtual void ShowAutoFetchCompleteNotification(
         const base::string16& pageTitle,
-        const std::string& url,
+        const std::string& original_url,
+        const std::string& final_url,
         int android_tab_id,
         int64_t offline_id) = 0;
   };
@@ -101,7 +104,6 @@
                          int64_t received_bytes) override {}
 
  private:
-
   base::WeakPtr<OfflinePageAutoFetcherService> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc
index 2ff410a..f48d469a 100644
--- a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h"
 
+#include <string>
+
 #include "base/memory/singleton.h"
 #include "chrome/browser/offline_pages/android/auto_fetch_notifier.h"
 #include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h"
@@ -16,11 +18,12 @@
 class OfflinePageAutoFetcherServiceFactory::ServiceDelegate final
     : public OfflinePageAutoFetcherService::Delegate {
   void ShowAutoFetchCompleteNotification(const base::string16& pageTitle,
-                                         const std::string& url,
+                                         const std::string& original_url,
+                                         const std::string& final_url,
                                          int android_tab_id,
                                          int64_t offline_id) override {
     offline_pages::ShowAutoFetchCompleteNotification(
-        pageTitle, url, android_tab_id, offline_id);
+        pageTitle, original_url, final_url, android_tab_id, offline_id);
   }
 };
 
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_unittest.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_unittest.cc
index bc9a1c7f..4f577764 100644
--- a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_unittest.cc
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_unittest.cc
@@ -42,9 +42,10 @@
 
 class MockDelegate : public OfflinePageAutoFetcherService::Delegate {
  public:
-  MOCK_METHOD4(ShowAutoFetchCompleteNotification,
+  MOCK_METHOD5(ShowAutoFetchCompleteNotification,
                void(const base::string16& pageTitle,
-                    const std::string& url,
+                    const std::string& original_url,
+                    const std::string& final_url,
                     int android_tab_id,
                     int64_t offline_id));
 };
@@ -235,7 +236,7 @@
       .WillOnce(testing::Return(&returned_item));
   EXPECT_CALL(delegate_, ShowAutoFetchCompleteNotification(
                              returned_item.title, kTestRequest.url().spec(),
-                             kTabId, kOfflineId));
+                             kTestRequest.url().spec(), kTabId, kOfflineId));
   service_->OnCompleted(kTestRequest,
                         RequestNotifier::BackgroundSavePageResult::SUCCESS);
   thread_bundle_.RunUntilIdle();
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc
index b045684..9a6c1658 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.cc
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -83,7 +83,7 @@
 
 ScopedJavaLocalRef<jobject> JNI_SavePageRequest_ToJavaDeletedPageInfo(
     JNIEnv* env,
-    const OfflinePageModel::DeletedPageInfo& deleted_page) {
+    const OfflinePageItem& deleted_page) {
   return Java_OfflinePageBridge_createDeletedPageInfo(
       env, deleted_page.offline_id,
       ConvertUTF8ToJavaString(env, deleted_page.client_id.name_space),
@@ -434,12 +434,10 @@
       JNI_SavePageRequest_ToJavaOfflinePageItem(env, added_page));
 }
 
-void OfflinePageBridge::OfflinePageDeleted(
-    const OfflinePageModel::DeletedPageInfo& page_info) {
+void OfflinePageBridge::OfflinePageDeleted(const OfflinePageItem& item) {
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_OfflinePageBridge_offlinePageDeleted(
-      env, java_ref_,
-      JNI_SavePageRequest_ToJavaDeletedPageInfo(env, page_info));
+      env, java_ref_, JNI_SavePageRequest_ToJavaDeletedPageInfo(env, item));
 }
 
 void OfflinePageBridge::GetAllPages(
@@ -502,10 +500,11 @@
     const JavaParamRef<jobject>& j_callback_obj) {
   ScopedJavaGlobalRef<jobject> j_callback_ref;
   j_callback_ref.Reset(env, j_callback_obj);
-  std::vector<ClientId> client_ids =
+  PageCriteria criteria;
+  criteria.client_ids =
       getClientIdsFromObjectArrays(env, j_namespaces_array, j_ids_array);
-  offline_page_model_->DeletePagesByClientIds(
-      client_ids, base::Bind(&DeletePageCallback, j_callback_ref));
+  offline_page_model_->DeletePagesWithCriteria(
+      criteria, base::BindOnce(&DeletePageCallback, j_callback_ref));
 }
 
 void OfflinePageBridge::DeletePagesByClientIdAndOrigin(
@@ -517,11 +516,12 @@
     const base::android::JavaParamRef<jobject>& j_callback_obj) {
   ScopedJavaGlobalRef<jobject> j_callback_ref;
   j_callback_ref.Reset(env, j_callback_obj);
-  std::vector<ClientId> client_ids =
+  PageCriteria criteria;
+  criteria.client_ids =
       getClientIdsFromObjectArrays(env, j_namespaces_array, j_ids_array);
-  offline_page_model_->DeletePagesByClientIdsAndOrigin(
-      client_ids, ConvertJavaStringToUTF8(j_origin),
-      base::Bind(&DeletePageCallback, j_callback_ref));
+  criteria.request_origin = ConvertJavaStringToUTF8(j_origin);
+  offline_page_model_->DeletePagesWithCriteria(
+      criteria, base::BindOnce(&DeletePageCallback, j_callback_ref));
 }
 
 void OfflinePageBridge::DeletePagesByOfflineId(
@@ -534,8 +534,11 @@
   std::vector<int64_t> offline_ids;
   base::android::JavaLongArrayToInt64Vector(env, j_offline_ids_array,
                                             &offline_ids);
-  offline_page_model_->DeletePagesByOfflineId(
-      offline_ids, base::Bind(&DeletePageCallback, j_callback_ref));
+
+  PageCriteria criteria;
+  criteria.offline_ids = std::move(offline_ids);
+  offline_page_model_->DeletePagesWithCriteria(
+      criteria, base::BindOnce(&DeletePageCallback, j_callback_ref));
 }
 
 void OfflinePageBridge::GetPagesByClientId(
@@ -590,8 +593,8 @@
   j_callback_ref.Reset(env, j_callback_obj);
 
   PageCriteria criteria;
-  criteria.client_namespaces.push_back(
-      ConvertJavaStringToUTF8(env, j_namespace));
+  criteria.client_namespaces =
+      std::vector<std::string>{ConvertJavaStringToUTF8(env, j_namespace)};
   offline_page_model_->GetPagesWithCriteria(
       criteria, base::BindOnce(&MultipleOfflinePageItemCallback, j_result_ref,
                                j_callback_ref));
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.h b/chrome/browser/offline_pages/android/offline_page_bridge.h
index 747bdfa..6920263 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.h
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.h
@@ -66,8 +66,7 @@
   void OfflinePageModelLoaded(OfflinePageModel* model) override;
   void OfflinePageAdded(OfflinePageModel* model,
                         const OfflinePageItem& added_page) override;
-  void OfflinePageDeleted(
-      const OfflinePageModel::DeletedPageInfo& page_info) override;
+  void OfflinePageDeleted(const OfflinePageItem& item) override;
 
   void GetAllPages(JNIEnv* env,
                    const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/offline_pages/android/offline_test_util_jni.cc b/chrome/browser/offline_pages/android/offline_test_util_jni.cc
index d300606c..683cf270 100644
--- a/chrome/browser/offline_pages/android/offline_test_util_jni.cc
+++ b/chrome/browser/offline_pages/android/offline_test_util_jni.cc
@@ -194,12 +194,15 @@
     const JavaParamRef<jlongArray>& j_offline_ids_array,
     const JavaParamRef<jobject>& j_callback_obj) {
   ScopedJavaGlobalRef<jobject> j_callback_ref(env, j_callback_obj);
+
   std::vector<int64_t> offline_ids;
   base::android::JavaLongArrayToInt64Vector(env, j_offline_ids_array,
                                             &offline_ids);
-  GetOfflinePageModel()->DeletePagesByOfflineId(
-      offline_ids,
-      base::BindOnce(&OnDeletePageDone, std::move(j_callback_ref)));
+
+  PageCriteria criteria;
+  criteria.offline_ids = std::move(offline_ids);
+  GetOfflinePageModel()->DeletePagesWithCriteria(
+      criteria, base::BindOnce(&OnDeletePageDone, std::move(j_callback_ref)));
 }
 
 JNI_EXPORT void JNI_OfflineTestUtil_StartRequestCoordinatorProcessing(
diff --git a/chrome/browser/offline_pages/background_loader_offliner.cc b/chrome/browser/offline_pages/background_loader_offliner.cc
index 598c44f..062759f707e 100644
--- a/chrome/browser/offline_pages/background_loader_offliner.cc
+++ b/chrome/browser/offline_pages/background_loader_offliner.cc
@@ -544,10 +544,10 @@
 
   if (save_state_ == DELETE_AFTER_SAVE) {
     // Delete the saved page off disk and from the OPM.
-    std::vector<int64_t> offline_ids;
-    offline_ids.push_back(offline_id);
-    offline_page_model_->DeletePagesByOfflineId(
-        offline_ids,
+    PageCriteria criteria;
+    criteria.offline_ids = std::vector<int64_t>{offline_id};
+    offline_page_model_->DeletePagesWithCriteria(
+        criteria,
         base::Bind(&BackgroundLoaderOffliner::DeleteOfflinePageCallback,
                    weak_ptr_factory_.GetWeakPtr(), request));
     save_state_ = NONE;
diff --git a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
index 21c54cb..cdd299a1 100644
--- a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
+++ b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
@@ -104,8 +104,8 @@
                                   SavePageResult::ALREADY_EXISTS, 123456));
   }
 
-  void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
-                              DeletePageCallback callback) override {
+  void DeletePagesWithCriteria(const PageCriteria& criteria,
+                               DeletePageCallback callback) override {
     mock_deleting_ = true;
     std::move(callback).Run(DeletePageResult::SUCCESS);
   }
diff --git a/chrome/browser/offline_pages/fresh_offline_content_observer.cc b/chrome/browser/offline_pages/fresh_offline_content_observer.cc
index 876b73d..39feb93 100644
--- a/chrome/browser/offline_pages/fresh_offline_content_observer.cc
+++ b/chrome/browser/offline_pages/fresh_offline_content_observer.cc
@@ -43,6 +43,6 @@
 }
 
 void FreshOfflineContentObserver::OfflinePageDeleted(
-    const OfflinePageModel::DeletedPageInfo& page_info) {}
+    const OfflinePageItem& item) {}
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/fresh_offline_content_observer.h b/chrome/browser/offline_pages/fresh_offline_content_observer.h
index ec6d2e4..b31c0b0 100644
--- a/chrome/browser/offline_pages/fresh_offline_content_observer.h
+++ b/chrome/browser/offline_pages/fresh_offline_content_observer.h
@@ -25,8 +25,7 @@
   void OfflinePageModelLoaded(OfflinePageModel* model) override;
   void OfflinePageAdded(OfflinePageModel* model,
                         const OfflinePageItem& added_page) override;
-  void OfflinePageDeleted(
-      const OfflinePageModel::DeletedPageInfo& page_info) override;
+  void OfflinePageDeleted(const OfflinePageItem& item) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FreshOfflineContentObserver);
diff --git a/chrome/browser/offline_pages/offline_page_bookmark_observer.cc b/chrome/browser/offline_pages/offline_page_bookmark_observer.cc
index 9773160b..e673d74 100644
--- a/chrome/browser/offline_pages/offline_page_bookmark_observer.cc
+++ b/chrome/browser/offline_pages/offline_page_bookmark_observer.cc
@@ -42,8 +42,10 @@
 
 void OfflinePageBookmarkObserver::DoDeleteRemovedBookmarkPages(
     const MultipleOfflineIdResult& offline_ids) {
-  offline_page_model_->DeletePagesByOfflineId(
-      offline_ids,
+  PageCriteria criteria;
+  criteria.offline_ids = offline_ids;
+  offline_page_model_->DeletePagesWithCriteria(
+      criteria,
       base::Bind(&OfflinePageBookmarkObserver::OnDeleteRemovedBookmarkPagesDone,
                  weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/offline_pages/recent_tab_helper.cc b/chrome/browser/offline_pages/recent_tab_helper.cc
index 19a8127..a7684f9 100644
--- a/chrome/browser/offline_pages/recent_tab_helper.cc
+++ b/chrome/browser/offline_pages/recent_tab_helper.cc
@@ -229,8 +229,10 @@
            last_n_latest_saved_snapshot_info_->request_id)) {
     DVLOG(1) << " - Deleting previous last_n snapshot with offline_id "
              << last_n_latest_saved_snapshot_info_->request_id;
-    std::vector<int64_t> id{last_n_latest_saved_snapshot_info_->request_id};
-    page_model_->DeletePagesByOfflineId(id, DeletePageCallback());
+    PageCriteria criteria;
+    criteria.offline_ids =
+        std::vector<int64_t>{last_n_latest_saved_snapshot_info_->request_id};
+    page_model_->DeletePagesWithCriteria(criteria, base::DoNothing());
     last_n_latest_saved_snapshot_info_.reset();
   }
 
@@ -446,9 +448,11 @@
 
   DVLOG_IF(1, !page_ids.empty()) << "Deleting " << page_ids.size()
                                  << " offline pages...";
-  page_model_->DeletePagesByOfflineId(
-      page_ids, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge,
-                           weak_ptr_factory_.GetWeakPtr(), snapshot_info));
+  PageCriteria criteria;
+  criteria.offline_ids = page_ids;
+  page_model_->DeletePagesWithCriteria(
+      criteria, base::BindOnce(&RecentTabHelper::ContinueSnapshotAfterPurge,
+                               weak_ptr_factory_.GetWeakPtr(), snapshot_info));
 }
 
 void RecentTabHelper::ContinueSnapshotAfterPurge(
diff --git a/chrome/browser/offline_pages/recent_tab_helper_unittest.cc b/chrome/browser/offline_pages/recent_tab_helper_unittest.cc
index ae6a2e8..21fd95c9 100644
--- a/chrome/browser/offline_pages/recent_tab_helper_unittest.cc
+++ b/chrome/browser/offline_pages/recent_tab_helper_unittest.cc
@@ -145,8 +145,7 @@
     page_added_count_++;
     all_pages_needs_updating_ = true;
   }
-  void OfflinePageDeleted(
-      const OfflinePageModel::DeletedPageInfo& pageInfo) override {
+  void OfflinePageDeleted(const OfflinePageItem& item) override {
     model_removed_count_++;
     all_pages_needs_updating_ = true;
   }
diff --git a/chrome/browser/previews/previews_offline_helper.cc b/chrome/browser/previews/previews_offline_helper.cc
index 977b2bd..83e183f 100644
--- a/chrome/browser/previews/previews_offline_helper.cc
+++ b/chrome/browser/previews/previews_offline_helper.cc
@@ -201,11 +201,11 @@
 }
 
 void PreviewsOfflineHelper::OfflinePageDeleted(
-    const offline_pages::OfflinePageModel::DeletedPageInfo& page_info) {
+    const offline_pages::OfflinePageItem& deleted_page) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Has no effect if the url was never in the dictionary.
-  available_pages_->RemoveKey(HashURL(page_info.url));
+  available_pages_->RemoveKey(HashURL(deleted_page.url));
 
   RemoveStaleOfflinePageEntries(available_pages_.get());
   UpdatePref();
diff --git a/chrome/browser/previews/previews_offline_helper.h b/chrome/browser/previews/previews_offline_helper.h
index 16f7a9a..4b0fe3c 100644
--- a/chrome/browser/previews/previews_offline_helper.h
+++ b/chrome/browser/previews/previews_offline_helper.h
@@ -46,8 +46,7 @@
       offline_pages::OfflinePageModel* model,
       const offline_pages::OfflinePageItem& added_page) override;
   void OfflinePageDeleted(
-      const offline_pages::OfflinePageModel::DeletedPageInfo& page_info)
-      override;
+      const offline_pages::OfflinePageItem& deleted_page) override;
 
   void SetPrefServiceForTesting(PrefService* pref_service) {
     pref_service_ = pref_service;
diff --git a/chrome/browser/previews/previews_offline_helper_unittest.cc b/chrome/browser/previews/previews_offline_helper_unittest.cc
index ccef8a87..89f1b55 100644
--- a/chrome/browser/previews/previews_offline_helper_unittest.cc
+++ b/chrome/browser/previews/previews_offline_helper_unittest.cc
@@ -40,11 +40,10 @@
     return item;
   }
 
-  offline_pages::OfflinePageModel::DeletedPageInfo MakeDeletedPageInfo(
-      const std::string& url) {
-    offline_pages::OfflinePageModel::DeletedPageInfo info;
-    info.url = GURL(url);
-    return info;
+  offline_pages::OfflinePageItem MakeDeletedPageItem(const std::string& url) {
+    offline_pages::OfflinePageItem item;
+    item.url = GURL(url);  // Only |url| is needed.
+    return item;
   }
 
  private:
@@ -201,7 +200,7 @@
           MakeAddedPageItem(fresh_page, test_case.original_url, fresh));
     }
     for (const std::string& deleted_page : test_case.delete_pages) {
-      helper->OfflinePageDeleted(MakeDeletedPageInfo(deleted_page));
+      helper->OfflinePageDeleted(MakeDeletedPageItem(deleted_page));
     }
 
     EXPECT_EQ(test_prefs.GetDictionary(kDictKey)->size(),
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index f30d26e..dffd3b6b 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -205,6 +205,20 @@
     ]
     output_dir = "$root_gen_dir/chrome"
   }
+
+  if (enable_kiosk_next && is_chrome_branded) {
+    grit("kiosk_next_internal_resources") {
+      source = "kiosk_next_internal_resources.grd"
+      defines = chrome_grit_defines
+      outputs = [
+        "grit/kiosk_next_internal_resources.h",
+        "grit/kiosk_next_internal_resources_map.cc",
+        "grit/kiosk_next_internal_resources_map.h",
+        "kiosk_next_internal_resources.pak",
+      ]
+      output_dir = "$root_gen_dir/chrome"
+    }
+  }
 }
 
 if (!is_android && !is_chromeos) {
diff --git a/chrome/browser/resources/chromeos/kiosk_next_home/bg_internal.js b/chrome/browser/resources/chromeos/kiosk_next_home/bg_internal.js
new file mode 100644
index 0000000..b2ab628
--- /dev/null
+++ b/chrome/browser/resources/chromeos/kiosk_next_home/bg_internal.js
@@ -0,0 +1,8 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.app.runtime.onLaunched.addListener(() => {
+  const windowOptions = {id: 'main', state: 'maximized', frame: 'none'};
+  chrome.app.window.create('internal/main.html', windowOptions);
+});
diff --git a/chrome/browser/resources/chromeos/kiosk_next_home/intent_config.json b/chrome/browser/resources/chromeos/kiosk_next_home/intent_config.json
deleted file mode 100644
index 83e966e3..0000000
--- a/chrome/browser/resources/chromeos/kiosk_next_home/intent_config.json
+++ /dev/null
@@ -1,5 +0,0 @@
-// TODO(brunoad): Remove when src-internal version is available.
-{
-  "allowed_hosts": [],
-  "allowed_custom_schemes": []
-}
diff --git a/chrome/browser/resources/chromeos/kiosk_next_home/kiosk_next_resources.grdp b/chrome/browser/resources/chromeos/kiosk_next_home/kiosk_next_resources.grdp
index e638415..2d95a48 100644
--- a/chrome/browser/resources/chromeos/kiosk_next_home/kiosk_next_resources.grdp
+++ b/chrome/browser/resources/chromeos/kiosk_next_home/kiosk_next_resources.grdp
@@ -1,10 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <grit-part>
-  <include name="IDR_KIOSK_NEXT_INTENT_CONFIG_JSON" file="chromeos/kiosk_next_home/intent_config.json" type="BINDATA" />
-  <include name="IDR_KIOSK_NEXT_BG_JS" file="chromeos/kiosk_next_home/bg.js" type="BINDATA" />
+  <if expr="_google_chrome">
+    <then>
+      <include name="IDR_KIOSK_NEXT_BG_JS" file="chromeos/kiosk_next_home/bg_internal.js" type="BINDATA" />
+      <include name="IDR_KIOSK_NEXT_MAIN_HTML" file="chromeos/kiosk_next_home/internal/main.html" type="chrome_html" />
+    </then>
+    <else>
+      <include name="IDR_KIOSK_NEXT_BG_JS" file="chromeos/kiosk_next_home/bg.js" type="BINDATA" />
+      <include name="IDR_KIOSK_NEXT_MAIN_HTML" file="chromeos/kiosk_next_home/main.html" type="chrome_html" />
+    </else>
+  </if>
   <include name="IDR_KIOSK_NEXT_ICON_192" file="chromeos/kiosk_next_home/static/icon192.png" type="BINDATA" />
-  <include name="IDR_KIOSK_NEXT_MAIN_HTML" file="chromeos/kiosk_next_home/main.html" type="chrome_html" />
   <include name="IDR_KIOSK_NEXT_API_JS" file="chromeos/kiosk_next_home/api.js" type="BINDATA" />
   <include name="IDR_KIOSK_NEXT_API_IMPL_JS" file="chromeos/kiosk_next_home/api_impl.js" type="BINDATA" />
   <include name="IDR_KIOSK_NEXT_HOME_MOJOM_JS" file="${root_gen_dir}/chrome/browser/resources/chromeos/kiosk_next_home/mojom_bin.js" type="BINDATA" use_base_dir="false" />
diff --git a/chrome/browser/resources/chromeos/kiosk_next_home/kiosk_next_resources_internal.grdp b/chrome/browser/resources/chromeos/kiosk_next_home/kiosk_next_resources_internal.grdp
deleted file mode 100644
index 5656207d..0000000
--- a/chrome/browser/resources/chromeos/kiosk_next_home/kiosk_next_resources_internal.grdp
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!-- TODO(brunoad): This list will be populated from src-internal -->
-<grit-part />
diff --git a/chrome/browser/resources/chromeos/kiosk_next_home/main.html b/chrome/browser/resources/chromeos/kiosk_next_home/main.html
index eeb6aa1..7721026 100644
--- a/chrome/browser/resources/chromeos/kiosk_next_home/main.html
+++ b/chrome/browser/resources/chromeos/kiosk_next_home/main.html
@@ -5,8 +5,5 @@
   <script src="api_impl.js"></script>
 </head>
 <body>
-  <div>
-    TODO(michaelpg): Remove this when the real files are available from
-    src-internal.
-  </div>
+  <div>Kiosk Next Home</div>
 </body>
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 1ca4281..f36b527 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -95,9 +95,6 @@
         <include name="IDR_ARC_SUPPORT_RECOMMEND_APP_LIST_VIEW_HTML" file="chromeos/arc_support/recommend_app_list_view.html" type="chrome_html" flattenhtml="true" />
         <if expr="_kiosk_next">
           <part file="chromeos/kiosk_next_home/kiosk_next_resources.grdp" />
-          <if expr="_google_chrome">
-            <part file="chromeos/kiosk_next_home/kiosk_next_resources_internal.grdp" />
-          </if>
         </if>
       </if>
       <if expr="enable_plugins">
diff --git a/chrome/browser/resources/kiosk_next_internal_resources.grd b/chrome/browser/resources/kiosk_next_internal_resources.grd
new file mode 100644
index 0000000..f90c89f
--- /dev/null
+++ b/chrome/browser/resources/kiosk_next_internal_resources.grd
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/kiosk_next_internal_resources.h" type="rc_header">
+      <emit emit_type='prepend'></emit>
+    </output>
+    <output filename="grit/kiosk_next_internal_resources_map.cc" type="gzipped_resource_file_map_source" />
+    <output filename="grit/kiosk_next_internal_resources_map.h" type="gzipped_resource_map_header" />
+    <output filename="kiosk_next_internal_resources.pak" type="data_package" />
+  </outputs>
+  <release seq="1">
+    <includes>
+      <part file="chromeos/kiosk_next_home/internal/kiosk_next_resources_internal.grdp" />
+    </includes>
+  </release>
+</grit>
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index 7f925b7..0014f22 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -69,10 +69,13 @@
   position: static;
   /* This align correctly for both LTR and RTL */
   text-align: -webkit-auto;
-  transition: opacity 300ms;
   user-select: none;
 }
 
+html:not(.no-initial-fade) :-webkit-any(#mv-tiles, .mv-tiles-old) {
+  transition: opacity 300ms;
+}
+
 .mv-tiles-old {
   left: 0;
   margin: auto;
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.html b/chrome/browser/resources/local_ntp/most_visited_single.html
index 2f7f9ae..08371ec 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.html
+++ b/chrome/browser/resources/local_ntp/most_visited_single.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html>
+<html class="$i18n{noInitialFade}">
 <!-- 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. -->
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index ca1da432..95613b2 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -60,6 +60,7 @@
   MD_TILE_INNER: 'md-tile-inner',
   MD_TITLE: 'md-title',
   MD_TITLE_CONTAINER: 'md-title-container',
+  NO_INITIAL_FADE: 'no-initial-fade',
 };
 
 
@@ -441,13 +442,20 @@
   // Prevent keyboard navigation to tiles that are not visible.
   updateTileVisibility();
 
+  const flushOpacity = () => window.getComputedStyle(cur).opacity;
+
   // getComputedStyle causes the initial style (opacity 0) to be applied, so
   // that when we then set it to 1, that triggers the CSS transition.
   if (fadeIn) {
-    const style = window.getComputedStyle(cur).opacity;
+    flushOpacity();
   }
   cur.style.opacity = 1.0;
 
+  if (document.documentElement.classList.contains(CLASSES.NO_INITIAL_FADE)) {
+    flushOpacity();
+    document.documentElement.classList.remove(CLASSES.NO_INITIAL_FADE);
+  }
+
   // Make sure the tiles variable contain the next tileset we'll use if the host
   // page sends us an updated set of tiles.
   tiles = document.createElement('div');
diff --git a/chrome/browser/search/iframe_source.cc b/chrome/browser/search/iframe_source.cc
index 10674fda..16669cc9 100644
--- a/chrome/browser/search/iframe_source.cc
+++ b/chrome/browser/search/iframe_source.cc
@@ -72,11 +72,15 @@
 
 void IframeSource::SendResource(
     int resource_id,
-    const content::URLDataSource::GotDataCallback& callback) {
-  scoped_refptr<base::RefCountedMemory> response(
-      ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
-          resource_id));
-  callback.Run(response.get());
+    const content::URLDataSource::GotDataCallback& callback,
+    const ui::TemplateReplacements* replacements) {
+  base::StringPiece resource =
+      ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id);
+  std::string response =
+      replacements != nullptr
+          ? ui::ReplaceTemplateExpressions(resource, *replacements)
+          : resource.as_string();
+  callback.Run(base::RefCountedString::TakeString(&response));
 }
 
 void IframeSource::SendJSWithOrigin(
diff --git a/chrome/browser/search/iframe_source.h b/chrome/browser/search/iframe_source.h
index 9e7d802a..fba0e60 100644
--- a/chrome/browser/search/iframe_source.h
+++ b/chrome/browser/search/iframe_source.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "content/public/browser/url_data_source.h"
+#include "ui/base/template_expressions.h"
 
 #if defined(OS_ANDROID)
 #error "Instant is only used on desktop";
@@ -34,9 +35,9 @@
   virtual bool ServesPath(const std::string& path) const = 0;
 
   // Sends unmodified resource bytes.
-  void SendResource(
-      int resource_id,
-      const content::URLDataSource::GotDataCallback& callback);
+  void SendResource(int resource_id,
+                    const content::URLDataSource::GotDataCallback& callback,
+                    const ui::TemplateReplacements* replacements = nullptr);
 
   // Sends Javascript with an expected postMessage origin interpolated.
   void SendJSWithOrigin(
diff --git a/chrome/browser/search/most_visited_iframe_source.cc b/chrome/browser/search/most_visited_iframe_source.cc
index 0e11847..b91a352 100644
--- a/chrome/browser/search/most_visited_iframe_source.cc
+++ b/chrome/browser/search/most_visited_iframe_source.cc
@@ -5,9 +5,11 @@
 #include "chrome/browser/search/most_visited_iframe_source.h"
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/memory/ref_counted_memory.h"
 #include "build/build_config.h"
 #include "chrome/browser/search/local_files_ntp_source.h"
+#include "chrome/browser/search/ntp_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/local_ntp_resources.h"
@@ -78,7 +80,11 @@
 #endif
 
   if (path == kSingleHTMLPath) {
-    SendResource(IDR_MOST_VISITED_SINGLE_HTML, callback);
+    ui::TemplateReplacements replacements;
+    bool disable_fade = base::FeatureList::IsEnabled(
+        features::kDisableInitialMostVisitedFadeIn);
+    replacements["noInitialFade"] = disable_fade ? "no-initial-fade" : "";
+    SendResource(IDR_MOST_VISITED_SINGLE_HTML, callback, &replacements);
   } else if (path == kSingleCSSPath) {
     SendResource(IDR_MOST_VISITED_SINGLE_CSS, callback);
   } else if (path == kSingleJSPath) {
diff --git a/chrome/browser/search/ntp_features.cc b/chrome/browser/search/ntp_features.cc
index eca0c71b..1b6929f 100644
--- a/chrome/browser/search/ntp_features.cc
+++ b/chrome/browser/search/ntp_features.cc
@@ -9,6 +9,10 @@
 
 namespace features {
 
+// If enabled, does not fade in most visited tiles on initial page load.
+const base::Feature kDisableInitialMostVisitedFadeIn{
+    "DisableInitialMostVisitedFadeIn", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // If enabled, the user will see the second version of the customization picker.
 const base::Feature kNtpCustomizationMenuV2{"NtpCustomizationMenuV2",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/search/ntp_features.h b/chrome/browser/search/ntp_features.h
index 215641e..3211ce94 100644
--- a/chrome/browser/search/ntp_features.h
+++ b/chrome/browser/search/ntp_features.h
@@ -12,6 +12,7 @@
 // The features should be documented alongside the definition of their values in
 // the .cc file.
 
+extern const base::Feature kDisableInitialMostVisitedFadeIn;
 extern const base::Feature kNtpCustomizationMenuV2;
 extern const base::Feature kRemoveNtpFakebox;
 
diff --git a/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.cc b/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.cc
index 93906ca..49b0c89e 100644
--- a/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.cc
+++ b/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.cc
@@ -31,7 +31,13 @@
     SyncSessionsWebContentsRouter* router)
     : content::WebContentsObserver(web_contents),
       router_(router),
-      source_tab_id_(SessionID::InvalidValue()) {}
+      source_tab_id_(SessionID::InvalidValue()) {
+  chrome_translate_client_ =
+      ChromeTranslateClient::FromWebContents(web_contents);
+  // A translate client is not always attached to web contents (e.g. tests).
+  if (chrome_translate_client_)
+    chrome_translate_client_->translate_driver().AddObserver(this);
+}
 
 SyncSessionsRouterTabHelper::~SyncSessionsRouterTabHelper() {}
 
@@ -47,6 +53,8 @@
 
 void SyncSessionsRouterTabHelper::WebContentsDestroyed() {
   NotifyRouter();
+  if (chrome_translate_client_)
+    chrome_translate_client_->translate_driver().RemoveObserver(this);
 }
 
 void SyncSessionsRouterTabHelper::DidFinishLoad(
@@ -70,6 +78,12 @@
   SetSourceTabIdForChild(new_contents);
 }
 
+void SyncSessionsRouterTabHelper::OnLanguageDetermined(
+    const translate::LanguageDetectionDetails& details) {
+  // TODO (crbug.com/957657): NotifyRouter() when language is synced on
+  // notification.
+}
+
 void SyncSessionsRouterTabHelper::SetSourceTabIdForChild(
     content::WebContents* child_contents) {
   SessionID source_tab_id = SessionTabHelper::IdForTab(web_contents());
diff --git a/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h b/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h
index a10d18d..93756a4 100644
--- a/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h
+++ b/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h
@@ -5,7 +5,9 @@
 #ifndef CHROME_BROWSER_SYNC_SESSIONS_SYNC_SESSIONS_ROUTER_TAB_HELPER_H_
 #define CHROME_BROWSER_SYNC_SESSIONS_SYNC_SESSIONS_ROUTER_TAB_HELPER_H_
 
+#include "chrome/browser/translate/chrome_translate_client.h"
 #include "components/sessions/core/session_id.h"
+#include "components/translate/content/browser/content_translate_driver.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
@@ -22,7 +24,8 @@
 // https://chromium.googlesource.com/chromium/src/+/master/docs/tab_helpers.md
 class SyncSessionsRouterTabHelper
     : public content::WebContentsUserData<SyncSessionsRouterTabHelper>,
-      public content::WebContentsObserver {
+      public content::WebContentsObserver,
+      public translate::ContentTranslateDriver::Observer {
  public:
   ~SyncSessionsRouterTabHelper() override;
 
@@ -46,6 +49,10 @@
                            bool started_from_context_menu,
                            bool renderer_initiated) override;
 
+  // ContentTranslateDriver::Observer implementation.
+  void OnLanguageDetermined(
+      const translate::LanguageDetectionDetails& details) override;
+
   // Sets the source tab id for the given child WebContents to the id of the
   // WebContents that owns this helper.
   void SetSourceTabIdForChild(content::WebContents* child_contents);
@@ -76,6 +83,8 @@
   // * Click on a link with target='_blank'.
   SessionID source_tab_id_;
 
+  ChromeTranslateClient* chrome_translate_client_;
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 
   DISALLOW_COPY_AND_ASSIGN(SyncSessionsRouterTabHelper);
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc
index d451b6c..49d6df3 100644
--- a/chrome/browser/translate/chrome_translate_client.cc
+++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -41,8 +41,6 @@
 #include "components/translate/core/browser/translate_manager.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/common/language_detection_details.h"
-#include "components/translate/core/common/language_detection_logging_helper.h"
-#include "components/translate/core/common/translation_logging_helper.h"
 #include "components/variations/service/variations_service.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/ui/ash/login_screen_client.cc b/chrome/browser/ui/ash/login_screen_client.cc
index 246cbe4a..03eded8 100644
--- a/chrome/browser/ui/ash/login_screen_client.cc
+++ b/chrome/browser/ui/ash/login_screen_client.cc
@@ -8,6 +8,7 @@
 
 #include "ash/public/interfaces/constants.mojom.h"
 #include "base/bind.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/help_app_launcher.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
@@ -68,11 +69,6 @@
   delegate_ = delegate;
 }
 
-void LoginScreenClient::SetParentAccessDelegate(
-    ParentAccessDelegate* delegate) {
-  parent_access_delegate_ = delegate;
-}
-
 void LoginScreenClient::AddSystemTrayFocusObserver(
     ash::SystemTrayFocusObserver* observer) {
   system_tray_focus_observers_.AddObserver(observer);
@@ -145,13 +141,9 @@
     const AccountId& account_id,
     const std::string& access_code,
     ValidateParentAccessCodeCallback callback) {
-  if (!parent_access_delegate_) {
-    LOG(ERROR) << "Cannot validate parent access code - no delegate";
-    std::move(callback).Run(false);
-    return;
-  }
-  parent_access_delegate_->ValidateParentAccessCode(access_code,
-                                                    std::move(callback));
+  bool result = chromeos::parent_access::ParentAccessService::Get()
+                    .ValidateParentAccessCode(account_id, access_code);
+  std::move(callback).Run(result);
 }
 
 void LoginScreenClient::HardlockPod(const AccountId& account_id) {
diff --git a/chrome/browser/ui/ash/login_screen_client.h b/chrome/browser/ui/ash/login_screen_client.h
index ac6c5d8..ab184798 100644
--- a/chrome/browser/ui/ash/login_screen_client.h
+++ b/chrome/browser/ui/ash/login_screen_client.h
@@ -80,10 +80,6 @@
   // Set the object which will handle calls coming from ash.
   void SetDelegate(Delegate* delegate);
 
-  // Set the object which will handle parent access related calls coming from
-  // ash.
-  void SetParentAccessDelegate(ParentAccessDelegate* delegate);
-
   // Returns an object which can be used to make calls to ash.
   ash::mojom::LoginScreenPtr& login_screen();
 
@@ -148,7 +144,6 @@
   // Binds this object to the client interface.
   mojo::Binding<ash::mojom::LoginScreenClient> binding_;
   Delegate* delegate_ = nullptr;
-  ParentAccessDelegate* parent_access_delegate_ = nullptr;
 
   // Captures authentication related user metrics for login screen.
   std::unique_ptr<chromeos::LoginAuthRecorder> auth_recorder_;
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
index e302c690..fff0134 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -30,7 +30,6 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
-#include "chrome/browser/chromeos/accessibility/ax_host_service.h"
 #include "ui/base/ui_base_features.h"
 #endif
 
@@ -71,18 +70,12 @@
         SendEvent(focus, ax::mojom::Event::kChildrenChanged);
     }
   }
-  // Gain access to out-of-process native windows.
-  AXHostService::SetAutomationEnabled(true);
 #endif
 }
 
 void AutomationManagerAura::Disable() {
   enabled_ = false;
   Reset(true);
-
-#if defined(OS_CHROMEOS)
-  AXHostService::SetAutomationEnabled(false);
-#endif
 }
 
 void AutomationManagerAura::OnViewEvent(views::View* view,
diff --git a/chrome/browser/ui/signin_view_controller.cc b/chrome/browser/ui/signin_view_controller.cc
index 0744937..59f0685 100644
--- a/chrome/browser/ui/signin_view_controller.cc
+++ b/chrome/browser/ui/signin_view_controller.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/web_contents.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/google_api_keys.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "url/url_constants.h"
 
@@ -179,9 +180,29 @@
     const std::string& email_hint,
     const GURL& redirect_url) {
   Profile* profile = browser->profile();
-  DCHECK(signin::DiceMethodGreaterOrEqual(
-      AccountConsistencyModeManager::GetMethodForProfile(profile),
-      signin::AccountConsistencyMethod::kDiceMigration));
+
+#if DCHECK_IS_ON()
+  if (!signin::DiceMethodGreaterOrEqual(
+          AccountConsistencyModeManager::GetMethodForProfile(profile),
+          signin::AccountConsistencyMethod::kDiceMigration)) {
+    // Developers often fall into the trap of not configuring the OAuth client
+    // ID and client secret and then attempt to sign in to Chromium, which
+    // fail as the account consistency is disabled. Explicitly check that the
+    // OAuth client ID are configured when developers attempt to sign in to
+    // Chromium.
+    DCHECK(google_apis::HasOAuthClientConfigured())
+        << "You must configure the OAuth client ID and client secret in order "
+           "to sign in to Chromium. See instruction at "
+           "https://www.chromium.org/developers/how-tos/api-keys";
+
+    // Account consistency mode does not support signing in to Chrome due to
+    // some other unexpected reason. Signing in to Chrome is not supported.
+    NOTREACHED()
+        << "OAuth client ID and client secret is configured, but "
+           "the account consistency mode does not support signing in to "
+           "Chromium.";
+  }
+#endif
 
   // If redirect_url is empty, we would like to redirect to the NTP, but it's
   // not possible through the continue_url, because Gaia cannot redirect to
diff --git a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
index 33456f7..8ef3802 100644
--- a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
@@ -325,7 +325,7 @@
 
 void CardUnmaskPromptViews::OnPerformAction(views::Combobox* combobox) {
   if (ExpirationDateIsValid()) {
-    if (month_input_->invalid()) {
+    if (month_input_->GetInvalid()) {
       month_input_->SetInvalid(false);
       year_input_->SetInvalid(false);
       SetRetriableErrorMessage(base::string16());
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
index bcad029..0676d8b2 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
@@ -403,7 +403,7 @@
   if (IsEditingServerCard()) {
     views::Combobox* address_combobox = static_cast<views::Combobox*>(
         dialog()->GetViewByID(GetInputFieldViewId(kBillingAddressType)));
-    if (address_combobox->invalid())
+    if (address_combobox->GetInvalid())
       return false;
 
     autofill::AddressComboboxModel* model =
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
index bf8436ef..61fe9c1 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
@@ -852,7 +852,7 @@
       dialog_view()->GetViewByID(EditorViewController::GetInputFieldViewId(
           autofill::ADDRESS_BILLING_LINE1)));
   ASSERT_NE(nullptr, billing_combobox);
-  EXPECT_FALSE(billing_combobox->invalid());
+  EXPECT_FALSE(billing_combobox->GetInvalid());
   EXPECT_TRUE(billing_combobox->enabled());
 
   // And then save credit card state and come back to payment sheet.
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
index 44745f3..8a982c4 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -755,7 +755,7 @@
       static_cast<ValidatingCombobox*>(delegate_->dialog_view()->GetViewByID(
           EditorViewController::GetInputFieldViewId(type)));
   DCHECK(combobox);
-  return combobox->invalid();
+  return combobox->GetInvalid();
 }
 
 bool PaymentRequestBrowserTestBase::IsPayButtonEnabled() {
diff --git a/chrome/browser/ui/webui/about_ui_unittest.cc b/chrome/browser/ui/webui/about_ui_unittest.cc
index a1235e0..301e194 100644
--- a/chrome/browser/ui/webui/about_ui_unittest.cc
+++ b/chrome/browser/ui/webui/about_ui_unittest.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h"
 #include "chrome/browser/chromeos/login/ui/fake_login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/scoped_browser_locale.h"
@@ -179,7 +180,7 @@
     fake_login_display_host_ =
         std::make_unique<chromeos::FakeLoginDisplayHost>();
     fake_login_display_host_->StartWizard(
-        chromeos::OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
+        chromeos::DemoPreferencesScreenView::kScreenId);
     fake_login_display_host_->GetWizardController()
         ->SimulateDemoModeSetupForTesting();
     fake_login_display_host_->GetWizardController()
diff --git a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h
index 8634d27..71d5798 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h
@@ -14,8 +14,7 @@
 
 class AppDownloadingScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_APP_DOWNLOADING;
+  constexpr static StaticOobeScreenId kScreenId{"app-downloading"};
 
   virtual ~AppDownloadingScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
index 9865a343..60b082d3 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/chromeos/login/app_launch_controller.h"
 #include "chrome/browser/chromeos/login/oobe_screen.h"
 #include "chrome/browser/chromeos/login/screens/network_error.h"
+#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/chromium_strings.h"
@@ -182,7 +183,7 @@
       break;
   }
 
-  if (GetCurrentScreen() != OobeScreen::SCREEN_ERROR_MESSAGE)
+  if (GetCurrentScreen() != ErrorScreenView::kScreenId)
     error_screen_->SetParentScreen(kScreenId);
   error_screen_->Show();
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h
index 814a6fd..b1a6143 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h
@@ -28,8 +28,7 @@
     APP_LAUNCH_STATE_SHOWING_NETWORK_CONFIGURE_UI,
   };
 
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_APP_LAUNCH_SPLASH;
+  constexpr static StaticOobeScreenId kScreenId{"app-launch-splash"};
 
   virtual ~AppLaunchSplashScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h
index 0f86eca4..2eccabc7 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h
@@ -27,8 +27,7 @@
     WAITING_APP_WINDOW,
   };
 
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_ARC_KIOSK_SPLASH;
+  constexpr static StaticOobeScreenId kScreenId{"arc-kiosk-splash"};
 
   ArcKioskSplashScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
index 1cad4778..ed3ec96 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/network/network_handler.h"
@@ -89,7 +90,7 @@
 void ArcTermsOfServiceScreenHandler::OnCurrentScreenChanged(
     OobeScreenId current_screen,
     OobeScreenId new_screen) {
-  if (new_screen != OobeScreen::SCREEN_GAIA_SIGNIN)
+  if (new_screen != GaiaView::kScreenId)
     return;
 
   MaybeLoadPlayStoreToS(false);
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h
index d6bed17a..02a0cb49 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h
@@ -47,8 +47,7 @@
 
 class ArcTermsOfServiceScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE;
+  constexpr static StaticOobeScreenId kScreenId{"arc-tos"};
 
   virtual ~ArcTermsOfServiceScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
index 5e5353f..a21bc5f0 100644
--- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
@@ -23,8 +23,7 @@
 // and its WebUI representation.
 class AssistantOptInFlowScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW;
+  constexpr static StaticOobeScreenId kScreenId{"assistant-optin-flow"};
 
   virtual ~AssistantOptInFlowScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index ca429de..15dc59b 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -34,7 +34,10 @@
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_constants.h"
@@ -75,11 +78,10 @@
   WizardController* const wizard_controller =
       WizardController::default_controller();
   if (wizard_controller && !wizard_controller->login_screen_started()) {
-    wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_RESET);
+    wizard_controller->AdvanceToScreen(ResetView::kScreenId);
   } else {
     DCHECK(LoginDisplayHost::default_host());
-    LoginDisplayHost::default_host()->StartWizard(
-        OobeScreen::SCREEN_OOBE_RESET);
+    LoginDisplayHost::default_host()->StartWizard(ResetView::kScreenId);
   }
 }
 
@@ -246,8 +248,7 @@
   // Don't recreate WizardController if it already exists.
   WizardController* wizard_controller = WizardController::default_controller();
   if (wizard_controller && !wizard_controller->login_screen_started()) {
-    wizard_controller->AdvanceToScreen(
-        OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING);
+    wizard_controller->AdvanceToScreen(EnableDebuggingScreenView::kScreenId);
   }
 }
 
@@ -329,7 +330,7 @@
   connection->GetConnector()->BindInterface(ash::mojom::kServiceName,
                                             &event_rewriter_controller_ptr);
   event_rewriter_controller_ptr->SetArrowToTabRewritingEnabled(
-      screen == OobeScreen::SCREEN_OOBE_EULA);
+      screen == EulaView::kScreenId);
 }
 
 void CoreOobeHandler::HandleEnableHighContrast(bool enabled) {
@@ -659,7 +660,7 @@
   WizardController* wizard_controller = WizardController::default_controller();
   if (wizard_controller && !wizard_controller->login_screen_started()) {
     wizard_controller->SimulateDemoModeSetupForTesting(config);
-    wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
+    wizard_controller->AdvanceToScreen(DemoSetupScreenView::kScreenId);
   }
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h
index 59f453f..f3a8227 100644
--- a/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h
@@ -16,8 +16,7 @@
 // Interface of the demo mode preferences screen view.
 class DemoPreferencesScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES;
+  constexpr static StaticOobeScreenId kScreenId{"demo-preferences"};
 
   virtual ~DemoPreferencesScreenView();
 
diff --git a/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h
index 77e9095..5362c7c 100644
--- a/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h
@@ -15,8 +15,7 @@
 // Interface of the demo mode setup screen view.
 class DemoSetupScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_OOBE_DEMO_SETUP;
+  constexpr static StaticOobeScreenId kScreenId{"demo-setup"};
 
   virtual ~DemoSetupScreenView();
 
diff --git a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
index 15760661..1cb75a48 100644
--- a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
@@ -15,8 +15,7 @@
 // Interface between the device disabled screen and its representation.
 class DeviceDisabledScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_DEVICE_DISABLED;
+  constexpr static StaticOobeScreenId kScreenId{"device-disabled"};
 
   virtual ~DeviceDisabledScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h
index 8510831..7f074ec 100644
--- a/chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h
@@ -17,7 +17,7 @@
 // WebUI representation.
 class DiscoverScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId = OobeScreen::SCREEN_DISCOVER;
+  constexpr static StaticOobeScreenId kScreenId{"discover"};
 
   virtual ~DiscoverScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
index 9664897d..aaa881d 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
@@ -22,8 +22,7 @@
 // Note, do not forget to call OnViewDestroyed in the dtor.
 class EnableDebuggingScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING;
+  constexpr static StaticOobeScreenId kScreenId{"debugging"};
 
   virtual ~EnableDebuggingScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
index cdfafacc..4661fce4 100644
--- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
@@ -37,8 +37,7 @@
   using ContinueLoginCallback = base::OnceCallback<void(const UserContext&)>;
   using RestartLoginCallback = base::OnceCallback<void(const UserContext&)>;
 
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_ENCRYPTION_MIGRATION;
+  constexpr static StaticOobeScreenId kScreenId{"encryption-migration"};
 
   virtual ~EncryptionMigrationScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index c8065702..f94c267 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
 #include "chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
@@ -627,7 +628,7 @@
 }
 
 bool EnrollmentScreenHandler::IsEnrollmentScreenHiddenByError() const {
-  return (GetCurrentScreen() == OobeScreen::SCREEN_ERROR_MESSAGE &&
+  return (GetCurrentScreen() == ErrorScreenView::kScreenId &&
           error_screen_->GetParentScreen() == kScreenId);
 }
 
@@ -735,7 +736,7 @@
                                  std::string());
   }
 
-  if (GetCurrentScreen() != OobeScreen::SCREEN_ERROR_MESSAGE) {
+  if (GetCurrentScreen() != ErrorScreenView::kScreenId) {
     error_screen_->SetUIState(NetworkError::UI_STATE_SIGNIN);
     error_screen_->SetParentScreen(kScreenId);
     error_screen_->SetHideCallback(base::Bind(&EnrollmentScreenHandler::DoShow,
@@ -926,7 +927,7 @@
   const bool cfm = policy_manager && policy_manager->IsRemoraRequisition();
   screen_data.SetString("flow", cfm ? "cfm" : "enterprise");
 
-  ShowScreenWithData(OobeScreen::SCREEN_OOBE_ENROLLMENT, &screen_data);
+  ShowScreenWithData(EnrollmentScreenView::kScreenId, &screen_data);
   if (first_show_) {
     first_show_ = false;
     UpdateStateInternal(NetworkError::ERROR_REASON_UPDATE, true);
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h
index 9db0b684..67a2695 100644
--- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h
@@ -17,8 +17,7 @@
 // representation. Owned by ErrorScreen.
 class ErrorScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_ERROR_MESSAGE;
+  constexpr static StaticOobeScreenId kScreenId{"error-message"};
 
   virtual ~ErrorScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
index e6aea40f..395a459 100644
--- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
@@ -27,7 +27,7 @@
 // dtor.
 class EulaView {
  public:
-  constexpr static StaticOobeScreenId kScreenId = OobeScreen::SCREEN_OOBE_EULA;
+  constexpr static StaticOobeScreenId kScreenId{"eula"};
 
   virtual ~EulaView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h
index c13329e..8eef6b97 100644
--- a/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h
@@ -18,8 +18,7 @@
 // WebUI representation.
 class FingerprintSetupScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_FINGERPRINT_SETUP;
+  constexpr static StaticOobeScreenId kScreenId{"fingerprint-setup"};
 
   virtual ~FingerprintSetupScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
index b5d2ba0..2b5a197 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -36,8 +36,7 @@
 
 class GaiaView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_GAIA_SIGNIN;
+  constexpr static StaticOobeScreenId kScreenId{"gaia-signin"};
 
   GaiaView() = default;
   virtual ~GaiaView() = default;
diff --git a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
index 55d60aa4..a731413 100644
--- a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
@@ -24,8 +24,7 @@
 // dtor.
 class HIDDetectionView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_OOBE_HID_DETECTION;
+  constexpr static StaticOobeScreenId kScreenId{"hid-detection"};
 
   virtual ~HIDDetectionView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
index 11ad4ab0..4b296b9 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
@@ -19,8 +19,7 @@
 // Note, do not forget to call OnViewDestroyed in the dtor.
 class KioskAutolaunchScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_KIOSK_AUTOLAUNCH;
+  constexpr static StaticOobeScreenId kScreenId{"autolaunch"};
 
   virtual ~KioskAutolaunchScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
index ca852c8..7e7a8de 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
@@ -19,8 +19,7 @@
 // Note, do not forget to call OnViewDestroyed in the dtor.
 class KioskEnableScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_KIOSK_ENABLE;
+  constexpr static StaticOobeScreenId kScreenId{"kiosk-enable"};
 
   virtual ~KioskEnableScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
index bf08657..e7310c4 100644
--- a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
@@ -16,8 +16,7 @@
 // WebUI representation.
 class MarketingOptInScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_MARKETING_OPT_IN;
+  constexpr static StaticOobeScreenId kScreenId{"marketing-opt-in"};
 
   virtual ~MarketingOptInScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h
index bd11dc7..e132f7f 100644
--- a/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h
@@ -16,8 +16,7 @@
 // WebUI representation.
 class MultiDeviceSetupScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_MULTIDEVICE_SETUP;
+  constexpr static StaticOobeScreenId kScreenId{"multidevice-setup"};
 
   virtual ~MultiDeviceSetupScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.h
index 5a7c8d0..72467e9c 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.h
@@ -17,8 +17,7 @@
 // Interface of network screen. Owned by NetworkScreen.
 class NetworkScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_OOBE_NETWORK;
+  constexpr static StaticOobeScreenId kScreenId{"network-selection"};
 
   virtual ~NetworkScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
index 2f7231b..268ad8c 100644
--- a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
@@ -18,8 +18,7 @@
 // WebUI representation.
 class RecommendAppsScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_RECOMMEND_APPS;
+  constexpr static StaticOobeScreenId kScreenId{"recommend-apps"};
 
   virtual ~RecommendAppsScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
index 3c820bb..cdab74d6 100644
--- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
@@ -19,7 +19,7 @@
 // representation, either views based or WebUI.
 class ResetView {
  public:
-  constexpr static StaticOobeScreenId kScreenId = OobeScreen::SCREEN_OOBE_RESET;
+  constexpr static StaticOobeScreenId kScreenId{"reset"};
 
   virtual ~ResetView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index b25784e..5c8abd4 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -189,7 +189,7 @@
 }
 
 bool IsSigninScreen(const OobeScreenId screen) {
-  return screen == OobeScreen::SCREEN_GAIA_SIGNIN ||
+  return screen == GaiaView::kScreenId ||
          screen == OobeScreen::SCREEN_ACCOUNT_PICKER;
 }
 
@@ -569,7 +569,7 @@
   switch (ui_state) {
     case UI_STATE_GAIA_SIGNIN:
       ui_state_ = UI_STATE_GAIA_SIGNIN;
-      ShowScreen(OobeScreen::SCREEN_GAIA_SIGNIN);
+      ShowScreen(GaiaView::kScreenId);
       break;
     case UI_STATE_ACCOUNT_PICKER:
       ui_state_ = UI_STATE_ACCOUNT_PICKER;
@@ -770,9 +770,9 @@
   error_screen_->AllowGuestSignin(guest_signin_allowed);
   error_screen_->AllowOfflineLogin(offline_login_allowed);
 
-  if (GetCurrentScreen() != OobeScreen::SCREEN_ERROR_MESSAGE) {
+  if (GetCurrentScreen() != ErrorScreenView::kScreenId) {
     error_screen_->SetUIState(NetworkError::UI_STATE_SIGNIN);
-    error_screen_->SetParentScreen(OobeScreen::SCREEN_GAIA_SIGNIN);
+    error_screen_->SetParentScreen(GaiaView::kScreenId);
     error_screen_->Show();
     histogram_helper_->OnErrorShow(error_screen_->GetErrorState());
   }
@@ -1446,7 +1446,7 @@
 }
 
 bool SigninScreenHandler::IsSigninScreenHiddenByError() const {
-  return (GetCurrentScreen() == OobeScreen::SCREEN_ERROR_MESSAGE) &&
+  return (GetCurrentScreen() == ErrorScreenView::kScreenId) &&
          (IsSigninScreen(error_screen_->GetParentScreen()));
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h
index 5796eb1c..3dca4ba 100644
--- a/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h
@@ -23,8 +23,7 @@
 // and its WebUI representation.
 class SupervisionTransitionScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_SUPERVISION_TRANSITION;
+  constexpr static StaticOobeScreenId kScreenId{"supervision-transition"};
 
   virtual ~SupervisionTransitionScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
index a90acd5..31cd5b7 100644
--- a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
@@ -18,8 +18,7 @@
 // WebUI representation.
 class SyncConsentScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_SYNC_CONSENT;
+  constexpr static StaticOobeScreenId kScreenId{"sync-consent"};
 
   virtual ~SyncConsentScreenView() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
index 616b58c..06e6b91 100644
--- a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
@@ -21,8 +21,7 @@
 // WebUI representation.
 class TermsOfServiceScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_TERMS_OF_SERVICE;
+  constexpr static StaticOobeScreenId kScreenId{"terms-of-service"};
 
   virtual ~TermsOfServiceScreenView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
index c188346..7a19433 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
@@ -21,8 +21,7 @@
 
 class UpdateRequiredView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_UPDATE_REQUIRED;
+  constexpr static StaticOobeScreenId kScreenId{"update-required"};
 
   virtual ~UpdateRequiredView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
index d12758e..be45877 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
@@ -19,8 +19,7 @@
 // representation. Owned by UpdateScreen.
 class UpdateView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_OOBE_UPDATE;
+  constexpr static StaticOobeScreenId kScreenId{"update"};
 
   virtual ~UpdateView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
index efecb62..437027a 100644
--- a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
@@ -23,8 +23,7 @@
 // Interface for WelcomeScreenHandler.
 class WelcomeView {
  public:
-  constexpr static StaticOobeScreenId kScreenId =
-      OobeScreen::SCREEN_OOBE_WELCOME;
+  constexpr static StaticOobeScreenId kScreenId{"connect"};
 
   virtual ~WelcomeView() {}
 
diff --git a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
index 73ebaa4..11ab991 100644
--- a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
@@ -18,7 +18,7 @@
 // Note, do not forget to call OnViewDestroyed in the dtor.
 class WrongHWIDScreenView {
  public:
-  constexpr static StaticOobeScreenId kScreenId = OobeScreen::SCREEN_WRONG_HWID;
+  constexpr static StaticOobeScreenId kScreenId{"wrong-hwid"};
 
   virtual ~WrongHWIDScreenView() {}
 
diff --git a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
index e729a9b..7802d7201 100644
--- a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
+++ b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
@@ -93,10 +93,10 @@
   std::string callback_id;
   CHECK(args->GetString(0, &callback_id));
 
-  std::vector<int64_t> offline_ids;
   const base::ListValue* offline_ids_from_arg;
   args->GetList(1, &offline_ids_from_arg);
 
+  std::vector<int64_t> offline_ids;
   for (size_t i = 0; i < offline_ids_from_arg->GetSize(); i++) {
     std::string value;
     offline_ids_from_arg->GetString(i, &value);
@@ -105,8 +105,10 @@
     offline_ids.push_back(int_value);
   }
 
-  offline_page_model_->DeletePagesByOfflineId(
-      offline_ids,
+  offline_pages::PageCriteria criteria;
+  criteria.offline_ids = std::move(offline_ids);
+  offline_page_model_->DeletePagesWithCriteria(
+      criteria,
       base::Bind(&OfflineInternalsUIMessageHandler::HandleDeletedPagesCallback,
                  weak_ptr_factory_.GetWeakPtr(), callback_id));
 }
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index 0c5a1e9bb..8d55e88 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -125,7 +125,7 @@
     virtual void OnCancelRequest() {}
   };
 
-  AuthenticatorRequestDialogModel(const std::string& relying_party_id);
+  explicit AuthenticatorRequestDialogModel(const std::string& relying_party_id);
   ~AuthenticatorRequestDialogModel();
 
   void SetCurrentStep(Step step);
diff --git a/chrome/chrome_cleaner/os/system_util_cleaner.h b/chrome/chrome_cleaner/os/system_util_cleaner.h
index 13dbacb..e8d7d14 100644
--- a/chrome/chrome_cleaner/os/system_util_cleaner.h
+++ b/chrome/chrome_cleaner/os/system_util_cleaner.h
@@ -32,12 +32,6 @@
 // @returns true if the current process is running elevated.
 bool HasAdminRights();
 
-// Check whether the thumbprint (sha1) of the signing certificate of a given
-// file is part of a sorted array of thumbprints.
-bool IsFileCertificateThumbprintInArray(const base::FilePath& fullpath,
-                                        const char* const thumbprints[],
-                                        size_t thumbprints_length);
-
 // Check whether a process is running with the image |executable|. Return true
 // if a process is found.
 bool IsProcessRunning(const wchar_t* executable);
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index dc766a2..aba6aad8 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -8,6 +8,10 @@
 import("//ui/base/ui_features.gni")
 import("chrome_repack_locales.gni")
 
+if (is_chromeos) {
+  import("//chrome/browser/chromeos/kiosk_next_home/kiosk_next.gni")
+}
+
 # Generates a rule to repack a set of resources, substituting a given string
 # in for the percentage (e.g. "100", "200"). It generates the repacked files in
 # the "gen" directory, and then introduces a copy rule to copy it to the root
@@ -166,6 +170,10 @@
         "//third_party/ink:ink_resources",
         "//ui/file_manager:resources",
       ]
+      if (enable_kiosk_next && is_chrome_branded) {
+        sources += [ "$root_gen_dir/chrome/kiosk_next_internal_resources.pak" ]
+        deps += [ "//chrome/browser/resources:kiosk_next_internal_resources" ]
+      }
     }
     if (!is_android && !is_chromeos) {
       sources += [ "$root_gen_dir/chrome/onboarding_welcome_resources.pak" ]
diff --git a/chrome/credential_provider/test/BUILD.gn b/chrome/credential_provider/test/BUILD.gn
index 427e79d..6e8ca24 100644
--- a/chrome/credential_provider/test/BUILD.gn
+++ b/chrome/credential_provider/test/BUILD.gn
@@ -55,5 +55,6 @@
   if (is_win && llvm_force_head_revision) {
     # TODO(https://crbug.com/958955): Fix dupes and remove this flag.
     ldflags = [ "/FORCE:MultipleRes" ]
+    configs -= [ "//build/config/compiler:fatal_linker_warnings_win" ]
   }
 }
diff --git a/chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom b/chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom
deleted file mode 100644
index a9df4af..0000000
--- a/chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom
+++ /dev/null
@@ -1,130 +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.
-
-// API exposed by the diagnosticsd daemon. Normally the consumer of this API is
-// the browser.
-
-// NOTE: This mojom should be kept in sync with the copy in Chromium OS's repo
-// in src/platform2/diagnostics/mojo/.
-
-module chromeos.diagnosticsd.mojom;
-
-[Extensible]
-enum DiagnosticsdWebRequestHttpMethod {
-  kGet,
-  kHead,
-  kPost,
-  kPut,
-};
-
-[Extensible]
-enum DiagnosticsdWebRequestStatus {
-  // The request was successfully completed with a 2xx HTTP status.
-  kOk,
-  // Failed to make the web request. This covers such cases when the network
-  // is unavailable, or connection attempt failed, or TLS handshake failed,
-  // or too many pending requests, etc.
-  kNetworkError,
-  // HTTP request finished with a non-2xx status.
-  kHttpError,
-};
-
-// Factory interface exposed by the diagnosticsd daemon, which allows both
-// endpoints (the diagnosticsd and the browser) to exchange with their
-// interfaces (DiagnosticsdService and DiagnosticsdClient correspondingly).
-interface DiagnosticsdServiceFactory {
-  // Returns an interface to DiagnosticsdService in response to the passed
-  // interface to DiagnosticsdClient.
-  GetService@0(DiagnosticsdService& service, DiagnosticsdClient client) => ();
-};
-
-// Interface exposed by the diagnosticsd daemon.
-interface DiagnosticsdService {
-  // Sends a message, originating from the diagnostics UI extension (hosted by
-  // the browser), to the diagnostics_processor daemon. The message contents are
-  // serialized JSON. Delivery of the message is not guaranteed (for example, if
-  // the diagnostics_processor daemon isn't running at the moment).
-  //
-  // NOTE: the |json_message| message must not exceed 1 MB (1'000'000 bytes).
-  //
-  // The response will contain the JSON message returned by the
-  // diagnostics_processor daemon. The response handle will be unset if the
-  // request wasn't delivered to the daemon or the daemon made no reply.
-  //
-  // NOTE: Both request and response messages are opaque to Chrome and not
-  // interpreted by it in any way (except for the JSON validity verification
-  // of the response message that happens in the target extension's renderer
-  // process). This method simply transmits data between two endpoints that are
-  // implemented by third parties (the diagnostics UI extension and the
-  // diagnostics_processor daemon).
-  SendUiMessageToDiagnosticsProcessor@0(handle json_message)
-      => (handle? response_json_message);
-
-  // Called when new configuration data blob is available. This happens when
-  // the device policy, passing this configuration data blob, gets updated.
-  // It is only a notification that the configuration data has been changed.
-  // The GetConfigurationData method of DiagnosticsdClient needs to be called to
-  // retrieve the actual configuration data.
-  // NOTE: This notification is only triggered for changes that occur after the
-  // current Mojo connection was established;
-  // an initial call to GetConfigurationData should be used in order to fetch
-  // the changes that happened beforehand.
-  NotifyConfigurationDataChanged@1();
-};
-
-// Interface exposed by the consumer of DiagnosticsdService. In production this
-// is the browser.
-interface DiagnosticsdClient {
-  // Performs a web request, originating from the diagnostics_processor daemon,
-  // using the browser's network stack.
-  //
-  // The web request:
-  // * |http_method| - the HTTP method of the web request,
-  // * |url| - the URL with HTTPS scheme.
-  // * |headers| - the list of HTTP headers.
-  // * |request_body| - the body of the HTTP request.
-  // NOTE: the total size of all |handle| fields in the request must not exceed
-  // 1 MB (1'000'000 bytes).
-  //
-  // The response to that web request:
-  // * the |status| of the web request,
-  // * |http_status| - the HTTP status code if the |status| is |kOk| or
-  //                   |kHttpError|, otherwise the HTTP status code is 0.
-  // * |response_body| - the web response payload. The handle is valid only
-  //                     if |status| is |kOk| or |kHttpError|. And the length
-  //                     is guaranteed to not exceed 1 MB (1'000'000 bytes).
-  PerformWebRequest@0(DiagnosticsdWebRequestHttpMethod http_method,
-                      handle url,
-                      array<handle> headers,
-                      handle? request_body)
-      => (DiagnosticsdWebRequestStatus status, int32 http_status,
-          handle? response_body);
-
-  // Sends a message, originating from the diagnostics_processor daemon, to the
-  // diagnostics UI extension (hosted by the browser). The message contents are
-  // serialized JSON. Delivery of the message is not guaranteed (for example, if
-  // no user is currently logged in that has the diagnostics UI extension
-  // installed).
-  //
-  // NOTE: the size of the |json_message| must not exceed 1 MB (1'000'000
-  // bytes).
-  //
-  // The response will contain the JSON message returned by the extension. The
-  // response handle will be unset if the request wasn't delivered to the
-  // extension or the extension made no reply. The response is guaranteed to not
-  // exceed 1 MB (1'000'000 bytes).
-  //
-  // NOTE: Both request and response messages are opaque to Chrome and not
-  // interpreted by it in any way (except for the JSON validity verification
-  // of the input message that happens in the target extension's renderer
-  // process). This method simply transmits data between two endpoints that are
-  // implemented by third parties (the diagnostics UI extension and the
-  // diagnostics_processor daemon).
-  SendDiagnosticsProcessorMessageToUi@1(handle json_message)
-      => (handle? response_json_message);
-
-  // Retrieves a JSON-formatted configuration data. The length of
-  // |json_configuration_data| does not exceed 20'000 bytes.
-  GetConfigurationData@2() => (string json_configuration_data);
-};
diff --git a/chrome/services/diagnosticsd/OWNERS b/chrome/services/wilco_dtc_supportd/OWNERS
similarity index 100%
rename from chrome/services/diagnosticsd/OWNERS
rename to chrome/services/wilco_dtc_supportd/OWNERS
diff --git a/chrome/services/diagnosticsd/public/mojom/BUILD.gn b/chrome/services/wilco_dtc_supportd/public/mojom/BUILD.gn
similarity index 90%
rename from chrome/services/diagnosticsd/public/mojom/BUILD.gn
rename to chrome/services/wilco_dtc_supportd/public/mojom/BUILD.gn
index bb55066..3d38bc6 100644
--- a/chrome/services/diagnosticsd/public/mojom/BUILD.gn
+++ b/chrome/services/wilco_dtc_supportd/public/mojom/BUILD.gn
@@ -8,7 +8,7 @@
 
 mojom("mojom") {
   sources = [
-    "diagnosticsd.mojom",
+    "wilco_dtc_supportd.mojom",
   ]
 
   public_deps = [
diff --git a/chrome/services/diagnosticsd/public/mojom/OWNERS b/chrome/services/wilco_dtc_supportd/public/mojom/OWNERS
similarity index 100%
rename from chrome/services/diagnosticsd/public/mojom/OWNERS
rename to chrome/services/wilco_dtc_supportd/public/mojom/OWNERS
diff --git a/chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom b/chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom
new file mode 100644
index 0000000..a2f8862
--- /dev/null
+++ b/chrome/services/wilco_dtc_supportd/public/mojom/wilco_dtc_supportd.mojom
@@ -0,0 +1,132 @@
+// 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.
+
+// API exposed by the wilco_dtc_supportd daemon. Normally the consumer of this
+// API is the browser.
+
+// NOTE: This mojom should be kept in sync with the copy in Chromium OS's repo
+// in src/platform2/diagnostics/mojo/.
+
+module chromeos.wilco_dtc_supportd.mojom;
+
+[Extensible]
+enum WilcoDtcSupportdWebRequestHttpMethod {
+  kGet,
+  kHead,
+  kPost,
+  kPut,
+};
+
+[Extensible]
+enum WilcoDtcSupportdWebRequestStatus {
+  // The request was successfully completed with a 2xx HTTP status.
+  kOk,
+  // Failed to make the web request. This covers such cases when the network
+  // is unavailable, or connection attempt failed, or TLS handshake failed,
+  // or too many pending requests, etc.
+  kNetworkError,
+  // HTTP request finished with a non-2xx status.
+  kHttpError,
+};
+
+// Factory interface exposed by the wilco_dtc_supportd daemon, which allows both
+// endpoints (the wilco_dtc_supportd and the browser) to exchange with their
+// interfaces (WilcoDtcSupportdService and WilcoDtcSupportdClient
+// correspondingly).
+interface WilcoDtcSupportdServiceFactory {
+  // Returns an interface to WilcoDtcSupportdService in response to the passed
+  // interface to WilcoDtcSupportdClient.
+  GetService@0(WilcoDtcSupportdService& service, WilcoDtcSupportdClient client)
+      => ();
+};
+
+// Interface exposed by the wilco_dtc_supportd daemon.
+interface WilcoDtcSupportdService {
+  // Sends a message, originating from the wilco_dtc UI extension (hosted by
+  // the browser), to the wilco_dtc daemon. The message contents are serialized
+  // JSON. Delivery of the message is not guaranteed (for example, if the
+  // wilco_dtc daemon isn't running at the moment).
+  //
+  // NOTE: the |json_message| message must not exceed 1 MB (1'000'000 bytes).
+  //
+  // The response will contain the JSON message returned by the wilco_dtc
+  // daemon. The response handle will be unset if the request wasn't delivered
+  // to the daemon or the daemon made no reply.
+  //
+  // NOTE: Both request and response messages are opaque to Chrome and not
+  // interpreted by it in any way (except for the JSON validity verification
+  // of the response message that happens in the target extension's renderer
+  // process). This method simply transmits data between two endpoints that are
+  // implemented by third parties (the wilco_dtc UI extension and the wilco_dtc
+  // daemon).
+  SendUiMessageToWilcoDtc@0(handle json_message)
+      => (handle? response_json_message);
+
+  // Called when new configuration data blob is available. This happens when
+  // the device policy, passing this configuration data blob, gets updated.
+  // It is only a notification that the configuration data has been changed.
+  // The GetConfigurationData method of WilcoDtcSupportdClient needs to be
+  // called to retrieve the actual configuration data.
+  //
+  // NOTE: This notification is only triggered for changes that occur after the
+  // current Mojo connection was established;
+  // an initial call to GetConfigurationData should be used in order to fetch
+  // the changes that happened beforehand.
+  NotifyConfigurationDataChanged@1();
+};
+
+// Interface exposed by the consumer of WilcoDtcSupportdService. In production
+// this is the browser.
+interface WilcoDtcSupportdClient {
+  // Performs a web request, originating from the wilco_dtc daemon, using the
+  // browser's network stack.
+  //
+  // The web request:
+  // * |http_method| - the HTTP method of the web request,
+  // * |url| - the URL with HTTPS scheme.
+  // * |headers| - the list of HTTP headers.
+  // * |request_body| - the body of the HTTP request.
+  // NOTE: the total size of all |handle| fields in the request must not exceed
+  // 1 MB (1'000'000 bytes).
+  //
+  // The response to that web request:
+  // * the |status| of the web request,
+  // * |http_status| - the HTTP status code if the |status| is |kOk| or
+  //                   |kHttpError|, otherwise the HTTP status code is 0.
+  // * |response_body| - the web response payload. The handle is valid only
+  //                     if |status| is |kOk| or |kHttpError|. And the length
+  //                     is guaranteed to not exceed 1 MB (1'000'000 bytes).
+  PerformWebRequest@0(WilcoDtcSupportdWebRequestHttpMethod http_method,
+                      handle url,
+                      array<handle> headers,
+                      handle? request_body)
+      => (WilcoDtcSupportdWebRequestStatus status, int32 http_status,
+          handle? response_body);
+
+  // Sends a message, originating from the wilco_dtc daemon, to the wilco_dtc
+  // UI extension (hosted by the browser). The message contents are serialized
+  // JSON. Delivery of the message is not guaranteed (for example, if no user is
+  // currently logged in that has the wilco_dtc UI extension installed).
+  //
+  // NOTE: the size of the |json_message| must not exceed 1 MB (1'000'000
+  // bytes).
+  //
+  // The response will contain the JSON message returned by the extension. The
+  // response handle will be unset if the request wasn't delivered to the
+  // extension or the extension made no reply. The response is guaranteed to not
+  // exceed 1 MB (1'000'000 bytes).
+  //
+  // NOTE: Both request and response messages are opaque to Chrome and not
+  // interpreted by it in any way (except for the JSON validity verification
+  // of the input message that happens in the target extension's renderer
+  // process). This method simply transmits data between two endpoints that are
+  // implemented by third parties (the wilco_dtc UI extension and the wilco_dtc
+  // daemon).
+  SendWilcoDtcMessageToUi@1(handle json_message)
+       => (handle? response_json_message);
+
+  // Retrieves a JSON-formatted configuration data. The length of
+  // |json_configuration_data| does not exceed 20'000 bytes.
+  GetConfigurationData@2() => (string json_configuration_data);
+};
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index fdbc492..9797503 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1769,6 +1769,9 @@
         "../browser/chromeos/attestation/attestation_policy_browsertest.cc",
         "../browser/chromeos/child_accounts/child_account_test_utils.cc",
         "../browser/chromeos/child_accounts/child_account_test_utils.h",
+        "../browser/chromeos/child_accounts/parent_access_code/parent_access_service_browsertest.cc",
+        "../browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.cc",
+        "../browser/chromeos/child_accounts/parent_access_code/parent_access_test_utils.h",
         "../browser/chromeos/child_accounts/screen_time_controller_browsertest.cc",
         "../browser/chromeos/child_accounts/time_limit_test_utils.cc",
         "../browser/chromeos/customization/customization_document_browsertest.cc",
@@ -3058,10 +3061,6 @@
     if (enable_widevine) {
       sources += [ "../browser/media/widevine_hardware_caps_win_unittest.cc" ]
     }
-    if (llvm_force_head_revision) {
-      # TODO(https://crbug.com/958955): Fix dupes and remove this flag.
-      ldflags = [ "/FORCE:MultipleRes" ]
-    }
   }
 
   if (!is_android) {
@@ -4550,6 +4549,11 @@
       "/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
       "/DELAYLOAD:api-ms-win-core-winrt-string-l1-1-0.dll",
     ]
+    if (llvm_force_head_revision) {
+      # TODO(https://crbug.com/958955): Fix dupes and remove this flag.
+      ldflags += [ "/FORCE:MultipleRes" ]
+      configs -= [ "//build/config/compiler:fatal_linker_warnings_win" ]
+    }
 
     if (is_chrome_branded) {
       sources += [
@@ -5776,6 +5780,7 @@
       if (llvm_force_head_revision) {
         # TODO(https://crbug.com/958955): Fix dupes and remove this flag.
         ldflags = [ "/FORCE:MultipleRes" ]
+        configs -= [ "//build/config/compiler:fatal_linker_warnings_win" ]
       }
     } else {
       sources -= [ "../app/chrome_version.rc.version" ]
diff --git a/chromecast/app/linux/cast_crash_reporter_client.cc b/chromecast/app/linux/cast_crash_reporter_client.cc
index 97663d64..019cefe9 100644
--- a/chromecast/app/linux/cast_crash_reporter_client.cc
+++ b/chromecast/app/linux/cast_crash_reporter_client.cc
@@ -15,7 +15,6 @@
 
 namespace {
 
-std::string* g_process_type = nullptr;
 uint64_t g_process_start_time_ms = 0u;
 
 }  // namespace
@@ -23,31 +22,22 @@
 // static
 void CastCrashReporterClient::InitCrashReporter(
     const std::string& process_type) {
-  DCHECK(!g_process_type);
+  DCHECK(!g_process_start_time_ms);
   g_process_start_time_ms =
       (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
 
-  // Save the process type (leaked).
-  g_process_type = new std::string(process_type);
-
   // Start up breakpad for this process, if applicable.
   breakpad::InitCrashReporter(process_type);
 }
 
 // static
-const char* CastCrashReporterClient::GetProcessType() {
-  return g_process_type ? g_process_type->c_str() : nullptr;
-}
-
-// static
 uint64_t CastCrashReporterClient::GetProcessStartTime() {
   return g_process_start_time_ms;
 }
 
-CastCrashReporterClient::CastCrashReporterClient() {
-}
-CastCrashReporterClient::~CastCrashReporterClient() {
-}
+CastCrashReporterClient::CastCrashReporterClient() {}
+
+CastCrashReporterClient::~CastCrashReporterClient() {}
 
 bool CastCrashReporterClient::EnableBreakpadForProcess(
     const std::string& process_type) {
@@ -57,18 +47,17 @@
          process_type == switches::kUtilityProcess;
 }
 
-bool CastCrashReporterClient::HandleCrashDump(const char* crashdump_filename) {
+bool CastCrashReporterClient::HandleCrashDump(const char* crashdump_filename,
+                                              uint64_t crash_pid) {
   // Set the initial error code to ERROR_WEB_CONTENT_RENDER_VIEW_GONE to show
   // an error message on next cast_shell run. Though the error code is for
   // renderer process crash, the actual messages can be used for browser process
   // as well.
-  if (!GetProcessType() || !strcmp(GetProcessType(), ""))
-    SetInitialErrorCode(ERROR_WEB_CONTENT_RENDER_VIEW_GONE);
+  SetInitialErrorCode(ERROR_WEB_CONTENT_RENDER_VIEW_GONE);
 
   // Upload crash dump. If user didn't opt-in crash report, minidump writer
   // instantiated within CrashUtil::RequestUploadCrashDump() does nothing.
-  CrashUtil::RequestUploadCrashDump(crashdump_filename,
-                                    GetProcessType() ? GetProcessType() : "",
+  CrashUtil::RequestUploadCrashDump(crashdump_filename, crash_pid,
                                     GetProcessStartTime());
 
   // Always return true to indicate that this crash dump has been processed,
diff --git a/chromecast/app/linux/cast_crash_reporter_client.h b/chromecast/app/linux/cast_crash_reporter_client.h
index 315ace23..0470507 100644
--- a/chromecast/app/linux/cast_crash_reporter_client.h
+++ b/chromecast/app/linux/cast_crash_reporter_client.h
@@ -23,10 +23,10 @@
 
   // crash_reporter::CrashReporterClient implementation:
   bool EnableBreakpadForProcess(const std::string& process_type) override;
-  bool HandleCrashDump(const char* crashdump_filename) override;
+  bool HandleCrashDump(const char* crashdump_filename,
+                       uint64_t crash_pid) override;
 
  private:
-  static const char* GetProcessType();
   static uint64_t GetProcessStartTime();
 
   DISALLOW_COPY_AND_ASSIGN(CastCrashReporterClient);
diff --git a/chromecast/app/linux/cast_crash_reporter_client_unittest.cc b/chromecast/app/linux/cast_crash_reporter_client_unittest.cc
index 816932de..9ce10ae4 100644
--- a/chromecast/app/linux/cast_crash_reporter_client_unittest.cc
+++ b/chromecast/app/linux/cast_crash_reporter_client_unittest.cc
@@ -131,7 +131,7 @@
   // Handle a "crash" on an IO restricted thread.
   base::ThreadRestrictions::SetIOAllowed(false);
   CastCrashReporterClient client;
-  ASSERT_TRUE(client.HandleCrashDump(minidump_path().value().c_str()));
+  ASSERT_TRUE(client.HandleCrashDump(minidump_path().value().c_str(), 0));
 
   // Assert that the thread is IO restricted when the function exits.
   // Note that SetIOAllowed returns the previous value.
@@ -143,7 +143,7 @@
   // Handle a crash on a non-IO restricted thread.
   base::ThreadRestrictions::SetIOAllowed(true);
   CastCrashReporterClient client;
-  ASSERT_TRUE(client.HandleCrashDump(minidump_path().value().c_str()));
+  ASSERT_TRUE(client.HandleCrashDump(minidump_path().value().c_str(), 0));
 
   // Assert that the thread is not IO restricted when the function exits.
   // Note that SetIOAllowed returns the previous value.
diff --git a/chromecast/browser/ui/aura/accessibility/automation_manager_aura.cc b/chromecast/browser/ui/aura/accessibility/automation_manager_aura.cc
index 9da1273..c263680 100644
--- a/chromecast/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chromecast/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -61,10 +61,6 @@
 void AutomationManagerAura::Disable() {
   enabled_ = false;
   Reset(true);
-
-#if defined(OS_CHROMEOS)
-  AXHostService::SetAutomationEnabled(false);
-#endif
 }
 
 void AutomationManagerAura::OnViewEvent(views::View* view,
diff --git a/chromecast/crash/linux/crash_util.cc b/chromecast/crash/linux/crash_util.cc
index 01b29202..6301453 100644
--- a/chromecast/crash/linux/crash_util.cc
+++ b/chromecast/crash/linux/crash_util.cc
@@ -35,25 +35,22 @@
 // static
 bool CrashUtil::RequestUploadCrashDump(
     const std::string& existing_minidump_path,
-    const std::string& crashed_process_name,
+    uint64_t crashed_pid,
     uint64_t crashed_process_start_time_ms) {
   // Remove IO restrictions from this thread. Chromium IO functions must be used
   // to access the file system and upload information to the crash server.
   const bool io_allowed = base::ThreadRestrictions::SetIOAllowed(true);
 
   LOG(INFO) << "Request to upload crash dump " << existing_minidump_path
-            << " for process " << crashed_process_name;
+            << " for process " << crashed_pid;
 
   uint64_t uptime_ms = GetCurrentTimeMs() - crashed_process_start_time_ms;
-  MinidumpParams params(crashed_process_name,
-                        uptime_ms,
-                        "",  // suffix
-                        AppStateTracker::GetPreviousApp(),
-                        AppStateTracker::GetCurrentApp(),
-                        AppStateTracker::GetLastLaunchedApp(),
-                        CAST_BUILD_RELEASE,
-                        CAST_BUILD_INCREMENTAL,
-                        ""  /* reason */);
+  MinidumpParams params(
+      uptime_ms,
+      "",  // suffix
+      AppStateTracker::GetPreviousApp(), AppStateTracker::GetCurrentApp(),
+      AppStateTracker::GetLastLaunchedApp(), CAST_BUILD_RELEASE,
+      CAST_BUILD_INCREMENTAL, "" /* reason */);
   DummyMinidumpGenerator minidump_generator(existing_minidump_path);
 
   base::FilePath filename = base::FilePath(existing_minidump_path).BaseName();
diff --git a/chromecast/crash/linux/crash_util.h b/chromecast/crash/linux/crash_util.h
index 04de5651..da66df7 100644
--- a/chromecast/crash/linux/crash_util.h
+++ b/chromecast/crash/linux/crash_util.h
@@ -18,7 +18,7 @@
   // Helper function to request upload an existing minidump file. Returns true
   // on success, false otherwise.
   static bool RequestUploadCrashDump(const std::string& existing_minidump_path,
-                                     const std::string& crashed_process_name,
+                                     uint64_t crashed_pid,
                                      uint64_t crashed_process_start_time_ms);
 
   // Util function to get current time in ms. This is used to record
diff --git a/chromecast/crash/linux/dump_info.cc b/chromecast/crash/linux/dump_info.cc
index 82f325c..f3516af 100644
--- a/chromecast/crash/linux/dump_info.cc
+++ b/chromecast/crash/linux/dump_info.cc
@@ -18,7 +18,7 @@
 // "%Y-%m-%d %H:%M:%S";
 const char kDumpTimeFormat[] = "%04d-%02d-%02d %02d:%02d:%02d";
 
-const int kNumRequiredParams = 5;
+const int kNumRequiredParams = 4;
 
 const char kNameKey[] = "name";
 const char kDumpTimeKey[] = "dump_time";
@@ -56,7 +56,6 @@
       std::make_unique<base::DictionaryValue>();
   base::DictionaryValue* entry;
   result->GetAsDictionary(&entry);
-  entry->SetString(kNameKey, params_.process_name);
 
   base::Time::Exploded ex;
   dump_time_.LocalExplode(&ex);
@@ -91,9 +90,6 @@
     return false;
 
   // Extract required fields.
-  if (!dict->GetString(kNameKey, &params_.process_name))
-    return false;
-
   std::string dump_time;
   if (!dict->GetString(kDumpTimeKey, &dump_time))
     return false;
@@ -116,6 +112,9 @@
   size_t num_params = kNumRequiredParams;
 
   // Extract all other optional fields.
+  std::string unused_process_name;
+  if (dict->GetString(kNameKey, &unused_process_name))
+    ++num_params;
   if (dict->GetString(kSuffixKey, &params_.suffix))
     ++num_params;
   if (dict->GetString(kPrevAppNameKey, &params_.previous_app_name))
diff --git a/chromecast/crash/linux/dump_info_unittest.cc b/chromecast/crash/linux/dump_info_unittest.cc
index 1817177..83f16cdf 100644
--- a/chromecast/crash/linux/dump_info_unittest.cc
+++ b/chromecast/crash/linux/dump_info_unittest.cc
@@ -41,7 +41,6 @@
 TEST(DumpInfoTest, AllRequiredFieldsIsValid) {
   std::unique_ptr<DumpInfo> info(
       CreateDumpInfo("{"
-                     "\"name\": \"name\","
                      "\"dump_time\" : \"2001-11-12 18:31:01\","
                      "\"dump\": \"dump_string\","
                      "\"uptime\": \"123456789\","
@@ -58,7 +57,6 @@
   EXPECT_TRUE(base::Time::FromLocalExploded(ex, &dump_time));
 
   ASSERT_TRUE(info->valid());
-  ASSERT_EQ("name", info->params().process_name);
   ASSERT_EQ(dump_time, info->dump_time());
   ASSERT_EQ("dump_string", info->crashed_process_dump());
   ASSERT_EQ(123456789u, info->params().process_uptime);
@@ -97,7 +95,6 @@
   EXPECT_TRUE(base::Time::FromLocalExploded(ex, &dump_time));
 
   ASSERT_TRUE(info->valid());
-  ASSERT_EQ("name", info->params().process_name);
   ASSERT_EQ(dump_time, info->dump_time());
   ASSERT_EQ("", info->crashed_process_dump());
   ASSERT_EQ(0u, info->params().process_uptime);
@@ -131,7 +128,6 @@
   EXPECT_TRUE(base::Time::FromLocalExploded(ex, &dump_time));
 
   ASSERT_TRUE(info->valid());
-  ASSERT_EQ("name", info->params().process_name);
   ASSERT_EQ(dump_time, info->dump_time());
   ASSERT_EQ("dump_string", info->crashed_process_dump());
   ASSERT_EQ(123456789u, info->params().process_uptime);
@@ -166,7 +162,6 @@
   EXPECT_TRUE(base::Time::FromLocalExploded(ex, &dump_time));
 
   ASSERT_TRUE(info->valid());
-  ASSERT_EQ("name", info->params().process_name);
   ASSERT_EQ(dump_time, info->dump_time());
   ASSERT_EQ("dump_string", info->crashed_process_dump());
   ASSERT_EQ(123456789u, info->params().process_uptime);
diff --git a/chromecast/crash/linux/minidump_params.cc b/chromecast/crash/linux/minidump_params.cc
index 32be9168..ff81e2b 100644
--- a/chromecast/crash/linux/minidump_params.cc
+++ b/chromecast/crash/linux/minidump_params.cc
@@ -6,8 +6,7 @@
 
 namespace chromecast {
 
-MinidumpParams::MinidumpParams(const std::string& p_process_name,
-                               const uint64_t p_process_uptime,
+MinidumpParams::MinidumpParams(const uint64_t p_process_uptime,
                                const std::string& p_suffix,
                                const std::string& p_previous_app_name,
                                const std::string& p_current_app_name,
@@ -15,19 +14,16 @@
                                const std::string& p_cast_release_version,
                                const std::string& p_cast_build_number,
                                const std::string& p_reason)
-    : process_name(p_process_name),
-      process_uptime(p_process_uptime),
+    : process_uptime(p_process_uptime),
       suffix(p_suffix),
       previous_app_name(p_previous_app_name),
       current_app_name(p_current_app_name),
       last_app_name(p_last_app_name),
       cast_release_version(p_cast_release_version),
       cast_build_number(p_cast_build_number),
-      reason(p_reason) {
-}
+      reason(p_reason) {}
 
-MinidumpParams::MinidumpParams() : process_uptime(0) {
-}
+MinidumpParams::MinidumpParams() : process_uptime(0) {}
 
 MinidumpParams::MinidumpParams(const MinidumpParams& params) = default;
 
diff --git a/chromecast/crash/linux/minidump_params.h b/chromecast/crash/linux/minidump_params.h
index 02bd69f..9cf92d8 100644
--- a/chromecast/crash/linux/minidump_params.h
+++ b/chromecast/crash/linux/minidump_params.h
@@ -13,8 +13,7 @@
 
 struct MinidumpParams {
   MinidumpParams();
-  MinidumpParams(const std::string& p_process_name,
-                 const uint64_t p_process_uptime,
+  MinidumpParams(const uint64_t p_process_uptime,
                  const std::string& p_suffix,
                  const std::string& p_previous_app_name,
                  const std::string& p_current_app_name,
@@ -25,7 +24,6 @@
   MinidumpParams(const MinidumpParams& params);
   ~MinidumpParams();
 
-  std::string process_name;
   uint64_t process_uptime;
   std::string suffix;
   std::string previous_app_name;
diff --git a/chromecast/crash/linux/minidump_uploader_unittest.cc b/chromecast/crash/linux/minidump_uploader_unittest.cc
index ac89484..1dd22e8 100644
--- a/chromecast/crash/linux/minidump_uploader_unittest.cc
+++ b/chromecast/crash/linux/minidump_uploader_unittest.cc
@@ -97,7 +97,7 @@
     // Must pass in non-empty MinidumpParams to circumvent the internal checks.
     std::unique_ptr<DumpInfo> dump(new DumpInfo(
         minidump_path.value(), logfile_path.value(), base::Time::Now(),
-        MinidumpParams("_", 0, "_", "_", "_", "_", "_", "_", "_")));
+        MinidumpParams(0, "_", "_", "_", "_", "_", "_", "_")));
 
     CHECK(AppendLockFile(lockfile_.value(), metadata_.value(), *dump));
     base::File minidump(
diff --git a/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc b/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc
index 7088a0c..3474b10c0 100644
--- a/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc
+++ b/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc
@@ -265,7 +265,6 @@
   // Sample parameters.
   base::Time now = base::Time::Now();
   MinidumpParams params;
-  params.process_name = "process";
 
   // Write the first entry.
   SynchronizedMinidumpManagerSimple manager;
@@ -294,7 +293,6 @@
   // Create some parameters for a minidump.
   base::Time now = base::Time::Now();
   MinidumpParams params;
-  params.process_name = "process";
 
   // Create a manager that grabs the lock then sleeps. Post a DoWork task to
   // another thread. |sleepy_manager| will grab the lock and hold it for
@@ -344,7 +342,6 @@
   // Create some parameters for a minidump.
   base::Time now = base::Time::Now();
   MinidumpParams params;
-  params.process_name = "process";
 
   // Fork the process.
   pid_t pid = base::ForkWithFlags(0u, nullptr, nullptr);
@@ -388,7 +385,6 @@
   // Sample parameters.
   base::Time now = base::Time::Now();
   MinidumpParams params;
-  params.process_name = "process";
 
   FakeSynchronizedMinidumpUploader uploader;
   SynchronizedMinidumpManagerSimple producer;
@@ -404,7 +400,6 @@
   // Sample parameters.
   base::Time now = base::Time::Now();
   MinidumpParams params;
-  params.process_name = "process";
 
   FakeSynchronizedMinidumpUploader uploader;
   SynchronizedMinidumpManagerSimple producer;
@@ -424,7 +419,6 @@
   // Sample parameters.
   base::Time now = base::Time::Now();
   MinidumpParams params;
-  params.process_name = "process";
 
   FakeSynchronizedMinidumpUploader uploader;
   SynchronizedMinidumpManagerSimple producer;
@@ -469,7 +463,6 @@
   // Sample parameters.
   base::Time now = base::Time::Now();
   MinidumpParams params;
-  params.process_name = "process";
 
   SynchronizedMinidumpManagerSimple producer;
   FakeSynchronizedMinidumpUploader uploader;
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn
index e3a674e..e440bbb 100644
--- a/chromeos/dbus/BUILD.gn
+++ b/chromeos/dbus/BUILD.gn
@@ -65,8 +65,6 @@
     "dbus_thread_manager.h",
     "debug_daemon_client.cc",
     "debug_daemon_client.h",
-    "diagnosticsd_client.cc",
-    "diagnosticsd_client.h",
     "easy_unlock_client.cc",
     "easy_unlock_client.h",
     "fake_arc_appfuse_provider_client.cc",
@@ -89,8 +87,6 @@
     "fake_cros_disks_client.h",
     "fake_debug_daemon_client.cc",
     "fake_debug_daemon_client.h",
-    "fake_diagnosticsd_client.cc",
-    "fake_diagnosticsd_client.h",
     "fake_easy_unlock_client.cc",
     "fake_easy_unlock_client.h",
     "fake_image_burner_client.cc",
@@ -111,6 +107,8 @@
     "fake_update_engine_client.h",
     "fake_virtual_file_provider_client.cc",
     "fake_virtual_file_provider_client.h",
+    "fake_wilco_dtc_supportd_client.cc",
+    "fake_wilco_dtc_supportd_client.h",
     "image_burner_client.cc",
     "image_burner_client.h",
     "image_loader_client.cc",
@@ -131,6 +129,8 @@
     "util/version_loader.h",
     "virtual_file_provider_client.cc",
     "virtual_file_provider_client.h",
+    "wilco_dtc_supportd_client.cc",
+    "wilco_dtc_supportd_client.h",
   ]
 }
 
diff --git a/chromeos/dbus/OWNERS b/chromeos/dbus/OWNERS
index 99dda4f..54cd6ce 100644
--- a/chromeos/dbus/OWNERS
+++ b/chromeos/dbus/OWNERS
@@ -2,9 +2,9 @@
 hashimoto@chromium.org
 derat@chromium.org
 
-per-file *diagnosticsd*=emaxx@chromium.org
-per-file *diagnosticsd*=pmarko@chromium.org
 per-file *smb_provider*=amistry@chromium.org
 per-file *smb_provider*=baileyberro@chromium.org
 per-file *smb_provider*=slangley@chromium.org
 per-file *smb_provider*=zentaro@chromium.org
+per-file *wilco_dtc_supportd*=emaxx@chromium.org
+per-file *wilco_dtc_supportd*=pmarko@chromium.org
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc
index 3b21035..267ebd1 100644
--- a/chromeos/dbus/dbus_clients_browser.cc
+++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -16,7 +16,6 @@
 #include "chromeos/dbus/dbus_client_implementation_type.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
-#include "chromeos/dbus/diagnosticsd_client.h"
 #include "chromeos/dbus/easy_unlock_client.h"
 #include "chromeos/dbus/fake_arc_appfuse_provider_client.h"
 #include "chromeos/dbus/fake_arc_midis_client.h"
@@ -27,7 +26,6 @@
 #include "chromeos/dbus/fake_concierge_client.h"
 #include "chromeos/dbus/fake_cros_disks_client.h"
 #include "chromeos/dbus/fake_debug_daemon_client.h"
-#include "chromeos/dbus/fake_diagnosticsd_client.h"
 #include "chromeos/dbus/fake_easy_unlock_client.h"
 #include "chromeos/dbus/fake_image_burner_client.h"
 #include "chromeos/dbus/fake_image_loader_client.h"
@@ -37,6 +35,7 @@
 #include "chromeos/dbus/fake_seneschal_client.h"
 #include "chromeos/dbus/fake_smb_provider_client.h"
 #include "chromeos/dbus/fake_virtual_file_provider_client.h"
+#include "chromeos/dbus/fake_wilco_dtc_supportd_client.h"
 #include "chromeos/dbus/image_burner_client.h"
 #include "chromeos/dbus/image_loader_client.h"
 #include "chromeos/dbus/lorgnette_manager_client.h"
@@ -46,6 +45,7 @@
 #include "chromeos/dbus/smb_provider_client.h"
 #include "chromeos/dbus/update_engine_client.h"
 #include "chromeos/dbus/virtual_file_provider_client.h"
+#include "chromeos/dbus/wilco_dtc_supportd_client.h"
 
 namespace chromeos {
 
@@ -82,8 +82,6 @@
   concierge_client_ = CREATE_DBUS_CLIENT(ConciergeClient, use_real_clients);
   debug_daemon_client_ =
       CREATE_DBUS_CLIENT(DebugDaemonClient, use_real_clients);
-  diagnosticsd_client_ =
-      CREATE_DBUS_CLIENT(DiagnosticsdClient, use_real_clients);
   easy_unlock_client_ = CREATE_DBUS_CLIENT(EasyUnlockClient, use_real_clients);
   image_burner_client_ =
       CREATE_DBUS_CLIENT(ImageBurnerClient, use_real_clients);
@@ -101,6 +99,8 @@
   update_engine_client_.reset(UpdateEngineClient::Create(client_impl_type));
   virtual_file_provider_client_ =
       CREATE_DBUS_CLIENT(VirtualFileProviderClient, use_real_clients);
+  wilco_dtc_supportd_client_ =
+      CREATE_DBUS_CLIENT(WilcoDtcSupportdClient, use_real_clients);
 }
 
 DBusClientsBrowser::~DBusClientsBrowser() = default;
@@ -117,7 +117,6 @@
   concierge_client_->Init(system_bus);
   cros_disks_client_->Init(system_bus);
   debug_daemon_client_->Init(system_bus);
-  diagnosticsd_client_->Init(system_bus);
   easy_unlock_client_->Init(system_bus);
   image_burner_client_->Init(system_bus);
   image_loader_client_->Init(system_bus);
@@ -128,6 +127,7 @@
   smb_provider_client_->Init(system_bus);
   update_engine_client_->Init(system_bus);
   virtual_file_provider_client_->Init(system_bus);
+  wilco_dtc_supportd_client_->Init(system_bus);
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index 501ccb8..a2e81d8 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -25,7 +25,6 @@
 class ConciergeClient;
 class CrosDisksClient;
 class DebugDaemonClient;
-class DiagnosticsdClient;
 class EasyUnlockClient;
 class ImageBurnerClient;
 class ImageLoaderClient;
@@ -36,6 +35,7 @@
 class SmbProviderClient;
 class UpdateEngineClient;
 class VirtualFileProviderClient;
+class WilcoDtcSupportdClient;
 
 // D-Bus clients used only in the browser process.
 // TODO(jamescook): Move this under //chrome/browser. http://crbug.com/647367
@@ -61,7 +61,6 @@
   std::unique_ptr<ConciergeClient> concierge_client_;
   std::unique_ptr<CrosDisksClient> cros_disks_client_;
   std::unique_ptr<DebugDaemonClient> debug_daemon_client_;
-  std::unique_ptr<DiagnosticsdClient> diagnosticsd_client_;
   std::unique_ptr<EasyUnlockClient> easy_unlock_client_;
   std::unique_ptr<ImageBurnerClient> image_burner_client_;
   std::unique_ptr<ImageLoaderClient> image_loader_client_;
@@ -72,6 +71,7 @@
   std::unique_ptr<SmbProviderClient> smb_provider_client_;
   std::unique_ptr<UpdateEngineClient> update_engine_client_;
   std::unique_ptr<VirtualFileProviderClient> virtual_file_provider_client_;
+  std::unique_ptr<WilcoDtcSupportdClient> wilco_dtc_supportd_client_;
 
   DISALLOW_COPY_AND_ASSIGN(DBusClientsBrowser);
 };
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index cc9e181..2dc6d02b 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -147,11 +147,6 @@
                           : nullptr;
 }
 
-DiagnosticsdClient* DBusThreadManager::GetDiagnosticsdClient() {
-  return clients_browser_ ? clients_browser_->diagnosticsd_client_.get()
-                          : nullptr;
-}
-
 EasyUnlockClient* DBusThreadManager::GetEasyUnlockClient() {
   return clients_browser_ ? clients_browser_->easy_unlock_client_.get()
                           : nullptr;
@@ -234,6 +229,11 @@
              : nullptr;
 }
 
+WilcoDtcSupportdClient* DBusThreadManager::GetWilcoDtcSupportdClient() {
+  return clients_browser_ ? clients_browser_->wilco_dtc_supportd_client_.get()
+                          : nullptr;
+}
+
 void DBusThreadManager::InitializeClients() {
   // Some clients call DBusThreadManager::Get() during initialization.
   DCHECK(g_dbus_thread_manager);
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index 2945592..5b34c6b6 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -35,7 +35,6 @@
 class DBusClientsBrowser;
 class DBusThreadManagerSetter;
 class DebugDaemonClient;
-class DiagnosticsdClient;
 class EasyUnlockClient;
 class ImageBurnerClient;
 class ImageLoaderClient;
@@ -54,6 +53,7 @@
 class SMSClient;
 class UpdateEngineClient;
 class VirtualFileProviderClient;
+class WilcoDtcSupportdClient;
 
 // THIS CLASS IS BEING DEPRECATED. See README.md for guidelines and
 // https://crbug.com/647367 for details.
@@ -122,7 +122,6 @@
   ConciergeClient* GetConciergeClient();
   CrosDisksClient* GetCrosDisksClient();
   DebugDaemonClient* GetDebugDaemonClient();
-  DiagnosticsdClient* GetDiagnosticsdClient();
   EasyUnlockClient* GetEasyUnlockClient();
   ImageBurnerClient* GetImageBurnerClient();
   ImageLoaderClient* GetImageLoaderClient();
@@ -133,6 +132,7 @@
   SmbProviderClient* GetSmbProviderClient();
   UpdateEngineClient* GetUpdateEngineClient();
   VirtualFileProviderClient* GetVirtualFileProviderClient();
+  WilcoDtcSupportdClient* GetWilcoDtcSupportdClient();
 
   // DEPRECATED, DO NOT USE. The static getter for each of these classes should
   // be used instead. TODO(stevenjb): Remove. https://crbug.com/948390.
diff --git a/chromeos/dbus/diagnosticsd_client.cc b/chromeos/dbus/diagnosticsd_client.cc
deleted file mode 100644
index 27bff7166..0000000
--- a/chromeos/dbus/diagnosticsd_client.cc
+++ /dev/null
@@ -1,85 +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 "chromeos/dbus/diagnosticsd_client.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/memory/weak_ptr.h"
-#include "dbus/bus.h"
-#include "dbus/message.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
-
-namespace chromeos {
-
-namespace {
-
-void OnVoidDBusMethod(VoidDBusMethodCallback callback,
-                      dbus::Response* response) {
-  std::move(callback).Run(response != nullptr);
-}
-
-// The DiagnosticsdClient implementation used in production.
-class DiagnosticsdClientImpl final : public DiagnosticsdClient {
- public:
-  DiagnosticsdClientImpl();
-  ~DiagnosticsdClientImpl() override;
-
-  // DiagnosticsdClient overrides:
-  void WaitForServiceToBeAvailable(
-      WaitForServiceToBeAvailableCallback callback) override;
-  void BootstrapMojoConnection(base::ScopedFD fd,
-                               VoidDBusMethodCallback callback) override;
-
- protected:
-  // DiagnosticsdClient overrides:
-  void Init(dbus::Bus* bus) override;
-
- private:
-  dbus::ObjectProxy* diagnosticsd_proxy_ = nullptr;
-
-  base::WeakPtrFactory<DiagnosticsdClientImpl> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdClientImpl);
-};
-
-DiagnosticsdClientImpl::DiagnosticsdClientImpl() = default;
-
-DiagnosticsdClientImpl::~DiagnosticsdClientImpl() = default;
-
-void DiagnosticsdClientImpl::WaitForServiceToBeAvailable(
-    WaitForServiceToBeAvailableCallback callback) {
-  diagnosticsd_proxy_->WaitForServiceToBeAvailable(std::move(callback));
-}
-
-void DiagnosticsdClientImpl::BootstrapMojoConnection(
-    base::ScopedFD fd,
-    VoidDBusMethodCallback callback) {
-  dbus::MethodCall method_call(
-      ::diagnostics::kDiagnosticsdServiceInterface,
-      ::diagnostics::kDiagnosticsdBootstrapMojoConnectionMethod);
-  dbus::MessageWriter writer(&method_call);
-  writer.AppendFileDescriptor(fd.get());
-  diagnosticsd_proxy_->CallMethod(
-      &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-      base::BindOnce(&OnVoidDBusMethod, std::move(callback)));
-}
-
-void DiagnosticsdClientImpl::Init(dbus::Bus* bus) {
-  diagnosticsd_proxy_ = bus->GetObjectProxy(
-      ::diagnostics::kDiagnosticsdServiceName,
-      dbus::ObjectPath(::diagnostics::kDiagnosticsdServicePath));
-}
-
-}  // namespace
-
-// static
-std::unique_ptr<DiagnosticsdClient> DiagnosticsdClient::Create() {
-  return std::make_unique<DiagnosticsdClientImpl>();
-}
-
-DiagnosticsdClient::DiagnosticsdClient() = default;
-
-}  // namespace chromeos
diff --git a/chromeos/dbus/diagnosticsd_client.h b/chromeos/dbus/diagnosticsd_client.h
deleted file mode 100644
index 9126bb418..0000000
--- a/chromeos/dbus/diagnosticsd_client.h
+++ /dev/null
@@ -1,44 +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 CHROMEOS_DBUS_DIAGNOSTICSD_CLIENT_H_
-#define CHROMEOS_DBUS_DIAGNOSTICSD_CLIENT_H_
-
-#include <memory>
-
-#include "base/component_export.h"
-#include "base/files/scoped_file.h"
-#include "base/macros.h"
-#include "chromeos/dbus/dbus_client.h"
-#include "chromeos/dbus/dbus_method_call_status.h"
-#include "dbus/object_proxy.h"
-
-namespace chromeos {
-
-class COMPONENT_EXPORT(CHROMEOS_DBUS) DiagnosticsdClient : public DBusClient {
- public:
-  // Factory function.
-  static std::unique_ptr<DiagnosticsdClient> Create();
-
-  // Registers |callback| to run when the diagnosticsd service becomes
-  // available.
-  virtual void WaitForServiceToBeAvailable(
-      WaitForServiceToBeAvailableCallback callback) = 0;
-
-  // Bootstrap the Mojo connection between Chrome and the diagnosticsd daemon.
-  // |fd| is the file descriptor with the child end of the Mojo pipe.
-  virtual void BootstrapMojoConnection(base::ScopedFD fd,
-                                       VoidDBusMethodCallback callback) = 0;
-
- protected:
-  // Create() should be used instead.
-  DiagnosticsdClient();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdClient);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROMEOS_DBUS_DIAGNOSTICSD_CLIENT_H_
diff --git a/chromeos/dbus/fake_diagnosticsd_client.cc b/chromeos/dbus/fake_wilco_dtc_supportd_client.cc
similarity index 78%
rename from chromeos/dbus/fake_diagnosticsd_client.cc
rename to chromeos/dbus/fake_wilco_dtc_supportd_client.cc
index 8c13a15..78ca233 100644
--- a/chromeos/dbus/fake_diagnosticsd_client.cc
+++ b/chromeos/dbus/fake_wilco_dtc_supportd_client.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 "chromeos/dbus/fake_diagnosticsd_client.h"
+#include "chromeos/dbus/fake_wilco_dtc_supportd_client.h"
 
 #include <utility>
 
@@ -11,13 +11,13 @@
 
 namespace chromeos {
 
-FakeDiagnosticsdClient::FakeDiagnosticsdClient() = default;
+FakeWilcoDtcSupportdClient::FakeWilcoDtcSupportdClient() = default;
 
-FakeDiagnosticsdClient::~FakeDiagnosticsdClient() = default;
+FakeWilcoDtcSupportdClient::~FakeWilcoDtcSupportdClient() = default;
 
-void FakeDiagnosticsdClient::Init(dbus::Bus* bus) {}
+void FakeWilcoDtcSupportdClient::Init(dbus::Bus* bus) {}
 
-void FakeDiagnosticsdClient::WaitForServiceToBeAvailable(
+void FakeWilcoDtcSupportdClient::WaitForServiceToBeAvailable(
     WaitForServiceToBeAvailableCallback callback) {
   if (wait_for_service_to_be_available_result_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -30,7 +30,7 @@
   }
 }
 
-void FakeDiagnosticsdClient::BootstrapMojoConnection(
+void FakeWilcoDtcSupportdClient::BootstrapMojoConnection(
     base::ScopedFD fd,
     VoidDBusMethodCallback callback) {
   if (bootstrap_mojo_connection_result_) {
@@ -43,13 +43,13 @@
   }
 }
 
-int FakeDiagnosticsdClient::
+int FakeWilcoDtcSupportdClient::
     wait_for_service_to_be_available_in_flight_call_count() const {
   return static_cast<int>(
       pending_wait_for_service_to_be_available_callbacks_.size());
 }
 
-void FakeDiagnosticsdClient::SetWaitForServiceToBeAvailableResult(
+void FakeWilcoDtcSupportdClient::SetWaitForServiceToBeAvailableResult(
     base::Optional<bool> wait_for_service_to_be_available_result) {
   wait_for_service_to_be_available_result_ =
       wait_for_service_to_be_available_result;
@@ -61,12 +61,12 @@
     std::move(callback).Run(*wait_for_service_to_be_available_result_);
 }
 
-int FakeDiagnosticsdClient::bootstrap_mojo_connection_in_flight_call_count()
+int FakeWilcoDtcSupportdClient::bootstrap_mojo_connection_in_flight_call_count()
     const {
   return static_cast<int>(pending_bootstrap_mojo_connection_callbacks_.size());
 }
 
-void FakeDiagnosticsdClient::SetBootstrapMojoConnectionResult(
+void FakeWilcoDtcSupportdClient::SetBootstrapMojoConnectionResult(
     base::Optional<bool> bootstrap_mojo_connection_result) {
   bootstrap_mojo_connection_result_ = bootstrap_mojo_connection_result;
   if (!bootstrap_mojo_connection_result_)
diff --git a/chromeos/dbus/fake_diagnosticsd_client.h b/chromeos/dbus/fake_wilco_dtc_supportd_client.h
similarity index 78%
rename from chromeos/dbus/fake_diagnosticsd_client.h
rename to chromeos/dbus/fake_wilco_dtc_supportd_client.h
index 2b62a4b6..94d71d8e 100644
--- a/chromeos/dbus/fake_diagnosticsd_client.h
+++ b/chromeos/dbus/fake_wilco_dtc_supportd_client.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 CHROMEOS_DBUS_FAKE_DIAGNOSTICSD_CLIENT_H_
-#define CHROMEOS_DBUS_FAKE_DIAGNOSTICSD_CLIENT_H_
+#ifndef CHROMEOS_DBUS_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_
+#define CHROMEOS_DBUS_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_
 
 #include <vector>
 
@@ -11,20 +11,20 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
-#include "chromeos/dbus/diagnosticsd_client.h"
+#include "chromeos/dbus/wilco_dtc_supportd_client.h"
 
 namespace chromeos {
 
-class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeDiagnosticsdClient final
-    : public DiagnosticsdClient {
+class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeWilcoDtcSupportdClient final
+    : public WilcoDtcSupportdClient {
  public:
-  FakeDiagnosticsdClient();
-  ~FakeDiagnosticsdClient() override;
+  FakeWilcoDtcSupportdClient();
+  ~FakeWilcoDtcSupportdClient() override;
 
   // DBusClient overrides:
   void Init(dbus::Bus* bus) override;
 
-  // DiagnosticsdClient overrides:
+  // WilcoDtcSupportdClient overrides:
   void WaitForServiceToBeAvailable(
       WaitForServiceToBeAvailableCallback callback) override;
   void BootstrapMojoConnection(base::ScopedFD fd,
@@ -55,9 +55,9 @@
   std::vector<VoidDBusMethodCallback>
       pending_bootstrap_mojo_connection_callbacks_;
 
-  DISALLOW_COPY_AND_ASSIGN(FakeDiagnosticsdClient);
+  DISALLOW_COPY_AND_ASSIGN(FakeWilcoDtcSupportdClient);
 };
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_DBUS_FAKE_DIAGNOSTICSD_CLIENT_H_
+#endif  // CHROMEOS_DBUS_FAKE_WILCO_DTC_SUPPORTD_CLIENT_H_
diff --git a/chromeos/dbus/wilco_dtc_supportd_client.cc b/chromeos/dbus/wilco_dtc_supportd_client.cc
new file mode 100644
index 0000000..a20ded3
--- /dev/null
+++ b/chromeos/dbus/wilco_dtc_supportd_client.cc
@@ -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.
+
+#include "chromeos/dbus/wilco_dtc_supportd_client.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+namespace {
+
+void OnVoidDBusMethod(VoidDBusMethodCallback callback,
+                      dbus::Response* response) {
+  std::move(callback).Run(response != nullptr);
+}
+
+// The WilcoDtcSupportdClient implementation used in production.
+class WilcoDtcSupportdClientImpl final : public WilcoDtcSupportdClient {
+ public:
+  WilcoDtcSupportdClientImpl();
+  ~WilcoDtcSupportdClientImpl() override;
+
+  // WilcoDtcSupportdClient overrides:
+  void WaitForServiceToBeAvailable(
+      WaitForServiceToBeAvailableCallback callback) override;
+  void BootstrapMojoConnection(base::ScopedFD fd,
+                               VoidDBusMethodCallback callback) override;
+
+ protected:
+  // WilcoDtcSupportdClient overrides:
+  void Init(dbus::Bus* bus) override;
+
+ private:
+  dbus::ObjectProxy* wilco_dtc_supportd_proxy_ = nullptr;
+
+  base::WeakPtrFactory<WilcoDtcSupportdClientImpl> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdClientImpl);
+};
+
+WilcoDtcSupportdClientImpl::WilcoDtcSupportdClientImpl() = default;
+
+WilcoDtcSupportdClientImpl::~WilcoDtcSupportdClientImpl() = default;
+
+void WilcoDtcSupportdClientImpl::WaitForServiceToBeAvailable(
+    WaitForServiceToBeAvailableCallback callback) {
+  wilco_dtc_supportd_proxy_->WaitForServiceToBeAvailable(std::move(callback));
+}
+
+void WilcoDtcSupportdClientImpl::BootstrapMojoConnection(
+    base::ScopedFD fd,
+    VoidDBusMethodCallback callback) {
+  dbus::MethodCall method_call(
+      ::diagnostics::kWilcoDtcSupportdServiceInterface,
+      ::diagnostics::kWilcoDtcSupportdBootstrapMojoConnectionMethod);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendFileDescriptor(fd.get());
+  wilco_dtc_supportd_proxy_->CallMethod(
+      &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+      base::BindOnce(&OnVoidDBusMethod, std::move(callback)));
+}
+
+void WilcoDtcSupportdClientImpl::Init(dbus::Bus* bus) {
+  wilco_dtc_supportd_proxy_ = bus->GetObjectProxy(
+      ::diagnostics::kWilcoDtcSupportdServiceName,
+      dbus::ObjectPath(::diagnostics::kWilcoDtcSupportdServicePath));
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<WilcoDtcSupportdClient> WilcoDtcSupportdClient::Create() {
+  return std::make_unique<WilcoDtcSupportdClientImpl>();
+}
+
+WilcoDtcSupportdClient::WilcoDtcSupportdClient() = default;
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/wilco_dtc_supportd_client.h b/chromeos/dbus/wilco_dtc_supportd_client.h
new file mode 100644
index 0000000..e4c9cdb
--- /dev/null
+++ b/chromeos/dbus/wilco_dtc_supportd_client.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 CHROMEOS_DBUS_WILCO_DTC_SUPPORTD_CLIENT_H_
+#define CHROMEOS_DBUS_WILCO_DTC_SUPPORTD_CLIENT_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "chromeos/dbus/dbus_client.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "dbus/object_proxy.h"
+
+namespace chromeos {
+
+class COMPONENT_EXPORT(CHROMEOS_DBUS) WilcoDtcSupportdClient
+    : public DBusClient {
+ public:
+  // Factory function.
+  static std::unique_ptr<WilcoDtcSupportdClient> Create();
+
+  // Registers |callback| to run when the wilco_dtc_supportd service becomes
+  // available.
+  virtual void WaitForServiceToBeAvailable(
+      WaitForServiceToBeAvailableCallback callback) = 0;
+
+  // Bootstrap the Mojo connection between Chrome and the wilco_dtc_supportd
+  // daemon. |fd| is the file descriptor with the child end of the Mojo pipe.
+  virtual void BootstrapMojoConnection(base::ScopedFD fd,
+                                       VoidDBusMethodCallback callback) = 0;
+
+ protected:
+  // Create() should be used instead.
+  WilcoDtcSupportdClient();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WilcoDtcSupportdClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_WILCO_DTC_SUPPORTD_CLIENT_H_
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index dd1a57f..e39d2fdb 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -629,6 +629,7 @@
     "//third_party/libaddressinput:test_support",
     "//third_party/libaddressinput:util",
     "//third_party/libphonenumber",
+    "//third_party/re2:re2",
     "//ui/base",
     "//url",
   ]
diff --git a/components/autofill/core/browser/autofill_download_manager.cc b/components/autofill/core/browser/autofill_download_manager.cc
index 1b9a042..19cfb64 100644
--- a/components/autofill/core/browser/autofill_download_manager.cc
+++ b/components/autofill/core/browser/autofill_download_manager.cc
@@ -20,7 +20,6 @@
 #include "base/rand_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -60,7 +59,7 @@
     {3314445, 3314448}, {3314854, 3314883},
 };
 
-const size_t kMaxQueryGetSize = 1400;  // 1.25KB
+const size_t kMaxQueryGetSize = 1400;  // 1.25 KiB
 const size_t kAutofillDownloadManagerMaxFormCacheSize = 16;
 const size_t kMaxFieldsPerQueryRequest = 100;
 
@@ -448,16 +447,22 @@
   return upload_request.SerializeToString(payload);
 }
 
-// Gets an API method URL given its type (query or upload) and an optional
-// resource ID.
+// Gets an API method URL given its type (query or upload), an optional
+// resource ID, and the HTTP method to be used.
 // Example usage:
-//   * GetAPIMethodUrl(REQUEST_QUERY, "1234") will return "/v1/pages/1234".
-//   * GetAPIMethodUrl(REQUEST_UPLOAD, "") will return "/v1/forms:vote".
+// * GetAPIMethodUrl(REQUEST_QUERY, "1234", "GET") will return "/v1/pages/1234".
+// * GetAPIMethodUrl(REQUEST_QUERY, "1234", "POST") will return "/v1/pages:get".
+// * GetAPIMethodUrl(REQUEST_UPLOAD, "", "POST") will return "/v1/forms:vote".
 std::string GetAPIMethodUrl(AutofillDownloadManager::RequestType type,
-                            base::StringPiece resource_id) {
+                            base::StringPiece resource_id,
+                            base::StringPiece method) {
   const char* api_method_url;
   if (type == AutofillDownloadManager::REQUEST_QUERY) {
-    api_method_url = "/v1/pages";
+    if (method == "POST") {
+      api_method_url = "/v1/pages:get";
+    } else {
+      api_method_url = "/v1/pages";
+    }
   } else if (type == AutofillDownloadManager::REQUEST_UPLOAD) {
     api_method_url = "/v1/forms:vote";
   } else {
@@ -471,6 +476,35 @@
   return base::StrCat({api_method_url, "/", resource_id});
 }
 
+// Gets HTTP body payload for API POST request.
+std::string GetAPIBodyPayload(const std::string& payload,
+                              AutofillDownloadManager::RequestType type) {
+  // Don't do anything for payloads not related to Query.
+  if (type != AutofillDownloadManager::REQUEST_QUERY) {
+    return payload;
+  }
+  // Wrap query payload in a request proto to interface with API Query method.
+  AutofillPageResourceQueryRequest request;
+  request.set_serialized_request(payload);
+  std::string new_payload;
+  DCHECK(request.SerializeToString(&new_payload))
+      << "could not serialize AutofillPageResourceQueryRequest payload";
+  return new_payload;
+}
+
+// Gets the data payload for API Query (POST and GET).
+bool GetAPIQueryPayload(const AutofillQueryContents& query,
+                        std::string* payload) {
+  std::string serialized_query;
+  if (!CreateApiRequestFromLegacyRequest(query).SerializeToString(
+          &serialized_query)) {
+    return false;
+  }
+  base::Base64UrlEncode(serialized_query,
+                        base::Base64UrlEncodePolicy::INCLUDE_PADDING, payload);
+  return true;
+}
+
 }  // namespace
 
 struct AutofillDownloadManager::FormRequestData {
@@ -542,10 +576,8 @@
 
   // Get the query request payload.
   std::string payload;
-  bool is_payload_serialized =
-      UseApi()
-          ? CreateApiRequestFromLegacyRequest(query).SerializeToString(&payload)
-          : query.SerializeToString(&payload);
+  bool is_payload_serialized = UseApi() ? GetAPIQueryPayload(query, &payload)
+                                        : query.SerializeToString(&payload);
   if (!is_payload_serialized) {
     return false;
   }
@@ -641,6 +673,11 @@
   }
 }
 
+size_t AutofillDownloadManager::GetPayloadLength(
+    base::StringPiece payload) const {
+  return payload.length();
+}
+
 std::tuple<GURL, std::string> AutofillDownloadManager::GetRequestURLAndMethod(
     const FormRequestData& request_data) const {
   std::string method("POST");
@@ -674,31 +711,27 @@
   // ID of the resource to add to the API request URL. Nothing will be added if
   // |resource_id| is empty.
   std::string resource_id;
+  std::string method = "POST";
 
-  // Get the resource id of corresponding webpage when doing a query request.
   if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) {
-    if (request_data.payload.length() <= kMaxQueryGetSize) {
-      base::Base64UrlEncode(request_data.payload,
-                            base::Base64UrlEncodePolicy::INCLUDE_PADDING,
-                            &resource_id);
+    if (request_data.payload.length() <= kMaxAPIQueryGetSize) {
+      resource_id = request_data.payload;
+      method = "GET";
+      UMA_HISTOGRAM_BOOLEAN("Autofill.Query.ApiUrlIsTooLong", false);
+    } else {
+      UMA_HISTOGRAM_BOOLEAN("Autofill.Query.ApiUrlIsTooLong", true);
     }
-    // Query method is always GET (represented by 0) with API.
-    UMA_HISTOGRAM_BOOLEAN("Autofill.Query.Method", 0);
+    UMA_HISTOGRAM_BOOLEAN("Autofill.Query.Method", (method == "GET") ? 0 : 1);
   }
 
   // Make the canonical URL to query the API, e.g.,
   // https://autofill.googleapis.com/v1/forms/1234?alt=proto.
   GURL url = autofill_server_url_.Resolve(
-      GetAPIMethodUrl(request_data.request_type, resource_id));
+      GetAPIMethodUrl(request_data.request_type, resource_id, method));
 
   // Add the query parameter to set the response format to a serialized proto.
   url = net::AppendQueryParameter(url, "alt", "proto");
 
-  // Determine the HTTP method that should be used.
-  std::string method =
-      (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY)
-          ? "GET"
-          : "POST";
   return std::make_tuple(std::move(url), std::move(method));
 }
 
@@ -714,6 +747,14 @@
       UseApi() ? GetRequestURLAndMethodForApi(request_data)
                : GetRequestURLAndMethod(request_data);
 
+  // Track the URL length for GET queries because the URL length can be in the
+  // thousands when rich metadata is enabled.
+  if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY &&
+      method == "GET") {
+    UMA_HISTOGRAM_COUNTS_100000("Autofill.Query.GetUrlLength",
+                                request_url.spec().length());
+  }
+
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = request_url;
   resource_request->load_flags =
@@ -750,10 +791,14 @@
   simple_loader->SetAllowHttpErrorResults(true);
 
   if (method == "POST") {
-    const std::string content_type =
+    const std::string& content_type =
         UseApi() ? "application/x-protobuf" : "text/proto";
+    const std::string& payload =
+        UseApi()
+            ? GetAPIBodyPayload(request_data.payload, request_data.request_type)
+            : request_data.payload;
     // Attach payload data and add data format header.
-    simple_loader->AttachStringForUpload(request_data.payload, content_type);
+    simple_loader->AttachStringForUpload(payload, content_type);
   }
 
   // Transfer ownership of the loader into url_loaders_. Temporarily hang
diff --git a/components/autofill/core/browser/autofill_download_manager.h b/components/autofill/core/browser/autofill_download_manager.h
index f38c3ae8..4fb0ea0 100644
--- a/components/autofill/core/browser/autofill_download_manager.h
+++ b/components/autofill/core/browser/autofill_download_manager.h
@@ -17,6 +17,7 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/variations/variations_http_header_provider.h"
@@ -31,6 +32,8 @@
 class AutofillDriver;
 class FormStructure;
 
+const size_t kMaxAPIQueryGetSize = 10240;  // 10 KiB
+
 // A helper to make sure that tests which modify the set of active autofill
 // experiments do not interfere with one another.
 struct ScopedActiveAutofillExperiments {
@@ -114,6 +117,12 @@
   // pair.
   static void ClearUploadHistory(PrefService* pref_service);
 
+ protected:
+  // Gets the length of the payload from request data. Used to simulate
+  // different payload sizes when testing without the need for data. Do not use
+  // this when the length is needed to read/write a buffer.
+  virtual size_t GetPayloadLength(base::StringPiece payload) const;
+
  private:
   friend class AutofillDownloadManagerTest;
   friend struct ScopedActiveAutofillExperiments;
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc
index b6c34b6..dc65b18 100644
--- a/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -52,6 +52,7 @@
 #include "services/network/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/re2/src/re2/re2.h"
 #include "url/third_party/mozilla/url_parse.h"
 
 using base::UTF8ToUTF16;
@@ -117,6 +118,54 @@
   return true;
 }
 
+bool GetAutofillPageResourceQueryRequestFromRequest(
+    network::TestURLLoaderFactory::PendingRequest* loader_request,
+    AutofillPageResourceQueryRequest* query_request) {
+  if (loader_request->request.request_body == nullptr) {
+    return false;
+  }
+
+  std::string request_body_content = GetStringFromDataElements(
+      loader_request->request.request_body->elements());
+  if (!query_request->ParseFromString(request_body_content)) {
+    return false;
+  }
+  return true;
+}
+
+bool DeserializeAutofillPageQueryRequest(base::StringPiece serialized_content,
+                                         AutofillPageQueryRequest* request) {
+  std::string decoded_content;
+  if (!base::Base64UrlDecode(serialized_content,
+                             base::Base64UrlDecodePolicy::REQUIRE_PADDING,
+                             &decoded_content)) {
+    return false;
+  }
+  if (!request->ParseFromString(decoded_content)) {
+    return false;
+  }
+  return true;
+}
+
+class AutofillDownloadManagerWithCustomPayloadSize
+    : public AutofillDownloadManager {
+ public:
+  ~AutofillDownloadManagerWithCustomPayloadSize() override {}
+  AutofillDownloadManagerWithCustomPayloadSize(AutofillDriver* driver,
+                                               Observer* observer,
+                                               const std::string& api_key,
+                                               size_t length)
+      : AutofillDownloadManager(driver, observer, api_key), length_(length) {}
+
+ protected:
+  size_t GetPayloadLength(base::StringPiece payload) const override {
+    return length_;
+  }
+
+ private:
+  size_t length_;
+};
+
 }  // namespace
 
 // This tests AutofillDownloadManager. AutofillDownloadManagerTest implements
@@ -499,22 +548,151 @@
   // Inspect the request that the test URL loader sent.
   network::TestURLLoaderFactory::PendingRequest* request =
       test_url_loader_factory_.GetPendingRequest(0);
-  // This is the URL we expect to query the API. The sub-path right after
-  // "/page" corresponds to the serialized AutofillPageQueryRequest proto (that
-  // we filled forms in) encoded in base64. The Autofill
-  // https://clients1.google.com/ domain URL corresponds to the default domain
-  // used by the download manager.
-  const std::string expected_url = {
-      "https://clients1.google.com/v1/pages/"
-      "Chc2LjEuMTcxNS4xNDQyL2VuIChHR0xMKRIlCU9O84MyjH9NEgsNeu"
-      "FP4BIAGgAiABILDZxOStASABoAIgAaAA==?"
-      "alt=proto"};
-  EXPECT_EQ(request->request.url, expected_url);
-  std::string api_key_header_value;
-  EXPECT_TRUE(request->request.headers.GetHeader("X-Goog-Api-Key",
-                                                 &api_key_header_value));
-  EXPECT_EQ(api_key_header_value, "dummykey");
 
+  // Verify request URL and the data payload it carries.
+  {
+    // This is the URL we expect to query the API. The sub-path right after
+    // "/page" corresponds to the serialized AutofillPageQueryRequest proto
+    // (that we filled forms in) encoded in base64. The Autofill
+    // https://clients1.google.com/ domain URL corresponds to the default domain
+    // used by the download manager, which is invalid, but good for testing.
+    const std::string expected_url =
+        R"(https://clients1.google.com/v1/pages/(.+)\?alt=proto)";
+    std::string encoded_request;
+    ASSERT_TRUE(re2::RE2::FullMatch(request->request.url.spec(), expected_url,
+                                    &encoded_request));
+    AutofillPageQueryRequest request_content;
+    ASSERT_TRUE(
+        DeserializeAutofillPageQueryRequest(encoded_request, &request_content));
+    // Verify form content.
+    ASSERT_EQ(request_content.forms().size(), 1);
+    EXPECT_EQ(request_content.forms(0).signature(),
+              form_structures[0]->form_signature());
+    // Verify field content.
+    ASSERT_EQ(request_content.forms(0).fields().size(), 2);
+    EXPECT_EQ(request_content.forms(0).fields(0).signature(),
+              form_structures[0]->field(0)->GetFieldSignature());
+    EXPECT_EQ(request_content.forms(0).fields(1).signature(),
+              form_structures[0]->field(1)->GetFieldSignature());
+  }
+
+  // Verify API key header.
+  {
+    std::string header_value;
+    EXPECT_TRUE(
+        request->request.headers.GetHeader("X-Goog-Api-Key", &header_value));
+    EXPECT_EQ(header_value, "dummykey");
+  }
+  // Verify binary response header.
+  {
+    std::string header_value;
+    ASSERT_TRUE(request->request.headers.GetHeader(
+        "X-Goog-Encode-Response-If-Executable", &header_value));
+    EXPECT_EQ(header_value, "base64");
+  }
+
+  // Verify response.
+  test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
+      request, "dummy response");
+  // Upon reception of a suggestions query, we expect OnLoadedServerPredictions
+  // to be called back from the observer and some histograms be incremented.
+  EXPECT_EQ(1U, responses_.size());
+  EXPECT_EQ(responses_.front().type_of_response,
+            AutofillDownloadManagerTest::QUERY_SUCCESSFULL);
+  histogram.ExpectBucketCount("Autofill.Query.WasInCache", CACHE_MISS, 1);
+  histogram.ExpectBucketCount("Autofill.Query.HttpResponseOrErrorCode",
+                              net::HTTP_OK, 1);
+}
+
+TEST_F(AutofillDownloadManagerTest, QueryAPITestWhenTooLongUrl) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      // Enabled
+      // We want to query the API rather than the legacy server.
+      {features::kAutofillUseApi},
+      // Disabled
+      {});
+
+  // Build the form structures that we want to query.
+  FormData form;
+  FormFieldData field;
+  // Fill a really long field that will bust the request URL size limit of 10
+  // KiB. This is not a lot of memory, hence this should not cause problems for
+  // machines running this test. This will force the fallback to POST.
+  field.name_attribute = base::string16(kMaxAPIQueryGetSize, 'a');
+  field.form_control_type = "text";
+  form.fields.push_back(field);
+
+  std::vector<std::unique_ptr<FormStructure>> form_structures;
+  {
+    auto form_structure = std::make_unique<FormStructure>(form);
+    form_structure->set_is_rich_query_enabled(true);
+    form_structures.push_back(std::move(form_structure));
+  }
+
+  AutofillDownloadManagerWithCustomPayloadSize download_manager(
+      &driver_, this, "dummykey", kMaxAPIQueryGetSize);
+
+  // Start the query request and look if it is successful. No response was
+  // received yet.
+  base::HistogramTester histogram;
+  EXPECT_TRUE(
+      download_manager.StartQueryRequest(ToRawPointerVector(form_structures)));
+
+  // Verify request.
+  // Verify if histograms are right.
+  histogram.ExpectUniqueSample("Autofill.ServerQueryResponse",
+                               AutofillMetrics::QUERY_SENT, 1);
+  // Verify that the logged method is POST.
+  histogram.ExpectUniqueSample("Autofill.Query.Method", METHOD_POST, 1);
+
+  // Get the latest request that the test URL loader sent.
+  network::TestURLLoaderFactory::PendingRequest* request =
+      test_url_loader_factory_.GetPendingRequest(0);
+  // Verify that the POST URL is used when request data too large.
+  const std::string expected_url = {
+      "https://clients1.google.com/v1/pages:get?alt=proto"};
+  // Verify API key header.
+  EXPECT_EQ(request->request.url, expected_url);
+  {
+    std::string header_value;
+    EXPECT_TRUE(
+        request->request.headers.GetHeader("X-Goog-Api-Key", &header_value));
+    EXPECT_EQ(header_value, "dummykey");
+  }
+  // Verify Content-Type header.
+  {
+    std::string header_value;
+    ASSERT_TRUE(
+        request->request.headers.GetHeader("Content-Type", &header_value));
+    EXPECT_EQ(header_value, "application/x-protobuf");
+  }
+  // Verify binary response header.
+  {
+    std::string header_value;
+    ASSERT_TRUE(request->request.headers.GetHeader(
+        "X-Goog-Encode-Response-If-Executable", &header_value));
+    EXPECT_EQ(header_value, "base64");
+  }
+  // Verify content of the POST body data.
+  {
+    AutofillPageResourceQueryRequest query_request;
+    ASSERT_TRUE(GetAutofillPageResourceQueryRequestFromRequest(request,
+                                                               &query_request));
+    AutofillPageQueryRequest request_content;
+    ASSERT_TRUE(DeserializeAutofillPageQueryRequest(
+        query_request.serialized_request(), &request_content));
+    // Verify form content.
+    ASSERT_EQ(request_content.forms().size(), 1);
+    EXPECT_EQ(request_content.forms(0).signature(),
+              form_structures[0]->form_signature());
+    // Verify field content.
+    ASSERT_EQ(request_content.forms(0).fields().size(), 1);
+    EXPECT_EQ(request_content.forms(0).fields(0).signature(),
+              form_structures[0]->field(0)->GetFieldSignature());
+  }
+
+  // Verify response.
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
       request, "dummy response");
   // Upon reception of a suggestions query, we expect OnLoadedServerPredictions
diff --git a/components/crash/content/app/breakpad_linux.cc b/components/crash/content/app/breakpad_linux.cc
index ecc7d66..3ab8ad2 100644
--- a/components/crash/content/app/breakpad_linux.cc
+++ b/components/crash/content/app/breakpad_linux.cc
@@ -1540,7 +1540,7 @@
   google_breakpad::PageAllocator allocator;
   const char* exe_buf = nullptr;
 
-  if (GetCrashReporterClient()->HandleCrashDump(info.filename)) {
+  if (GetCrashReporterClient()->HandleCrashDump(info.filename, info.pid)) {
     return;
   }
 
diff --git a/components/crash/content/app/crash_reporter_client.cc b/components/crash/content/app/crash_reporter_client.cc
index c3c3f9d..4d2b6ad 100644
--- a/components/crash/content/app/crash_reporter_client.cc
+++ b/components/crash/content/app/crash_reporter_client.cc
@@ -101,7 +101,8 @@
   return base::FilePath();
 }
 
-bool CrashReporterClient::HandleCrashDump(const char* crashdump_filename) {
+bool CrashReporterClient::HandleCrashDump(const char* crashdump_filename,
+                                          uint64_t crash_pid) {
   return false;
 }
 #endif
diff --git a/components/crash/content/app/crash_reporter_client.h b/components/crash/content/app/crash_reporter_client.h
index 1d35caa3..d46bcc2a3 100644
--- a/components/crash/content/app/crash_reporter_client.h
+++ b/components/crash/content/app/crash_reporter_client.h
@@ -109,7 +109,8 @@
   // to fallback to default handler.
   // WARNING: this handler runs in a compromised context. It may not call into
   // libc nor allocate memory normally.
-  virtual bool HandleCrashDump(const char* crashdump_filename);
+  virtual bool HandleCrashDump(const char* crashdump_filename,
+                               uint64_t crash_pid);
 #endif
 
   // The location where minidump files should be written. Returns true if
diff --git a/components/feed/content/feed_offline_host.cc b/components/feed/content/feed_offline_host.cc
index b49d4ab7..1764a9f 100644
--- a/components/feed/content/feed_offline_host.cc
+++ b/components/feed/content/feed_offline_host.cc
@@ -260,10 +260,9 @@
   notify_status_change_.Run(url, true);
 }
 
-void FeedOfflineHost::OfflinePageDeleted(
-    const OfflinePageModel::DeletedPageInfo& page_info) {
+void FeedOfflineHost::OfflinePageDeleted(const OfflinePageItem& deleted_page) {
   DCHECK(!notify_status_change_.is_null());
-  const std::string& url = page_info.url.spec();
+  const std::string& url = deleted_page.url.spec();
   EvictOfflinePageUrl(url);
   notify_status_change_.Run(url, false);
 }
diff --git a/components/feed/content/feed_offline_host.h b/components/feed/content/feed_offline_host.h
index c72a1cc..52e7f3c 100644
--- a/components/feed/content/feed_offline_host.h
+++ b/components/feed/content/feed_offline_host.h
@@ -99,8 +99,7 @@
       offline_pages::OfflinePageModel* model,
       const offline_pages::OfflinePageItem& added_page) override;
   void OfflinePageDeleted(
-      const offline_pages::OfflinePageModel::DeletedPageInfo& page_info)
-      override;
+      const offline_pages::OfflinePageItem& deleted_page) override;
 
  private:
   // Stores the given record in |url_hash_to_id_|. If there's a conflict, the
diff --git a/components/feed/content/feed_offline_host_unittest.cc b/components/feed/content/feed_offline_host_unittest.cc
index fb1a9c129..e27102bfc 100644
--- a/components/feed/content/feed_offline_host_unittest.cc
+++ b/components/feed/content/feed_offline_host_unittest.cc
@@ -394,10 +394,10 @@
   host()->GetOfflineStatus({kUrl1}, base::BindOnce(&IgnoreStatus));
   RunUntilIdle();
   EXPECT_EQ(host()->GetOfflineId(kUrl1).value(), 4);
-  OfflinePageModel::DeletedPageInfo page_info;
-  page_info.url = GURL(kUrl1);
+  OfflinePageItem page_item;
+  page_item.url = GURL(kUrl1);
 
-  host()->OfflinePageDeleted(page_info);
+  host()->OfflinePageDeleted(page_item);
 
   EXPECT_EQ(1U, get_status_notifications().size());
   EXPECT_EQ(kUrl1, get_status_notifications()[0].first);
diff --git a/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc b/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
index 8ca23916..0f94795 100644
--- a/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
+++ b/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
@@ -52,8 +52,8 @@
     // already waiting.
     if (initialization_completed_callbacks_.size() == 1) {
       PageCriteria criteria;
-      criteria.client_namespaces.push_back(
-          offline_pages::kSuggestedArticlesNamespace);
+      criteria.client_namespaces =
+          std::vector<std::string>{offline_pages::kSuggestedArticlesNamespace};
       offline_page_model_->GetPagesWithCriteria(
           criteria,
           base::BindOnce(&PrefetchedPagesTrackerImpl::OfflinePagesLoaded,
@@ -86,8 +86,8 @@
 }
 
 void PrefetchedPagesTrackerImpl::OfflinePageDeleted(
-    const offline_pages::OfflinePageModel::DeletedPageInfo& page_info) {
-  auto offline_id_it = offline_id_to_url_mapping_.find(page_info.offline_id);
+    const offline_pages::OfflinePageItem& deleted_page) {
+  auto offline_id_it = offline_id_to_url_mapping_.find(deleted_page.offline_id);
 
   if (offline_id_it == offline_id_to_url_mapping_.end()) {
     // We did not know about this page, thus, nothing to delete.
diff --git a/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h b/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h
index ee5fb2d..a3eade67 100644
--- a/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h
+++ b/components/ntp_snippets/remote/prefetched_pages_tracker_impl.h
@@ -41,8 +41,7 @@
       offline_pages::OfflinePageModel* model,
       const offline_pages::OfflinePageItem& added_page) override;
   void OfflinePageDeleted(
-      const offline_pages::OfflinePageModel::DeletedPageInfo& page_info)
-      override;
+      const offline_pages::OfflinePageItem& deleted_page) override;
 
  private:
   void OfflinePagesLoaded(const std::vector<offline_pages::OfflinePageItem>&
diff --git a/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc b/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
index 2a8458a6..5f982339 100644
--- a/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
+++ b/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
@@ -142,9 +142,9 @@
 
   ASSERT_TRUE(
       tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
-  tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
-      item.offline_id, kSystemDownloadId, item.client_id,
-      /*request_origin=*/"", item.original_url_if_different));
+  OfflinePageItem deleted_item = item;
+  deleted_item.system_download_id = kSystemDownloadId;
+  tracker.OfflinePageDeleted(deleted_item);
   EXPECT_FALSE(
       tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
 }
@@ -164,11 +164,9 @@
 
   ASSERT_TRUE(
       tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
-  tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
-      manually_downloaded_item.offline_id, kSystemDownloadId,
-      manually_downloaded_item.client_id,
-      /*request_origin=*/"",
-      manually_downloaded_item.original_url_if_different));
+  OfflinePageItem deleted_item = manually_downloaded_item;
+  deleted_item.system_download_id = kSystemDownloadId;
+  tracker.OfflinePageDeleted(deleted_item);
   EXPECT_TRUE(
       tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
 }
@@ -267,9 +265,9 @@
   ASSERT_TRUE(
       tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
 
-  tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
-      first_item.offline_id, kSystemDownloadId, first_item.client_id,
-      /*request_origin=*/"", first_item.original_url_if_different));
+  OfflinePageItem deleted_item = first_item;
+  deleted_item.system_download_id = kSystemDownloadId;
+  tracker.OfflinePageDeleted(deleted_item);
 
   // Only one offline page (out of two) has been removed, the remaining one
   // should be reported here.
@@ -292,16 +290,16 @@
   ASSERT_TRUE(
       tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
 
-  tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
-      first_item.offline_id, kSystemDownloadId, first_item.client_id,
-      /*request_origin=*/"", first_item.original_url_if_different));
+  OfflinePageItem first_deleted_item = first_item;
+  first_deleted_item.system_download_id = kSystemDownloadId;
+  tracker.OfflinePageDeleted(first_deleted_item);
 
   ASSERT_TRUE(
       tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
 
-  tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
-      second_item.offline_id, kSystemDownloadId, second_item.client_id,
-      /*request_origin=*/"", second_item.original_url_if_different));
+  OfflinePageItem second_deleted_item = second_item;
+  second_deleted_item.system_download_id = kSystemDownloadId;
+  tracker.OfflinePageDeleted(second_deleted_item);
 
   // All offline pages have been removed, their absence should be reported here.
   EXPECT_FALSE(
diff --git a/components/offline_pages/core/client_policy_controller.cc b/components/offline_pages/core/client_policy_controller.cc
index 8fd74baa..02392790c 100644
--- a/components/offline_pages/core/client_policy_controller.cc
+++ b/components/offline_pages/core/client_policy_controller.cc
@@ -30,7 +30,6 @@
 }  // namespace
 
 ClientPolicyController::ClientPolicyController() {
-  policies_.clear();
   // Manually defining client policies for bookmark and last_n.
   policies_.emplace(
       kBookmarkNamespace,
@@ -122,12 +121,8 @@
     const std::string& name = policy_item.first;
     if (policy_item.second.feature_policy.is_removed_on_cache_reset)
       cache_reset_namespaces_.push_back(name);
-    if (policy_item.second.feature_policy.is_supported_by_download)
-      download_namespaces_.push_back(name);
     if (policy_item.second.feature_policy.is_user_requested_download)
       user_requested_download_namespaces_.push_back(name);
-    if (policy_item.second.feature_policy.is_supported_by_recent_tabs)
-      recent_tab_namespaces_.push_back(name);
   }
 }
 
@@ -171,11 +166,6 @@
 }
 
 const std::vector<std::string>&
-ClientPolicyController::GetNamespacesSupportedByDownload() const {
-  return download_namespaces_;
-}
-
-const std::vector<std::string>&
 ClientPolicyController::GetNamespacesForUserRequestedDownload() const {
   return user_requested_download_namespaces_;
 }
@@ -185,11 +175,6 @@
   return GetPolicy(name_space).feature_policy.is_supported_by_recent_tabs;
 }
 
-const std::vector<std::string>&
-ClientPolicyController::GetNamespacesShownAsRecentlyVisitedSite() const {
-  return recent_tab_namespaces_;
-}
-
 bool ClientPolicyController::IsRestrictedToTabFromClientId(
     const std::string& name_space) const {
   return GetPolicy(name_space)
diff --git a/components/offline_pages/core/client_policy_controller.h b/components/offline_pages/core/client_policy_controller.h
index c58e590..5bb77c0e 100644
--- a/components/offline_pages/core/client_policy_controller.h
+++ b/components/offline_pages/core/client_policy_controller.h
@@ -35,7 +35,6 @@
 
   // Returns whether pages for |name_space| are shown in Download UI.
   bool IsSupportedByDownload(const std::string& name_space) const;
-  const std::vector<std::string>& GetNamespacesSupportedByDownload() const;
 
   // Returns whether pages for |name_space| are explicitly offlined due to user
   // action.
@@ -45,8 +44,6 @@
   // Returns whether pages for |name_space| are shown in recent tabs UI,
   // currently only available on NTP.
   bool IsShownAsRecentlyVisitedSite(const std::string& name_space) const;
-  const std::vector<std::string>& GetNamespacesShownAsRecentlyVisitedSite()
-      const;
 
   // Returns whether pages for |name_space| should only be opened in a
   // specifically assigned tab.
@@ -70,9 +67,7 @@
   std::map<std::string, OfflinePageClientPolicy> policies_;
 
   std::vector<std::string> cache_reset_namespaces_;
-  std::vector<std::string> download_namespaces_;
   std::vector<std::string> user_requested_download_namespaces_;
-  std::vector<std::string> recent_tab_namespaces_;
 };
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/client_policy_controller_unittest.cc b/components/offline_pages/core/client_policy_controller_unittest.cc
index 084c72d..bc8950d4 100644
--- a/components/offline_pages/core/client_policy_controller_unittest.cc
+++ b/components/offline_pages/core/client_policy_controller_unittest.cc
@@ -64,12 +64,6 @@
 
 void ClientPolicyControllerTest::ExpectDownloadSupport(std::string name_space,
                                                        bool expectation) {
-  EXPECT_EQ(expectation,
-            base::ContainsValue(
-                controller()->GetNamespacesSupportedByDownload(), name_space))
-      << "Namespace " << name_space
-      << " had incorrect download support when getting namespaces supported by"
-         " download.";
   EXPECT_EQ(expectation, controller()->IsSupportedByDownload(name_space))
       << "Namespace " << name_space
       << " had incorrect download support when directly checking if supported"
@@ -94,13 +88,6 @@
 
 void ClientPolicyControllerTest::ExpectRecentTab(std::string name_space,
                                                  bool expectation) {
-  EXPECT_EQ(
-      expectation,
-      base::ContainsValue(
-          controller()->GetNamespacesShownAsRecentlyVisitedSite(), name_space))
-      << "Namespace " << name_space
-      << " had incorrect recent tab support when getting namespaces shown as a"
-         " recently visited site.";
   EXPECT_EQ(expectation, controller()->IsShownAsRecentlyVisitedSite(name_space))
       << "Namespace " << name_space
       << " had incorrect recent tab support when directly checking if shown as"
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.cc b/components/offline_pages/core/downloads/download_ui_adapter.cc
index 2baebb4b..ee0b047 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter.cc
+++ b/components/offline_pages/core/downloads/download_ui_adapter.cc
@@ -148,14 +148,12 @@
 }
 
 // OfflinePageModel::Observer
-void DownloadUIAdapter::OfflinePageDeleted(
-    const OfflinePageModel::DeletedPageInfo& page_info) {
-  if (!delegate_->IsVisibleInUI(page_info.client_id))
+void DownloadUIAdapter::OfflinePageDeleted(const OfflinePageItem& item) {
+  if (!delegate_->IsVisibleInUI(item.client_id))
     return;
 
   for (auto& observer : observers_) {
-    observer.OnItemRemoved(
-        ContentId(kOfflinePageNamespace, page_info.client_id.id));
+    observer.OnItemRemoved(ContentId(kOfflinePageNamespace, item.client_id.id));
   }
 }
 
@@ -437,16 +435,12 @@
 }
 
 void DownloadUIAdapter::RemoveItem(const ContentId& id) {
-  std::vector<ClientId> client_ids;
-  auto* policy_controller = model_->GetPolicyController();
-  for (const auto& name_space :
-       policy_controller->GetNamespacesSupportedByDownload()) {
-    client_ids.push_back(ClientId(name_space, id.id));
-  }
-
-  model_->DeletePagesByClientIds(
-      client_ids, base::BindRepeating(&DownloadUIAdapter::OnDeletePagesDone,
-                                      weak_ptr_factory_.GetWeakPtr()));
+  PageCriteria criteria;
+  criteria.supported_by_downloads = true;
+  criteria.guid = id.id;
+  model_->DeletePagesWithCriteria(
+      criteria, base::BindRepeating(&DownloadUIAdapter::OnDeletePagesDone,
+                                    weak_ptr_factory_.GetWeakPtr()));
 }
 
 void DownloadUIAdapter::CancelDownload(const ContentId& id) {
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.h b/components/offline_pages/core/downloads/download_ui_adapter.h
index f2a58e3..a370f77 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter.h
+++ b/components/offline_pages/core/downloads/download_ui_adapter.h
@@ -114,8 +114,7 @@
   void OfflinePageModelLoaded(OfflinePageModel* model) override;
   void OfflinePageAdded(OfflinePageModel* model,
                         const OfflinePageItem& added_page) override;
-  void OfflinePageDeleted(
-      const OfflinePageModel::DeletedPageInfo& page_info) override;
+  void OfflinePageDeleted(const OfflinePageItem& item) override;
   void ThumbnailAdded(OfflinePageModel* model,
                       const int64_t offline_id,
                       const std::string& thumbnail) override;
diff --git a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
index 3dcddae..e1d485d4 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
+++ b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
@@ -50,7 +50,6 @@
 // Constants for a test OfflinePageItem.
 static const int kTestOfflineId1 = 1;
 static const int kTestOfflineId2 = 2;
-static const int64_t kSystemDownloadId = 0;
 static const char kTestUrl[] = "http://foo.com/bar.mhtml";
 static const char kTestGuid1[] = "cccccccc-cccc-4ccc-0ccc-ccccccccccc1";
 static const char kTestGuid2[] = "cccccccc-cccc-4ccc-0ccc-ccccccccccc2";
@@ -159,10 +158,7 @@
   void DeletePageAndNotifyAdapter(const std::string& guid) {
     for (const auto& page : pages) {
       if (page.second.client_id.id == guid) {
-        DeletedPageInfo info(page.second.offline_id, kSystemDownloadId,
-                             page.second.client_id, page.second.request_origin,
-                             page.second.original_url_if_different);
-        observer_->OfflinePageDeleted(info);
+        observer_->OfflinePageDeleted(page.second);
         pages.erase(page.first);
         return;
       }
diff --git a/components/offline_pages/core/model/clear_storage_task.cc b/components/offline_pages/core/model/clear_storage_task.cc
index 1c0ea825..9f9799b 100644
--- a/components/offline_pages/core/model/clear_storage_task.cc
+++ b/components/offline_pages/core/model/clear_storage_task.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <map>
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -17,6 +18,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "components/offline_pages/core/client_policy_controller.h"
+#include "components/offline_pages/core/model/delete_page_task.h"
 #include "components/offline_pages/core/offline_page_client_policy.h"
 #include "components/offline_pages/core/offline_page_metadata_store.h"
 #include "components/offline_pages/core/offline_store_utils.h"
@@ -172,14 +174,6 @@
   return base::DeleteFile(file_path, false);
 }
 
-// Deletes a page from the store by |offline_id|.
-bool DeletePageEntryByOfflineIdSync(sql::Database* db, int64_t offline_id) {
-  static const char kSql[] = "DELETE FROM offlinepages_v1 WHERE offline_id = ?";
-  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  statement.BindInt64(0, offline_id);
-  return statement.Run();
-}
-
 std::pair<size_t, DeletePageResult> ClearPagesSync(
     std::map<std::string, LifetimePolicy> temp_namespace_policy_map,
     const base::Time& start_time,
@@ -192,7 +186,7 @@
   for (const auto& page_info : *page_infos) {
     if (!base::PathExists(page_info.file_path) ||
         DeleteArchiveSync(page_info.file_path)) {
-      if (DeletePageEntryByOfflineIdSync(db, page_info.offline_id)) {
+      if (DeletePageTask::DeletePageFromDbSync(page_info.offline_id, db)) {
         pages_cleared++;
         // Reports the time since creation in minutes.
         base::TimeDelta time_since_creation =
diff --git a/components/offline_pages/core/model/delete_page_task.cc b/components/offline_pages/core/model/delete_page_task.cc
index 159bed38..fe2675e 100644
--- a/components/offline_pages/core/model/delete_page_task.cc
+++ b/components/offline_pages/core/model/delete_page_task.cc
@@ -5,6 +5,8 @@
 #include "components/offline_pages/core/model/delete_page_task.h"
 
 #include <iterator>
+#include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
@@ -13,6 +15,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/offline_pages/core/client_policy_controller.h"
+#include "components/offline_pages/core/model/get_pages_task.h"
 #include "components/offline_pages/core/model/offline_page_model_utils.h"
 #include "components/offline_pages/core/offline_clock.h"
 #include "components/offline_pages/core/offline_page_client_policy.h"
@@ -26,91 +29,35 @@
 
 namespace offline_pages {
 
+struct DeletePageTask::DeletePageTaskResult {
+  DeletePageTaskResult() = default;
+  DeletePageTaskResult(DeletePageResult result,
+                       const std::vector<OfflinePageItem>& deleted_pages)
+      : result(result), deleted_pages(deleted_pages) {}
+  DeletePageTaskResult(DeletePageTaskResult&& other) = default;
+  DeletePageTaskResult(const DeletePageTaskResult& other) = delete;
+  ~DeletePageTaskResult() = default;
+
+  DeletePageResult result;
+  std::vector<OfflinePageItem> deleted_pages;
+};
 using DeletePageTaskResult = DeletePageTask::DeletePageTaskResult;
 
 namespace {
 
-#define OFFLINE_PAGES_TABLE_NAME "offlinepages_v1"
-
-// A wrapper of DeletedPageInfo to include |file_path| in order to be used
-// through the deletion process. This is implementation detail and it will be
-// used to create OfflinePageModel::DeletedPageInfo that are passed through
-// callback.
-// Please keep WRAPPER_FIELDS, WRAPPER_FIELD_COUNT, the struct declaration of
-// DeletedPageInfoWrapper and the method CreateInfoWrapper in sync.
-// The WRAPPER_FIELD_COUNT is used for queries which requires more info than the
-// fields of INFO_WRAPPER_FIELD, as the additional field can be added manually
-// in the SQL query and the result of it can be simply fetched by calling
-// statement.Column*(INFO_WRAPPER_COUNT), as it's the last column. For example,
-// please take a look at GetCachedDeletedPageInfoWrappersByUrlPredicateSync.
-#define INFO_WRAPPER_FIELDS                                             \
-  "offline_id,system_download_id,client_namespace,client_id,file_path," \
-  "request_origin,access_count,creation_time,online_url,original_url"
-#define INFO_WRAPPER_FIELD_COUNT 10
-
-struct DeletedPageInfoWrapper {
-  DeletedPageInfoWrapper() = default;
-  // Move-only to avoid copies.
-  DeletedPageInfoWrapper(const DeletedPageInfoWrapper& other) = delete;
-  DeletedPageInfoWrapper(DeletedPageInfoWrapper&& other) = default;
-  DeletedPageInfoWrapper& operator=(DeletedPageInfoWrapper&& other) = default;
-
-  int64_t offline_id;
-  int64_t system_download_id;
-  ClientId client_id;
-  base::FilePath file_path;
-  std::string request_origin;
-  // Used by metric collection only:
-  int access_count;
-  base::Time creation_time;
-  GURL url;
-  GURL original_url_if_different;
-};
-
-// Consumes |wrapper| and returns an |OfflinePageModel::DeletePageInfo|.
-OfflinePageModel::DeletedPageInfo ExtractPageInfo(
-    DeletedPageInfoWrapper&& wrapper) {
-  OfflinePageModel::DeletedPageInfo info;
-  info.offline_id = wrapper.offline_id;
-  info.system_download_id = wrapper.system_download_id;
-  info.client_id = std::move(wrapper.client_id);
-  info.request_origin = std::move(wrapper.request_origin);
-  info.url = std::move(wrapper.url);
-  info.original_url_if_different = std::move(wrapper.original_url_if_different);
-  return info;
-}
-
-DeletedPageInfoWrapper CreateInfoWrapper(const sql::Statement& statement) {
-  DeletedPageInfoWrapper info_wrapper;
-  info_wrapper.offline_id = statement.ColumnInt64(0);
-  info_wrapper.system_download_id = statement.ColumnInt64(1);
-  info_wrapper.client_id.name_space = statement.ColumnString(2);
-  info_wrapper.client_id.id = statement.ColumnString(3);
-  info_wrapper.file_path =
-      store_utils::FromDatabaseFilePath(statement.ColumnString(4));
-  info_wrapper.request_origin = statement.ColumnString(5);
-  info_wrapper.access_count = statement.ColumnInt(6);
-  info_wrapper.creation_time =
-      store_utils::FromDatabaseTime(statement.ColumnInt64(7));
-  info_wrapper.url = GURL(statement.ColumnString(8));
-  info_wrapper.original_url_if_different = GURL(statement.ColumnString(9));
-  return info_wrapper;
-}
-
 void ReportDeletePageHistograms(
-    const std::vector<DeletedPageInfoWrapper>& info_wrappers) {
+    const std::vector<OfflinePageItem>& deleted_pages) {
   const int max_minutes = base::TimeDelta::FromDays(365).InMinutes();
   base::Time delete_time = OfflineTimeNow();
-  for (const auto& info_wrapper : info_wrappers) {
+  for (const auto& item : deleted_pages) {
     base::UmaHistogramCustomCounts(
-        model_utils::AddHistogramSuffix(info_wrapper.client_id.name_space,
+        model_utils::AddHistogramSuffix(item.client_id.name_space,
                                         "OfflinePages.PageLifetime"),
-        (delete_time - info_wrapper.creation_time).InMinutes(), 1, max_minutes,
-        100);
+        (delete_time - item.creation_time).InMinutes(), 1, max_minutes, 100);
     base::UmaHistogramCustomCounts(
-        model_utils::AddHistogramSuffix(info_wrapper.client_id.name_space,
+        model_utils::AddHistogramSuffix(item.client_id.name_space,
                                         "OfflinePages.AccessCount"),
-        info_wrapper.access_count, 1, 1000000, 50);
+        item.access_count, 1, 1000000, 50);
   }
 }
 
@@ -119,15 +66,6 @@
   return base::DeleteFile(file_path, false);
 }
 
-// Deletes a page from the store by |offline_id|.
-bool DeletePageEntryByOfflineIdSync(sql::Database* db, int64_t offline_id) {
-  static const char kSql[] =
-      "DELETE FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id = ?";
-  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  statement.BindInt64(0, offline_id);
-  return statement.Run();
-}
-
 // Deletes pages by DeletedPageInfoWrapper. This will return a
 // DeletePageTaskResult which contains the infos of the deleted pages (which are
 // successfully deleted from the disk and the store) and a DeletePageResult.
@@ -136,280 +74,87 @@
 // issue of leaving archive files behind (and they may be imported later).
 // Since the database entry will only be deleted while the associated archive
 // file is deleted successfully, there will be no such issue.
-DeletePageTaskResult DeletePagesByDeletedPageInfoWrappersSync(
+DeletePageTaskResult DeletePagesSync(
     sql::Database* db,
-    std::vector<DeletedPageInfoWrapper> info_wrappers) {
-  std::vector<OfflinePageModel::DeletedPageInfo> deleted_page_infos;
+    std::vector<OfflinePageItem> pages_to_delete) {
+  std::vector<OfflinePageItem> deleted_pages;
 
   // If there's no page to delete, return an empty list with SUCCESS.
-  if (info_wrappers.size() == 0)
-    return DeletePageTaskResult(DeletePageResult::SUCCESS, deleted_page_infos);
+  if (pages_to_delete.size() == 0)
+    return {DeletePageResult::SUCCESS, deleted_pages};
 
-  ReportDeletePageHistograms(info_wrappers);
+  ReportDeletePageHistograms(pages_to_delete);
 
   bool any_archive_deleted = false;
-  for (auto& info_wrapper : info_wrappers) {
-    if (DeleteArchiveSync(info_wrapper.file_path)) {
+  for (auto& item : pages_to_delete) {
+    if (DeleteArchiveSync(item.file_path)) {
       any_archive_deleted = true;
-      if (DeletePageEntryByOfflineIdSync(db, info_wrapper.offline_id)) {
-        deleted_page_infos.push_back(ExtractPageInfo(std::move(info_wrapper)));
-      }
+      if (DeletePageTask::DeletePageFromDbSync(item.offline_id, db))
+        deleted_pages.push_back(std::move(item));
     }
   }
   // If there're no files deleted, return DEVICE_FAILURE.
   if (!any_archive_deleted)
-    return DeletePageTaskResult(DeletePageResult::DEVICE_FAILURE,
-                                deleted_page_infos);
+    return {DeletePageResult::DEVICE_FAILURE, std::move(deleted_pages)};
 
-  return DeletePageTaskResult(DeletePageResult::SUCCESS, deleted_page_infos);
+  return {DeletePageResult::SUCCESS, std::move(deleted_pages)};
 }
 
-// Gets the page info for |offline_id|, returning in |info_wrapper|. Returns
-// false if there's no record for |offline_id|.
-bool GetDeletedPageInfoWrapperByOfflineIdSync(
-    sql::Database* db,
-    int64_t offline_id,
-    DeletedPageInfoWrapper* info_wrapper) {
-  static const char kSql[] =
-      "SELECT " INFO_WRAPPER_FIELDS " FROM " OFFLINE_PAGES_TABLE_NAME
-      " WHERE offline_id = ?";
-  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  statement.BindInt64(0, offline_id);
-
-  if (statement.Step()) {
-    *info_wrapper = CreateInfoWrapper(statement);
-    return true;
-  }
-  return false;
-}
-
-DeletePageTaskResult DeletePagesByOfflineIdsSync(
-    const std::vector<int64_t>& offline_ids,
-    sql::Database* db) {
-  if (offline_ids.empty())
-    return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
-
-  // If you create a transaction but dont Commit() it is automatically
-  // rolled back by its destructor when it falls out of scope.
-  sql::Transaction transaction(db);
-  if (!transaction.Begin())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
-
-  std::vector<DeletedPageInfoWrapper> infos;
-  for (int64_t offline_id : offline_ids) {
-    DeletedPageInfoWrapper info;
-    if (GetDeletedPageInfoWrapperByOfflineIdSync(db, offline_id, &info))
-      infos.push_back(std::move(info));
-  }
-  DeletePageTaskResult result =
-      DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos));
-
-  if (!transaction.Commit())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
-  return result;
-}
-
-// Gets page infos for |client_id|, returning a vector of
-// DeletedPageInfoWrappers because ClientId can refer to multiple pages.
-std::vector<DeletedPageInfoWrapper> GetDeletedPageInfoWrappersByClientIdSync(
-    sql::Database* db,
-    ClientId client_id) {
-  std::vector<DeletedPageInfoWrapper> info_wrappers;
-  static const char kSql[] =
-      "SELECT " INFO_WRAPPER_FIELDS " FROM " OFFLINE_PAGES_TABLE_NAME
-      " WHERE client_namespace = ? AND client_id = ?";
-  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  statement.BindString(0, client_id.name_space);
-  statement.BindString(1, client_id.id);
-
-  while (statement.Step())
-    info_wrappers.emplace_back(CreateInfoWrapper(statement));
-
-  return info_wrappers;
-}
-
-DeletePageTaskResult DeletePagesByClientIdsSync(
-    const std::vector<ClientId> client_ids,
-    sql::Database* db) {
-  std::vector<DeletedPageInfoWrapper> infos;
-
-  if (client_ids.empty())
-    return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
-
-  // If you create a transaction but dont Commit() it is automatically
-  // rolled back by its destructor when it falls out of scope.
-  sql::Transaction transaction(db);
-  if (!transaction.Begin())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
-
-  for (ClientId client_id : client_ids) {
-    std::vector<DeletedPageInfoWrapper> temp_infos =
-        GetDeletedPageInfoWrappersByClientIdSync(db, client_id);
-    infos.insert(infos.end(), std::make_move_iterator(temp_infos.begin()),
-                 std::make_move_iterator(temp_infos.end()));
-  }
-
-  DeletePageTaskResult result =
-      DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos));
-
-  if (!transaction.Commit())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
-  return result;
-}
-
-// Gets page infos for |client_id|, returning a vector of
-// DeletedPageInfoWrappers because ClientId can refer to multiple pages.
-std::vector<DeletedPageInfoWrapper>
-GetDeletedPageInfoWrappersByClientIdAndOriginSync(sql::Database* db,
-                                                  ClientId client_id,
-                                                  const std::string& origin) {
-  std::vector<DeletedPageInfoWrapper> info_wrappers;
-  static const char kSql[] =
-      "SELECT " INFO_WRAPPER_FIELDS " FROM " OFFLINE_PAGES_TABLE_NAME
-      " WHERE client_namespace = ? AND client_id = ? AND request_origin = ?";
-  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  statement.BindString(0, client_id.name_space);
-  statement.BindString(1, client_id.id);
-  statement.BindString(2, origin);
-
-  while (statement.Step())
-    info_wrappers.emplace_back(CreateInfoWrapper(statement));
-
-  return info_wrappers;
-}
-
-DeletePageTaskResult DeletePagesByClientIdsAndOriginSync(
-    const std::vector<ClientId> client_ids,
-    const std::string& origin,
-    sql::Database* db) {
-  std::vector<DeletedPageInfoWrapper> infos;
-
-  if (client_ids.empty())
-    return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
-
-  // If you create a transaction but dont Commit() it is automatically
-  // rolled back by its destructor when it falls out of scope.
-  sql::Transaction transaction(db);
-  if (!transaction.Begin())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
-
-  for (ClientId client_id : client_ids) {
-    std::vector<DeletedPageInfoWrapper> temp_infos =
-        GetDeletedPageInfoWrappersByClientIdAndOriginSync(db, client_id,
-                                                          origin);
-    infos.insert(infos.end(), std::make_move_iterator(temp_infos.begin()),
-                 std::make_move_iterator(temp_infos.end()));
-  }
-
-  DeletePageTaskResult result =
-      DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos));
-
-  if (!transaction.Commit())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
-  return result;
-}
-
-// Gets the page information of pages that are within the provided temporary
-// namespaces and satisfy the provided URL predicate.
-std::vector<DeletedPageInfoWrapper>
-GetCachedDeletedPageInfoWrappersByUrlPredicateSync(
-    sql::Database* db,
-    const std::vector<std::string>& temp_namespaces,
-    const UrlPredicate& url_predicate) {
-  std::vector<DeletedPageInfoWrapper> info_wrappers;
-  static const char kSql[] =
-      "SELECT " INFO_WRAPPER_FIELDS
-      ", online_url"
-      " FROM " OFFLINE_PAGES_TABLE_NAME " WHERE client_namespace = ?";
-
-  for (const auto& temp_namespace : temp_namespaces) {
-    sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-    statement.BindString(0, temp_namespace);
-
-    while (statement.Step()) {
-      if (!url_predicate.Run(
-              GURL(statement.ColumnString(INFO_WRAPPER_FIELD_COUNT))))
-        continue;
-      DeletedPageInfoWrapper info_wrapper = CreateInfoWrapper(statement);
-      info_wrappers.push_back(std::move(info_wrapper));
-    }
-  }
-  return info_wrappers;
-}
-
-DeletePageTaskResult DeleteCachedPagesByUrlPredicateSync(
-    const std::vector<std::string>& namespaces,
-    const UrlPredicate& predicate,
+DeletePageTaskResult DeletePagesWithCriteria(
+    const ClientPolicyController* policy_controller,
+    const PageCriteria& criteria,
     sql::Database* db) {
   // If you create a transaction but dont Commit() it is automatically
   // rolled back by its destructor when it falls out of scope.
   sql::Transaction transaction(db);
   if (!transaction.Begin())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
+    return {DeletePageResult::STORE_FAILURE, {}};
 
-  std::vector<DeletedPageInfoWrapper> infos =
-      GetCachedDeletedPageInfoWrappersByUrlPredicateSync(db, namespaces,
-                                                         predicate);
+  GetPagesTask::ReadResult read_result =
+      GetPagesTask::ReadPagesWithCriteriaSync(policy_controller, criteria, db);
+  if (!read_result.success)
+    return {DeletePageResult::STORE_FAILURE, {}};
+
   DeletePageTaskResult result =
-      DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos));
+      DeletePagesSync(db, std::move(read_result.pages));
 
   if (!transaction.Commit())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
+    return {DeletePageResult::STORE_FAILURE, {}};
   return result;
 }
 
-// Gets the page information of pages whose url and name_space equal to |url|
-// and |name_space|. The pages will be deleted from old to new (by last access
-// time) until there are limit - 1 pages left.
-// TODO(romax): This might be affected by https://crbug.com/753609 for url
-// matching.
-std::vector<DeletedPageInfoWrapper>
-GetDeletedPageInfoWrappersForPageLimitDeletion(sql::Database* db,
-                                               const GURL& url,
-                                               std::string name_space,
-                                               size_t limit) {
-  std::vector<DeletedPageInfoWrapper> info_wrappers;
-  static const char kSql[] =
-      "SELECT " INFO_WRAPPER_FIELDS " FROM " OFFLINE_PAGES_TABLE_NAME
-      " WHERE client_namespace = ? AND online_url = ?"
-      " ORDER BY last_access_time ASC";
-  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  statement.BindString(0, name_space);
-  statement.BindString(1, url.spec());
-
-  while (statement.Step()) {
-    DeletedPageInfoWrapper info_wrapper = CreateInfoWrapper(statement);
-    info_wrappers.push_back(std::move(info_wrapper));
+// Deletes all but |limit| pages that match |criteria|, in the order specified
+// by |criteria|.
+DeletePageTaskResult DeletePagesForPageLimit(
+    const ClientPolicyController* policy_controller,
+    const PageCriteria& criteria,
+    size_t limit,
+    sql::Database* db) {
+  // If the namespace can have unlimited pages per url, just return success. In
+  // practice, we shouldn't hit this condition.
+  if (limit == kUnlimitedPages) {
+    DLOG(ERROR) << "DeletePagesForPageLimit called with unlimited limit";
+    return {DeletePageResult::SUCCESS, {}};
   }
 
-  // Since the page information was selected by ascending order of last access
-  // time, only the first |size - limit| pages needs to be deleted.
-  int page_to_delete = info_wrappers.size() - limit;
-  if (page_to_delete < 0)
-    page_to_delete = 0;
-  info_wrappers.resize(page_to_delete);
-  return info_wrappers;
-}
-
-DeletePageTaskResult DeletePagesForPageLimit(const GURL& url,
-                                             std::string name_space,
-                                             size_t limit,
-                                             sql::Database* db) {
-  // If the namespace can have unlimited pages per url, just return success.
-  if (limit == kUnlimitedPages)
-    return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
-
   // If you create a transaction but dont Commit() it is automatically
   // rolled back by its destructor when it falls out of scope.
   sql::Transaction transaction(db);
   if (!transaction.Begin())
-    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
+    return {DeletePageResult::STORE_FAILURE, {}};
 
-  std::vector<DeletedPageInfoWrapper> infos =
-      GetDeletedPageInfoWrappersForPageLimitDeletion(db, url, name_space,
-                                                     limit);
+  GetPagesTask::ReadResult read_result =
+      GetPagesTask::ReadPagesWithCriteriaSync(policy_controller, criteria, db);
+  if (!read_result.success)
+    return {DeletePageResult::STORE_FAILURE, {}};
+
+  if (read_result.pages.size() > limit)
+    read_result.pages.resize(read_result.pages.size() - limit);
+  else
+    read_result.pages.clear();
+
   DeletePageTaskResult result =
-      DeletePagesByDeletedPageInfoWrappersSync(db, std::move(infos));
+      DeletePagesSync(db, std::move(read_result.pages));
 
   if (!transaction.Commit())
     return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
@@ -418,46 +163,15 @@
 
 }  // namespace
 
-// DeletePageTaskResult implementations.
-DeletePageTaskResult::DeletePageTaskResult() = default;
-DeletePageTaskResult::DeletePageTaskResult(
-    DeletePageResult result,
-    const std::vector<OfflinePageModel::DeletedPageInfo>& infos)
-    : result(result), infos(infos) {}
-DeletePageTaskResult::DeletePageTaskResult(const DeletePageTaskResult& other) =
-    default;
-DeletePageTaskResult::~DeletePageTaskResult() = default;
-
 // static
-std::unique_ptr<DeletePageTask> DeletePageTask::CreateTaskMatchingOfflineIds(
+std::unique_ptr<DeletePageTask> DeletePageTask::CreateTaskWithCriteria(
     OfflinePageMetadataStore* store,
-    DeletePageTask::DeletePageTaskCallback callback,
-    const std::vector<int64_t>& offline_ids) {
-  return std::unique_ptr<DeletePageTask>(new DeletePageTask(
-      store, base::BindOnce(&DeletePagesByOfflineIdsSync, offline_ids),
-      std::move(callback)));
-}
-
-// static
-std::unique_ptr<DeletePageTask> DeletePageTask::CreateTaskMatchingClientIds(
-    OfflinePageMetadataStore* store,
-    DeletePageTask::DeletePageTaskCallback callback,
-    const std::vector<ClientId>& client_ids) {
-  return std::unique_ptr<DeletePageTask>(new DeletePageTask(
-      store, base::BindOnce(&DeletePagesByClientIdsSync, client_ids),
-      std::move(callback)));
-}
-
-// static
-std::unique_ptr<DeletePageTask>
-DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
-    OfflinePageMetadataStore* store,
-    DeletePageTask::DeletePageTaskCallback callback,
-    const std::vector<ClientId>& client_ids,
-    const std::string& origin) {
+    const ClientPolicyController& policy_controller,
+    const PageCriteria& criteria,
+    DeletePageTask::DeletePageTaskCallback callback) {
   return std::unique_ptr<DeletePageTask>(new DeletePageTask(
       store,
-      base::BindOnce(&DeletePagesByClientIdsAndOriginSync, client_ids, origin),
+      base::BindOnce(&DeletePagesWithCriteria, &policy_controller, criteria),
       std::move(callback)));
 }
 
@@ -465,30 +179,40 @@
 std::unique_ptr<DeletePageTask>
 DeletePageTask::CreateTaskMatchingUrlPredicateForCachedPages(
     OfflinePageMetadataStore* store,
+    const ClientPolicyController& policy_controller,
     DeletePageTask::DeletePageTaskCallback callback,
-    ClientPolicyController* policy_controller,
     const UrlPredicate& predicate) {
-  std::vector<std::string> temp_namespaces =
-      policy_controller->GetNamespacesRemovedOnCacheReset();
-  return std::unique_ptr<DeletePageTask>(
-      new DeletePageTask(store,
-                         base::BindOnce(&DeleteCachedPagesByUrlPredicateSync,
-                                        temp_namespaces, predicate),
-                         std::move(callback)));
+  PageCriteria criteria;
+  criteria.client_namespaces =
+      policy_controller.GetNamespacesRemovedOnCacheReset();
+  criteria.additional_criteria = base::BindRepeating(
+      [](const UrlPredicate& predicate, const OfflinePageItem& item) {
+        return predicate.Run(item.url);
+      },
+      predicate);
+  return CreateTaskWithCriteria(store, policy_controller, criteria,
+                                std::move(callback));
 }
 
 // static
 std::unique_ptr<DeletePageTask> DeletePageTask::CreateTaskDeletingForPageLimit(
     OfflinePageMetadataStore* store,
+    const ClientPolicyController& policy_controller,
     DeletePageTask::DeletePageTaskCallback callback,
-    ClientPolicyController* policy_controller,
     const OfflinePageItem& page) {
   std::string name_space = page.client_id.name_space;
-  size_t limit = policy_controller->GetPolicy(name_space).pages_allowed_per_url;
-  return std::unique_ptr<DeletePageTask>(new DeletePageTask(
-      store,
-      base::BindOnce(&DeletePagesForPageLimit, page.url, name_space, limit),
-      std::move(callback)));
+  size_t limit = policy_controller.GetPolicy(name_space).pages_allowed_per_url;
+  PageCriteria criteria;
+  criteria.url = page.url;
+  criteria.client_namespaces = std::vector<std::string>{name_space};
+  // Sorting is important here. DeletePagesForPageLimit will delete the results
+  // in order, leaving only the last |limit| pages.
+  criteria.result_order = PageCriteria::kAscendingAccessTime;
+  return base::WrapUnique(
+      new DeletePageTask(store,
+                         base::BindOnce(&DeletePagesForPageLimit,
+                                        &policy_controller, criteria, limit),
+                         std::move(callback)));
 }
 
 DeletePageTask::DeletePageTask(OfflinePageMetadataStore* store,
@@ -512,8 +236,27 @@
 }
 
 void DeletePageTask::OnDeletePageDone(DeletePageTaskResult result) {
-  std::move(callback_).Run(result.result, result.infos);
+  std::move(callback_).Run(result.result, std::move(result.deleted_pages));
   TaskComplete();
 }
 
+// static
+bool DeletePageTask::DeletePageFromDbSync(int64_t offline_id,
+                                          sql::Database* db) {
+  static const char kSql[] = "DELETE FROM offlinepages_v1 WHERE offline_id=?";
+  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+  statement.BindInt64(0, offline_id);
+  return statement.Run();
+}
+
+bool DeletePageTask::DeletePagesFromDbSync(
+    const std::vector<int64_t>& offline_ids,
+    sql::Database* db) {
+  for (const auto& offline_id : offline_ids) {
+    if (!DeletePageTask::DeletePageFromDbSync(offline_id, db))
+      return false;
+  }
+  return true;
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/model/delete_page_task.h b/components/offline_pages/core/model/delete_page_task.h
index ba9a80d..c6a034b9 100644
--- a/components/offline_pages/core/model/delete_page_task.h
+++ b/components/offline_pages/core/model/delete_page_task.h
@@ -21,7 +21,6 @@
 
 namespace offline_pages {
 
-struct ClientId;
 class OfflinePageMetadataStore;
 
 // Task that deletes pages from the metadata store. It takes the store and
@@ -33,48 +32,23 @@
 // The tasks have to be created by using the static CreateTask* methods.
 class DeletePageTask : public Task {
  public:
-  struct DeletePageTaskResult {
-    DeletePageTaskResult();
-    DeletePageTaskResult(
-        DeletePageResult result,
-        const std::vector<OfflinePageModel::DeletedPageInfo>& infos);
-    DeletePageTaskResult(const DeletePageTaskResult& other);
-    ~DeletePageTaskResult();
+  struct DeletePageTaskResult;
+  using DeletePageTaskCallback =
+      base::OnceCallback<void(DeletePageResult,
+                              const std::vector<OfflinePageItem>&)>;
 
-    DeletePageResult result;
-    std::vector<OfflinePageModel::DeletedPageInfo> infos;
-  };
-  typedef base::OnceCallback<void(
-      DeletePageResult,
-      const std::vector<OfflinePageModel::DeletedPageInfo>&)>
-      DeletePageTaskCallback;
-
-  // Creates a task to delete pages with offline ids in |offline_ids|.
-  static std::unique_ptr<DeletePageTask> CreateTaskMatchingOfflineIds(
+  static std::unique_ptr<DeletePageTask> CreateTaskWithCriteria(
       OfflinePageMetadataStore* store,
-      DeletePageTask::DeletePageTaskCallback callback,
-      const std::vector<int64_t>& offline_ids);
-
-  // Creates a task to delete pages with client ids in |client_ids|.
-  static std::unique_ptr<DeletePageTask> CreateTaskMatchingClientIds(
-      OfflinePageMetadataStore* store,
-      DeletePageTask::DeletePageTaskCallback callback,
-      const std::vector<ClientId>& client_ids);
-
-  // Creates a task to delete pages with the client ids in |client_ids|
-  // provided they also have origin |origin|.
-  static std::unique_ptr<DeletePageTask> CreateTaskMatchingClientIdsAndOrigin(
-      OfflinePageMetadataStore* store,
-      DeletePageTask::DeletePageTaskCallback callback,
-      const std::vector<ClientId>& client_ids,
-      const std::string& origin);
+      const ClientPolicyController& policy_controller,
+      const PageCriteria& criteria,
+      DeletePageTask::DeletePageTaskCallback callback);
 
   // Creates a task to delete pages which satisfy |predicate|.
   static std::unique_ptr<DeletePageTask>
   CreateTaskMatchingUrlPredicateForCachedPages(
       OfflinePageMetadataStore* store,
+      const ClientPolicyController& policy_controller,
       DeletePageTask::DeletePageTaskCallback callback,
-      ClientPolicyController* policy_controller,
       const UrlPredicate& predicate);
 
   // Creates a task to delete old pages that have the same url and namespace
@@ -83,8 +57,8 @@
   // Returns nullptr if there's no page limit per url of the page's namespace.
   static std::unique_ptr<DeletePageTask> CreateTaskDeletingForPageLimit(
       OfflinePageMetadataStore* store,
+      const ClientPolicyController& policy_controller,
       DeletePageTask::DeletePageTaskCallback callback,
-      ClientPolicyController* policy_controller,
       const OfflinePageItem& page);
 
   ~DeletePageTask() override;
@@ -92,9 +66,20 @@
   // Task implementation.
   void Run() override;
 
+  // Deletes a single page from the database. This function reads
+  // from the database and should be called from within an
+  // |SqlStoreBase::Execute()| call.
+  static bool DeletePageFromDbSync(int64_t offline_id, sql::Database* db);
+  // Deletes all pages with matching offline_ids from the database. Returns
+  // false and aborts if a page could not be deleted. This function reads
+  // from the database and should be called from within an
+  // |SqlStoreBase::Execute()| call.
+  static bool DeletePagesFromDbSync(const std::vector<int64_t>& offline_ids,
+                                    sql::Database* db);
+
  private:
-  typedef base::OnceCallback<DeletePageTaskResult(sql::Database*)>
-      DeleteFunction;
+  using DeleteFunction =
+      base::OnceCallback<DeletePageTaskResult(sql::Database*)>;
 
   // Making the constructor private, in order to use static methods to create
   // tasks.
diff --git a/components/offline_pages/core/model/delete_page_task_unittest.cc b/components/offline_pages/core/model/delete_page_task_unittest.cc
index 09a787a3..98a94d8 100644
--- a/components/offline_pages/core/model/delete_page_task_unittest.cc
+++ b/components/offline_pages/core/model/delete_page_task_unittest.cc
@@ -5,6 +5,8 @@
 #include "components/offline_pages/core/model/delete_page_task.h"
 
 #include <memory>
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -25,14 +27,11 @@
 
 namespace offline_pages {
 
-using DeletedPageInfo = OfflinePageModel::DeletedPageInfo;
-
 namespace {
 
 const char kTestNamespace[] = "default";
 const GURL kTestUrl1("http://example.com");
 const GURL kTestUrl2("http://other.page.com");
-const int64_t kTestOfflineIdNoMatch = 20170905LL;
 const ClientId kTestClientIdNoMatch(kTestNamespace, "20170905");
 
 GURL OriginalUrl() {
@@ -51,7 +50,7 @@
   void ResetResults();
 
   void OnDeletePageDone(DeletePageResult result,
-                        const std::vector<DeletedPageInfo>& deleted_page_infos);
+                        const std::vector<OfflinePageItem>& deleted_pages);
   bool CheckPageDeleted(const OfflinePageItem& page);
   DeletePageTask::DeletePageTaskCallback delete_page_callback();
 
@@ -59,15 +58,15 @@
   const base::Optional<DeletePageResult>& last_delete_page_result() {
     return last_delete_page_result_;
   }
-  const std::vector<DeletedPageInfo>& last_deleted_page_infos() {
-    return last_deleted_page_infos_;
+  const std::vector<OfflinePageItem>& last_deleted_page_items() {
+    return last_deleted_page_items_;
   }
 
  private:
   std::unique_ptr<base::HistogramTester> histogram_tester_;
 
   base::Optional<DeletePageResult> last_delete_page_result_;
-  std::vector<DeletedPageInfo> last_deleted_page_infos_;
+  std::vector<OfflinePageItem> last_deleted_page_items_;
 };
 
 DeletePageTaskTest::DeletePageTaskTest() {}
@@ -81,9 +80,9 @@
 
 void DeletePageTaskTest::OnDeletePageDone(
     DeletePageResult result,
-    const std::vector<DeletedPageInfo>& deleted_page_infos) {
+    const std::vector<OfflinePageItem>& deleted_page_items) {
   last_delete_page_result_ = result;
-  last_deleted_page_infos_ = deleted_page_infos;
+  last_deleted_page_items_ = deleted_page_items;
 }
 
 DeletePageTask::DeletePageTaskCallback
@@ -97,8 +96,8 @@
   return !base::PathExists(page.file_path) && !stored_page;
 }
 
-// Delete a page and verify all the information in DeletedPageInfo is accurate.
-TEST_F(DeletePageTaskTest, DeletedPageInfoIsPopulated) {
+// Delete a page and verify all the information in deleted_pages is accurate.
+TEST_F(DeletePageTaskTest, OfflinePageItemIsPopulated) {
   generator()->SetNamespace(kTestNamespace);
   OfflinePageItem page1 = generator()->CreateItemWithTempFile();
   page1.url = kTestUrl1;
@@ -108,256 +107,24 @@
   store_test_util()->InsertItem(page1);
 
   // Run DeletePageTask for to delete the page.
-  std::vector<int64_t> offline_ids({page1.offline_id});
-  auto task = DeletePageTask::CreateTaskMatchingOfflineIds(
-      store(), delete_page_callback(), offline_ids);
+  PageCriteria criteria;
+  criteria.offline_ids = std::vector<int64_t>{page1.offline_id};
+  auto task = DeletePageTask::CreateTaskWithCriteria(
+      store(), *policy_controller(), criteria, delete_page_callback());
   RunTask(std::move(task));
 
   EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(1UL, last_deleted_page_infos().size());
+  EXPECT_EQ(1UL, last_deleted_page_items().size());
 
-  // Verify original_url is returned via DeletedPageInfo.
-  const DeletedPageInfo& info = last_deleted_page_infos()[0];
-  EXPECT_EQ(page1.url, info.url);
-  EXPECT_EQ(page1.client_id, info.client_id);
-  EXPECT_EQ(page1.request_origin, info.request_origin);
-  EXPECT_EQ(page1.system_download_id, info.system_download_id);
-  EXPECT_EQ(page1.offline_id, info.offline_id);
-  EXPECT_EQ(OriginalUrl(), info.original_url_if_different);
-  EXPECT_EQ(OriginalUrl(), info.GetOriginalUrl());
-}
-
-TEST_F(DeletePageTaskTest, DeletePageByOfflineId) {
-  // Add 3 pages and try to delete 2 of them using offline id.
-  generator()->SetNamespace(kTestNamespace);
-  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
-  // Set an access count of 200 to avoid falling in the same bucket.
-  generator()->SetAccessCount(200);
-  OfflinePageItem page3 = generator()->CreateItemWithTempFile();
-
-  store_test_util()->InsertItem(page1);
-  store_test_util()->InsertItem(page2);
-  store_test_util()->InsertItem(page3);
-
-  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
-  EXPECT_TRUE(base::PathExists(page1.file_path));
-  EXPECT_TRUE(base::PathExists(page2.file_path));
-  EXPECT_TRUE(base::PathExists(page3.file_path));
-
-  // The pages with the offline ids will be removed from the store.
-  std::vector<int64_t> offline_ids({page1.offline_id, page3.offline_id});
-  auto task = DeletePageTask::CreateTaskMatchingOfflineIds(
-      store(), delete_page_callback(), offline_ids);
-  RunTask(std::move(task));
-
-  EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(2UL, last_deleted_page_infos().size());
-  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
-  EXPECT_TRUE(CheckPageDeleted(page1));
-  EXPECT_FALSE(CheckPageDeleted(page2));
-  EXPECT_TRUE(CheckPageDeleted(page3));
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.PageLifetime"),
-      2);
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      2);
-  histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      0, 1);
-  histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      200, 1);
-}
-
-TEST_F(DeletePageTaskTest, DeletePageByOfflineIdNotFound) {
-  generator()->SetNamespace(kTestNamespace);
-  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page3 = generator()->CreateItemWithTempFile();
-  store_test_util()->InsertItem(page1);
-  store_test_util()->InsertItem(page2);
-  store_test_util()->InsertItem(page3);
-
-  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
-
-  // The pages with the offline ids will be removed from the store. But since
-  // the id isn't in the store, there will be no pages deleted and the result
-  // will be success since there's no NOT_FOUND anymore.
-  // This *might* break if any of the generated offline ids above equals to the
-  // constant value defined above.
-  std::vector<int64_t> offline_ids({kTestOfflineIdNoMatch});
-  auto task = DeletePageTask::CreateTaskMatchingOfflineIds(
-      store(), delete_page_callback(), offline_ids);
-  RunTask(std::move(task));
-
-  EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(0UL, last_deleted_page_infos().size());
-  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
-  EXPECT_FALSE(CheckPageDeleted(page1));
-  EXPECT_FALSE(CheckPageDeleted(page2));
-  EXPECT_FALSE(CheckPageDeleted(page3));
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.PageLifetime"),
-      0);
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      0);
-}
-
-TEST_F(DeletePageTaskTest, DeletePageByClientId) {
-  // Add 3 pages and try to delete 2 of them using client id.
-  generator()->SetNamespace(kTestNamespace);
-  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
-  generator()->SetAccessCount(200);
-  OfflinePageItem page3 = generator()->CreateItemWithTempFile();
-  store_test_util()->InsertItem(page1);
-  store_test_util()->InsertItem(page2);
-  store_test_util()->InsertItem(page3);
-
-  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
-  EXPECT_TRUE(base::PathExists(page1.file_path));
-  EXPECT_TRUE(base::PathExists(page2.file_path));
-  EXPECT_TRUE(base::PathExists(page3.file_path));
-
-  std::vector<ClientId> client_ids({page1.client_id, page3.client_id});
-  auto task = DeletePageTask::CreateTaskMatchingClientIds(
-      store(), delete_page_callback(), client_ids);
-  RunTask(std::move(task));
-
-  EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(2UL, last_deleted_page_infos().size());
-  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
-  EXPECT_TRUE(CheckPageDeleted(page1));
-  EXPECT_FALSE(CheckPageDeleted(page2));
-  EXPECT_TRUE(CheckPageDeleted(page3));
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.PageLifetime"),
-      2);
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      2);
-  histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      0, 1);
-  histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      200, 1);
-}
-
-TEST_F(DeletePageTaskTest, DeletePageByClientIdNotFound) {
-  generator()->SetNamespace(kTestNamespace);
-  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page3 = generator()->CreateItemWithTempFile();
-  store_test_util()->InsertItem(page1);
-  store_test_util()->InsertItem(page2);
-  store_test_util()->InsertItem(page3);
-
-  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
-
-  // The pages with the client ids will be removed from the store. But since
-  // the id isn't in the store, there will be no pages deleted and the result
-  // will be success since there's no NOT_FOUND anymore.
-  std::vector<ClientId> client_ids({kTestClientIdNoMatch});
-  auto task = DeletePageTask::CreateTaskMatchingClientIds(
-      store(), delete_page_callback(), client_ids);
-  RunTask(std::move(task));
-
-  EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(0UL, last_deleted_page_infos().size());
-  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.PageLifetime"),
-      0);
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      0);
-}
-
-TEST_F(DeletePageTaskTest, DeletePageByClientIdAndOrigin) {
-  // Add 3 pages and try to delete 2 of them using client id and origin
-  // Page1: {test namespace, random id, abc.xyz}
-  // Page2: {test namespace, foo, abc.xyz}
-  // Page3: {test namespace, foo, <none>}
-  generator()->SetNamespace(kTestNamespace);
-  generator()->SetRequestOrigin("abc.xyz");
-  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
-  generator()->SetId("foo");
-  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
-  generator()->SetRequestOrigin("");
-  OfflinePageItem page3 = generator()->CreateItemWithTempFile();
-  store_test_util()->InsertItem(page1);
-  store_test_util()->InsertItem(page2);
-  store_test_util()->InsertItem(page3);
-
-  std::vector<ClientId> client_ids({page1.client_id, page2.client_id});
-  auto task = DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
-      store(), delete_page_callback(), client_ids, "abc.xyz");
-  RunTask(std::move(task));
-
-  EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(2UL, last_deleted_page_infos().size());
-  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
-  EXPECT_TRUE(CheckPageDeleted(page1));
-  EXPECT_TRUE(CheckPageDeleted(page2));
-  EXPECT_FALSE(CheckPageDeleted(page3));
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.PageLifetime"),
-      2);
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      2);
-}
-
-TEST_F(DeletePageTaskTest, DeletePageByClientIdAndOriginNotFound) {
-  generator()->SetNamespace(kTestNamespace);
-  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page3 = generator()->CreateItemWithTempFile();
-  store_test_util()->InsertItem(page1);
-  store_test_util()->InsertItem(page2);
-  store_test_util()->InsertItem(page3);
-
-  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
-
-  // The pages with the client ids will be removed from the store given that
-  // their origin matches. But since the origin isn't in the store, there will
-  // be no pages deleted and the result will be success since there's no
-  // NOT_FOUND anymore.
-  std::vector<ClientId> client_ids(
-      {page1.client_id, page2.client_id, page3.client_id});
-  auto task = DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
-      store(), delete_page_callback(), client_ids, "abc.xyz");
-  RunTask(std::move(task));
-
-  EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(0UL, last_deleted_page_infos().size());
-  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.PageLifetime"),
-      0);
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id.name_space,
-                                      "OfflinePages.AccessCount"),
-      0);
+  // Verify original_url is returned via OfflinePageItem.
+  const OfflinePageItem& item = last_deleted_page_items()[0];
+  EXPECT_EQ(page1.url, item.url);
+  EXPECT_EQ(page1.client_id, item.client_id);
+  EXPECT_EQ(page1.request_origin, item.request_origin);
+  EXPECT_EQ(page1.system_download_id, item.system_download_id);
+  EXPECT_EQ(page1.offline_id, item.offline_id);
+  EXPECT_EQ(OriginalUrl(), item.original_url_if_different);
+  EXPECT_EQ(OriginalUrl(), item.GetOriginalUrl());
 }
 
 TEST_F(DeletePageTaskTest, DeletePageByUrlPredicate) {
@@ -385,11 +152,11 @@
   });
 
   auto task = DeletePageTask::CreateTaskMatchingUrlPredicateForCachedPages(
-      store(), delete_page_callback(), policy_controller(), predicate);
+      store(), *policy_controller(), delete_page_callback(), predicate);
   RunTask(std::move(task));
 
   EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(2UL, last_deleted_page_infos().size());
+  EXPECT_EQ(2UL, last_deleted_page_items().size());
   EXPECT_EQ(predicate.Run(page1.url), CheckPageDeleted(page1));
   EXPECT_EQ(predicate.Run(page2.url), CheckPageDeleted(page2));
   EXPECT_EQ(predicate.Run(page3.url), CheckPageDeleted(page3));
@@ -434,11 +201,11 @@
       base::BindRepeating([](const GURL& url) -> bool { return false; });
 
   auto task = DeletePageTask::CreateTaskMatchingUrlPredicateForCachedPages(
-      store(), delete_page_callback(), policy_controller(), predicate);
+      store(), *policy_controller(), delete_page_callback(), predicate);
   RunTask(std::move(task));
 
   EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(0UL, last_deleted_page_infos().size());
+  EXPECT_EQ(0UL, last_deleted_page_items().size());
   EXPECT_FALSE(CheckPageDeleted(page1));
   EXPECT_FALSE(CheckPageDeleted(page2));
   EXPECT_FALSE(CheckPageDeleted(page3));
@@ -476,11 +243,11 @@
   EXPECT_TRUE(base::PathExists(page3.file_path));
 
   auto task = DeletePageTask::CreateTaskDeletingForPageLimit(
-      store(), delete_page_callback(), policy_controller(), page);
+      store(), *policy_controller(), delete_page_callback(), page);
   RunTask(std::move(task));
 
   EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(1UL, last_deleted_page_infos().size());
+  EXPECT_EQ(1UL, last_deleted_page_items().size());
   EXPECT_TRUE(CheckPageDeleted(page1));
   EXPECT_FALSE(CheckPageDeleted(page2));
   EXPECT_FALSE(CheckPageDeleted(page3));
@@ -514,13 +281,13 @@
   EXPECT_TRUE(base::PathExists(page3.file_path));
 
   auto task = DeletePageTask::CreateTaskDeletingForPageLimit(
-      store(), delete_page_callback(), policy_controller(), page);
+      store(), *policy_controller(), delete_page_callback(), page);
   RunTask(std::move(task));
 
   // Since there's no limit for page per url of Download Namespace, the result
   // should be success with no page deleted.
   EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
-  EXPECT_EQ(0UL, last_deleted_page_infos().size());
+  EXPECT_EQ(0UL, last_deleted_page_items().size());
   histogram_tester()->ExpectTotalCount(
       model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
diff --git a/components/offline_pages/core/model/get_pages_task.cc b/components/offline_pages/core/model/get_pages_task.cc
index fa970bb..027960ce 100644
--- a/components/offline_pages/core/model/get_pages_task.cc
+++ b/components/offline_pages/core/model/get_pages_task.cc
@@ -79,6 +79,40 @@
   return string_to_match;
 }
 
+}  // namespace
+
+GetPagesTask::ReadResult::ReadResult() = default;
+GetPagesTask::ReadResult::ReadResult(const ReadResult& other) = default;
+GetPagesTask::ReadResult::~ReadResult() = default;
+
+GetPagesTask::GetPagesTask(OfflinePageMetadataStore* store,
+                           const ClientPolicyController* policy_controller,
+                           const PageCriteria& criteria,
+                           MultipleOfflinePageItemCallback callback)
+    : store_(store),
+      policy_controller_(policy_controller),
+      criteria_(criteria),
+      callback_(std::move(callback)),
+      weak_ptr_factory_(this) {
+  DCHECK(store_);
+  DCHECK(!callback_.is_null());
+}
+
+GetPagesTask::~GetPagesTask() = default;
+
+void GetPagesTask::Run() {
+  store_->Execute(base::BindOnce(&GetPagesTask::ReadPagesWithCriteriaSync,
+                                 policy_controller_, std::move(criteria_)),
+                  base::BindOnce(&GetPagesTask::CompleteWithResult,
+                                 weak_ptr_factory_.GetWeakPtr()),
+                  ReadResult());
+}
+
+void GetPagesTask::CompleteWithResult(ReadResult result) {
+  std::move(callback_).Run(result.pages);
+  TaskComplete();
+}
+
 // Some comments on query performance as of March 2019:
 // - SQLite stores data in row-oriented fashion, so there's little cost to
 //   querying additional columns.
@@ -95,12 +129,21 @@
 //   query quickly. Otherwise, we need to read the whole table anyway. Unless
 //   the db is loaded to memory, and disk access will likely dwarf any
 //   other query optimizations.
-ReadResult ReadPagesByCriteriaSync(
-    const PageCriteria& criteria,
+ReadResult GetPagesTask::ReadPagesWithCriteriaSync(
     const ClientPolicyController* policy_controller,
+    const PageCriteria& criteria,
     sql::Database* db) {
   ReadResult result;
 
+  // Quick return for known empty results.
+  if ((criteria.offline_ids && criteria.offline_ids.value().empty()) ||
+      (criteria.client_ids && criteria.client_ids.value().empty()) ||
+      (criteria.client_namespaces &&
+       criteria.client_namespaces.value().empty())) {
+    result.success = true;
+    return result;
+  }
+
   // Note: the WHERE clause here is a relaxed form of |criteria|, so returned
   // items must be re-checked with |MeetsCriteria|.
   static const char kSql[] =
@@ -114,16 +157,19 @@
       " AND (? OR request_origin=?)"
       " AND (? OR instr(?,client_id)>0)"
       " AND (? OR online_url LIKE ? OR original_url LIKE ?)"
-      " ORDER BY creation_time DESC";
+      // Order by either creation_time or last_access_time, depending on
+      // bound parameters.
+      " ORDER BY creation_time*?+last_access_time*?";
 
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
 
   int param = 0;
 
-  if (criteria.offline_id) {
-    int64_t id = criteria.offline_id.value();
-    statement.BindInt64(param++, id);
-    statement.BindInt64(param++, id);
+  if (criteria.offline_ids) {
+    const std::vector<int64_t> ids = criteria.offline_ids.value();
+    auto min_max = std::minmax_element(ids.begin(), ids.end());
+    statement.BindInt64(param++, *min_max.first);
+    statement.BindInt64(param++, *min_max.second);
   } else {
     statement.BindInt64(param++, INT64_MIN);
     statement.BindInt64(param++, INT64_MAX);
@@ -153,11 +199,11 @@
   statement.BindBool(param++, criteria.request_origin.empty());
   statement.BindString(param++, criteria.request_origin);
 
-  if (!criteria.client_ids.empty()) {
+  if (criteria.client_ids) {
     // Collect all client ids into a single string for matching in the query
     // with substring match (instr()).
     std::string concatenated_ids;
-    for (const ClientId& id : criteria.client_ids) {
+    for (const ClientId& id : criteria.client_ids.value()) {
       concatenated_ids += id.id;
     }
     statement.BindBool(param++, false);
@@ -175,6 +221,14 @@
   statement.BindString(param++, url_pattern);
   statement.BindString(param++, url_pattern);
 
+  // ORDER BY criteria.
+  statement.BindInt64(
+      param++,
+      criteria.result_order == PageCriteria::kDescendingCreationTime ? -1 : 0);
+  statement.BindInt64(
+      param++,
+      criteria.result_order == PageCriteria::kAscendingAccessTime ? 1 : 0);
+
   while (statement.Step()) {
     // Initially, read just the client ID to avoid creating the offline item
     // if it's filtered out.
@@ -194,38 +248,4 @@
   return result;
 }
 
-}  // namespace
-
-GetPagesTask::ReadResult::ReadResult() = default;
-GetPagesTask::ReadResult::ReadResult(const ReadResult& other) = default;
-GetPagesTask::ReadResult::~ReadResult() = default;
-
-GetPagesTask::GetPagesTask(OfflinePageMetadataStore* store,
-                           const ClientPolicyController* policy_controller,
-                           const PageCriteria& criteria,
-                           MultipleOfflinePageItemCallback callback)
-    : store_(store),
-      policy_controller_(policy_controller),
-      criteria_(criteria),
-      callback_(std::move(callback)),
-      weak_ptr_factory_(this) {
-  DCHECK(store_);
-  DCHECK(!callback_.is_null());
-}
-
-GetPagesTask::~GetPagesTask() {}
-
-void GetPagesTask::Run() {
-  store_->Execute(base::BindOnce(&ReadPagesByCriteriaSync, std::move(criteria_),
-                                 policy_controller_),
-                  base::BindOnce(&GetPagesTask::CompleteWithResult,
-                                 weak_ptr_factory_.GetWeakPtr()),
-                  ReadResult());
-}
-
-void GetPagesTask::CompleteWithResult(ReadResult result) {
-  std::move(callback_).Run(result.pages);
-  TaskComplete();
-}
-
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/model/get_pages_task.h b/components/offline_pages/core/model/get_pages_task.h
index 22c3cb6..280f5bd 100644
--- a/components/offline_pages/core/model/get_pages_task.h
+++ b/components/offline_pages/core/model/get_pages_task.h
@@ -42,6 +42,14 @@
   // Task implementation:
   void Run() override;
 
+  // Reads and returns all pages matching |criteria|. This function reads
+  // from the database and should be called from within an
+  // |SqlStoreBase::Execute()| call.
+  static ReadResult ReadPagesWithCriteriaSync(
+      const ClientPolicyController* policy_controller,
+      const PageCriteria& criteria,
+      sql::Database* db);
+
  private:
   void CompleteWithResult(ReadResult result);
 
diff --git a/components/offline_pages/core/model/get_pages_task_unittest.cc b/components/offline_pages/core/model/get_pages_task_unittest.cc
index 6fe12a8..0c9e9a6 100644
--- a/components/offline_pages/core/model/get_pages_task_unittest.cc
+++ b/components/offline_pages/core/model/get_pages_task_unittest.cc
@@ -29,6 +29,9 @@
 class GetPagesTaskTest : public ModelTaskTestBase {
  public:
   const std::set<OfflinePageItem>& task_result() const { return task_result_; }
+  const std::vector<OfflinePageItem>& ordered_task_result() const {
+    return ordered_task_result_;
+  }
 
   void InsertItems(std::vector<OfflinePageItem> items) {
     for (auto& item : items) {
@@ -45,6 +48,7 @@
 
  private:
   void OnGetPagesDone(const std::vector<OfflinePageItem>& result) {
+    ordered_task_result_ = result;
     task_result_.clear();
     task_result_.insert(result.begin(), result.end());
     // Verify there were no identical items, to ensure the set contains the
@@ -55,6 +59,7 @@
  protected:
   ClientPolicyController policy_controller_;
   std::set<OfflinePageItem> task_result_;
+  std::vector<OfflinePageItem> ordered_task_result_;
 };
 
 TEST_F(GetPagesTaskTest, GetAllPages) {
@@ -69,7 +74,7 @@
   EXPECT_EQ(std::set<OfflinePageItem>({item_1, item_2, item_3}), task_result());
 }
 
-TEST_F(GetPagesTaskTest, MultipleClientIds) {
+TEST_F(GetPagesTaskTest, ClientId) {
   generator()->SetNamespace(kTestNamespace);
   OfflinePageItem item_1 = generator()->CreateItem();
   OfflinePageItem item_2 = generator()->CreateItem();
@@ -77,10 +82,15 @@
   InsertItems({item_1, item_2, item_3});
 
   PageCriteria criteria;
-  criteria.client_ids = {item_1.client_id, item_2.client_id};
-  RunTask(CreateTask(criteria));
 
+  criteria.client_ids =
+      std::vector<ClientId>{item_1.client_id, item_2.client_id};
+  RunTask(CreateTask(criteria));
   EXPECT_EQ(std::set<OfflinePageItem>({item_1, item_2}), task_result());
+
+  criteria.client_ids = std::vector<ClientId>();
+  RunTask(CreateTask(criteria));
+  EXPECT_EQ(std::set<OfflinePageItem>(), task_result());
 }
 
 TEST_F(GetPagesTaskTest, Namespace) {
@@ -93,10 +103,14 @@
   InsertItems({item_1, item_2, item_3});
 
   PageCriteria criteria;
-  criteria.client_namespaces.push_back(kTestNamespace);
-  RunTask(CreateTask(criteria));
 
+  criteria.client_namespaces = std::vector<std::string>{kTestNamespace};
+  RunTask(CreateTask(criteria));
   EXPECT_EQ(std::set<OfflinePageItem>({item_1, item_2}), task_result());
+
+  criteria.client_namespaces = std::vector<std::string>{};
+  RunTask(CreateTask(criteria));
+  EXPECT_EQ(std::set<OfflinePageItem>(), task_result());
 }
 
 TEST_F(GetPagesTaskTest, RequestOrigin) {
@@ -163,10 +177,14 @@
   InsertItems({item_1, item_2, item_3});
 
   PageCriteria criteria;
-  criteria.offline_id = item_1.offline_id;
-  RunTask(CreateTask(criteria));
 
+  criteria.offline_ids = std::vector<int64_t>{item_1.offline_id};
+  RunTask(CreateTask(criteria));
   EXPECT_EQ(std::set<OfflinePageItem>({item_1}), task_result());
+
+  criteria.offline_ids = std::vector<int64_t>{};
+  RunTask(CreateTask(criteria));
+  EXPECT_EQ(std::set<OfflinePageItem>({}), task_result());
 }
 
 TEST_F(GetPagesTaskTest, Guid) {
@@ -272,7 +290,8 @@
   {
     PageCriteria criteria;
     criteria.supported_by_downloads = true;
-    criteria.client_namespaces = {kCCTNamespace, kNTPSuggestionsNamespace};
+    criteria.client_namespaces =
+        std::vector<std::string>{kCCTNamespace, kNTPSuggestionsNamespace};
     RunTask(CreateTask(criteria));
 
     EXPECT_EQ(std::set<OfflinePageItem>({ntp_suggestion_item}), task_result());
@@ -295,4 +314,41 @@
   EXPECT_EQ(std::set<OfflinePageItem>({cct_item}), task_result());
 }
 
+TEST_F(GetPagesTaskTest, OrderDescendingCreationTime) {
+  generator()->SetNamespace(kCCTNamespace);
+  OfflinePageItem item1 = generator()->CreateItem();
+  OfflinePageItem item2 = generator()->CreateItem();
+  item2.creation_time = item1.creation_time + base::TimeDelta::FromSeconds(2);
+  OfflinePageItem item3 = generator()->CreateItem();
+  item3.creation_time = item1.creation_time + base::TimeDelta::FromSeconds(1);
+
+  InsertItems({item1, item2, item3});
+
+  PageCriteria criteria;
+  // kDescendingCreationTime is default.
+  RunTask(CreateTask(criteria));
+
+  EXPECT_EQ(std::vector<OfflinePageItem>({item2, item3, item1}),
+            ordered_task_result());
+}
+
+TEST_F(GetPagesTaskTest, OrderAscendingAccessTime) {
+  generator()->SetNamespace(kCCTNamespace);
+  OfflinePageItem item1 = generator()->CreateItem();
+  item1.last_access_time = base::Time();
+  OfflinePageItem item2 = generator()->CreateItem();
+  item2.last_access_time = base::Time() + base::TimeDelta::FromSeconds(2);
+  OfflinePageItem item3 = generator()->CreateItem();
+  item3.last_access_time = base::Time() + base::TimeDelta::FromSeconds(1);
+
+  InsertItems({item1, item2, item3});
+
+  PageCriteria criteria;
+  criteria.result_order = PageCriteria::kAscendingAccessTime;
+  RunTask(CreateTask(criteria));
+
+  EXPECT_EQ(std::vector<OfflinePageItem>({item1, item3, item2}),
+            ordered_task_result());
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index 78180af..51dd135 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -266,48 +266,23 @@
   task_queue_.AddTask(std::move(task));
 }
 
-void OfflinePageModelTaskified::DeletePagesByOfflineId(
-    const std::vector<int64_t>& offline_ids,
+void OfflinePageModelTaskified::DeletePagesWithCriteria(
+    const PageCriteria& criteria,
     DeletePageCallback callback) {
-  auto task = DeletePageTask::CreateTaskMatchingOfflineIds(
-      store_.get(),
+  task_queue_.AddTask(DeletePageTask::CreateTaskWithCriteria(
+      store_.get(), *policy_controller_.get(), criteria,
       base::BindOnce(&OfflinePageModelTaskified::OnDeleteDone,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
-      offline_ids);
-  task_queue_.AddTask(std::move(task));
-}
-
-void OfflinePageModelTaskified::DeletePagesByClientIds(
-    const std::vector<ClientId>& client_ids,
-    DeletePageCallback callback) {
-  auto task = DeletePageTask::CreateTaskMatchingClientIds(
-      store_.get(),
-      base::BindOnce(&OfflinePageModelTaskified::OnDeleteDone,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
-      client_ids);
-  task_queue_.AddTask(std::move(task));
-}
-
-void OfflinePageModelTaskified::DeletePagesByClientIdsAndOrigin(
-    const std::vector<ClientId>& client_ids,
-    const std::string& origin,
-    DeletePageCallback callback) {
-  auto task = DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
-      store_.get(),
-      base::BindOnce(&OfflinePageModelTaskified::OnDeleteDone,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
-      client_ids, origin);
-  task_queue_.AddTask(std::move(task));
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
 }
 
 void OfflinePageModelTaskified::DeleteCachedPagesByURLPredicate(
     const UrlPredicate& predicate,
     DeletePageCallback callback) {
   auto task = DeletePageTask::CreateTaskMatchingUrlPredicateForCachedPages(
-      store_.get(),
+      store_.get(), *policy_controller_.get(),
       base::BindOnce(&OfflinePageModelTaskified::OnDeleteDone,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
-      policy_controller_.get(), predicate);
+      predicate);
   task_queue_.AddTask(std::move(task));
 }
 
@@ -322,7 +297,7 @@
     int64_t offline_id,
     SingleOfflinePageItemCallback callback) {
   PageCriteria criteria;
-  criteria.offline_id = offline_id;
+  criteria.offline_ids = std::vector<int64_t>{offline_id};
   // Adapt multiple result to single result callback.
   auto wrapped_callback = base::BindOnce(
       [](SingleOfflinePageItemCallback callback,
@@ -347,7 +322,7 @@
   // client ids, and then extract the offline IDs from the items. This is fine
   // since we're not expecting many pages with the same client ID.
   PageCriteria criteria;
-  criteria.client_ids = {client_id};
+  criteria.client_ids = std::vector<ClientId>{client_id};
   GetPagesWithCriteria(criteria, base::BindOnce(&WrapInMultipleItemsCallback,
                                                 std::move(callback)));
 }
@@ -608,20 +583,20 @@
 void OfflinePageModelTaskified::OnDeleteDone(
     DeletePageCallback callback,
     DeletePageResult result,
-    const std::vector<OfflinePageModel::DeletedPageInfo>& infos) {
+    const std::vector<OfflinePageItem>& deleted_items) {
   UMA_HISTOGRAM_ENUMERATION("OfflinePages.DeletePageResult", result);
   std::vector<int64_t> system_download_ids;
 
   // Notify observers and run callback.
-  for (const auto& info : infos) {
+  for (const auto& item : deleted_items) {
     UMA_HISTOGRAM_ENUMERATION(
         "OfflinePages.DeletePageCount",
-        model_utils::ToNamespaceEnum(info.client_id.name_space));
-    offline_event_logger_.RecordPageDeleted(info.offline_id);
+        model_utils::ToNamespaceEnum(item.client_id.name_space));
+    offline_event_logger_.RecordPageDeleted(item.offline_id);
     for (Observer& observer : observers_)
-      observer.OfflinePageDeleted(info);
-    if (info.system_download_id != 0)
-      system_download_ids.push_back(info.system_download_id);
+      observer.OfflinePageDeleted(item);
+    if (item.system_download_id != 0)
+      system_download_ids.push_back(item.system_download_id);
   }
 
   // Remove the page from the system download manager. We don't need to wait for
@@ -728,11 +703,11 @@
 void OfflinePageModelTaskified::RemovePagesMatchingUrlAndNamespace(
     const OfflinePageItem& page) {
   auto task = DeletePageTask::CreateTaskDeletingForPageLimit(
-      store_.get(),
+      store_.get(), *policy_controller_.get(),
       base::BindOnce(&OfflinePageModelTaskified::OnDeleteDone,
                      weak_ptr_factory_.GetWeakPtr(),
                      base::DoNothing::Once<DeletePageResult>()),
-      policy_controller_.get(), page);
+      page);
   task_queue_.AddTask(std::move(task));
 }
 
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.h b/components/offline_pages/core/model/offline_page_model_taskified.h
index 5a1b652e7..b7b7395 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.h
+++ b/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -81,14 +81,8 @@
                 SavePageCallback callback) override;
   void AddPage(const OfflinePageItem& page, AddPageCallback callback) override;
   void MarkPageAccessed(int64_t offline_id) override;
-
-  void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
-                              DeletePageCallback callback) override;
-  void DeletePagesByClientIds(const std::vector<ClientId>& client_ids,
-                              DeletePageCallback callback) override;
-  void DeletePagesByClientIdsAndOrigin(const std::vector<ClientId>& client_ids,
-                                       const std::string& origin,
-                                       DeletePageCallback callback) override;
+  void DeletePagesWithCriteria(const PageCriteria& criteria,
+                               DeletePageCallback callback) override;
   void DeleteCachedPagesByURLPredicate(const UrlPredicate& predicate,
                                        DeletePageCallback callback) override;
 
@@ -159,10 +153,9 @@
                      AddPageResult result);
 
   // Callbacks for deleting pages.
-  void OnDeleteDone(
-      DeletePageCallback callback,
-      DeletePageResult result,
-      const std::vector<OfflinePageModel::DeletedPageInfo>& infos);
+  void OnDeleteDone(DeletePageCallback callback,
+                    DeletePageResult result,
+                    const std::vector<OfflinePageItem>& deleted_items);
 
   void OnStoreThumbnailDone(int64_t offline_id,
                             bool success,
diff --git a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
index 6d8b969..9093ff6 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -97,8 +97,7 @@
   void OfflinePageModelLoaded(OfflinePageModel* model) override;
   void OfflinePageAdded(OfflinePageModel* model,
                         const OfflinePageItem& added_page) override;
-  void OfflinePageDeleted(
-      const OfflinePageModel::DeletedPageInfo& page_info) override;
+  void OfflinePageDeleted(const OfflinePageItem& item) override;
   MOCK_METHOD3(ThumbnailAdded,
                void(OfflinePageModel* model,
                     int64_t offline_id,
@@ -172,9 +171,7 @@
   bool observer_add_page_called() { return observer_add_page_called_; }
   const OfflinePageItem& last_added_page() { return last_added_page_; }
   bool observer_delete_page_called() { return observer_delete_page_called_; }
-  const OfflinePageModel::DeletedPageInfo& last_deleted_page_info() {
-    return last_deleted_page_info_;
-  }
+  const OfflinePageItem& last_deleted_page() { return last_deleted_page_; }
   base::Time last_maintenance_tasks_schedule_time() {
     return model_->last_maintenance_tasks_schedule_time_;
   }
@@ -197,7 +194,7 @@
   bool observer_add_page_called_;
   OfflinePageItem last_added_page_;
   bool observer_delete_page_called_;
-  OfflinePageModel::DeletedPageInfo last_deleted_page_info_;
+  OfflinePageItem last_deleted_page_;
 };
 
 OfflinePageModelTaskifiedTest::OfflinePageModelTaskifiedTest()
@@ -284,9 +281,9 @@
 }
 
 void OfflinePageModelTaskifiedTest::OfflinePageDeleted(
-    const OfflinePageModel::DeletedPageInfo& page_info) {
+    const OfflinePageItem& item) {
   observer_delete_page_called_ = true;
-  last_deleted_page_info_ = page_info;
+  last_deleted_page_ = item;
 }
 
 void OfflinePageModelTaskifiedTest::SetLastPathCreatedByArchiver(
@@ -848,7 +845,7 @@
 // These newly added tests are testing the API instead of results, which
 // should be covered in DeletePagesTaskTest.
 
-TEST_F(OfflinePageModelTaskifiedTest, DeletePagesByOfflineId) {
+TEST_F(OfflinePageModelTaskifiedTest, DeletePagesWithCriteria) {
   page_generator()->SetArchiveDirectory(temporary_dir_path());
   page_generator()->SetNamespace(kDefaultNamespace);
   OfflinePageItem page1 = page_generator()->CreateItemWithTempFile();
@@ -863,12 +860,14 @@
   EXPECT_CALL(callback, Run(A<DeletePageResult>()));
   CheckTaskQueueIdle();
 
-  model()->DeletePagesByOfflineId({page1.offline_id}, callback.Get());
+  PageCriteria criteria;
+  criteria.offline_ids = std::vector<int64_t>{page1.offline_id};
+  model()->DeletePagesWithCriteria(criteria, callback.Get());
   EXPECT_TRUE(task_queue()->HasRunningTask());
 
   PumpLoop();
   EXPECT_TRUE(observer_delete_page_called());
-  EXPECT_EQ(last_deleted_page_info().offline_id, page1.offline_id);
+  EXPECT_EQ(last_deleted_page().offline_id, page1.offline_id);
   EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(temporary_dir_path()));
   EXPECT_EQ(1LL, store_test_util()->GetPageCount());
   EXPECT_EQ(page1.system_download_id,
@@ -918,7 +917,7 @@
 
   PumpLoop();
   EXPECT_TRUE(observer_delete_page_called());
-  EXPECT_EQ(last_deleted_page_info().offline_id, page1.offline_id);
+  EXPECT_EQ(last_deleted_page().offline_id, page1.offline_id);
   EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(temporary_dir_path()));
   EXPECT_EQ(1LL, store_test_util()->GetPageCount());
   histogram_tester()->ExpectUniqueSample(
@@ -1064,48 +1063,6 @@
   PumpLoop();
 }
 
-TEST_F(OfflinePageModelTaskifiedTest, DeletePagesByClientIds) {
-  page_generator()->SetArchiveDirectory(temporary_dir_path());
-  page_generator()->SetNamespace(kTestClientId1.name_space);
-  page_generator()->SetId(kTestClientId1.id);
-  OfflinePageItem page1 = page_generator()->CreateItemWithTempFile();
-  page_generator()->SetId(kTestClientId2.id);
-  OfflinePageItem page2 = page_generator()->CreateItemWithTempFile();
-  InsertPageIntoStore(page1);
-  InsertPageIntoStore(page2);
-  EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(temporary_dir_path()));
-  EXPECT_EQ(2LL, store_test_util()->GetPageCount());
-
-  base::MockCallback<DeletePageCallback> callback;
-  EXPECT_CALL(callback, Run(testing::A<DeletePageResult>()));
-  CheckTaskQueueIdle();
-
-  model()->DeletePagesByClientIds({page1.client_id}, callback.Get());
-  EXPECT_TRUE(task_queue()->HasRunningTask());
-
-  PumpLoop();
-  EXPECT_TRUE(observer_delete_page_called());
-  EXPECT_EQ(last_deleted_page_info().client_id, page1.client_id);
-  EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(temporary_dir_path()));
-  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.DeletePageCount",
-      static_cast<int>(
-          model_utils::ToNamespaceEnum(page1.client_id.name_space)),
-      1);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.DeletePageResult",
-      static_cast<int>(DeletePageResult::SUCCESS), 1);
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
-                                      "OfflinePages.PageLifetime"),
-      1);
-  histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
-                                      "OfflinePages.AccessCount"),
-      1);
-}
-
 // This test is affected by https://crbug.com/725685, which only affects windows
 // platform.
 #if defined(OS_WIN)
diff --git a/components/offline_pages/core/model/persistent_page_consistency_check_task.cc b/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
index fe8f69f..81f13a18 100644
--- a/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
+++ b/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
@@ -5,6 +5,7 @@
 #include "components/offline_pages/core/model/persistent_page_consistency_check_task.h"
 
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -13,6 +14,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "components/offline_pages/core/archive_manager.h"
 #include "components/offline_pages/core/client_policy_controller.h"
+#include "components/offline_pages/core/model/delete_page_task.h"
 #include "components/offline_pages/core/offline_page_client_policy.h"
 #include "components/offline_pages/core/offline_page_metadata_store.h"
 #include "components/offline_pages/core/offline_store_utils.h"
@@ -63,20 +65,6 @@
   return result;
 }
 
-bool DeletePagesByOfflineIds(const std::vector<int64_t>& offline_ids,
-                             sql::Database* db) {
-  static const char kSql[] =
-      "DELETE FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id = ?";
-
-  for (const auto& offline_id : offline_ids) {
-    sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-    statement.BindInt64(0, offline_id);
-    if (!statement.Run())
-      return false;
-  }
-  return true;
-}
-
 bool MarkPagesAsMissing(const std::vector<int64_t>& ids_of_missing_pages,
                         base::Time missing_time,
                         sql::Database* db) {
@@ -148,7 +136,7 @@
     }
   }
 
-  if (!DeletePagesByOfflineIds(page_ids_to_delete, db) ||
+  if (!DeletePageTask::DeletePagesFromDbSync(page_ids_to_delete, db) ||
       !MarkPagesAsMissing(pages_found_missing, check_time, db) ||
       !MarkPagesAsReappeared(pages_reappeared, db)) {
     return {SyncOperationResult::DB_OPERATION_ERROR,
diff --git a/components/offline_pages/core/model/startup_maintenance_task.cc b/components/offline_pages/core/model/startup_maintenance_task.cc
index e0a612e..b44b8fc 100644
--- a/components/offline_pages/core/model/startup_maintenance_task.cc
+++ b/components/offline_pages/core/model/startup_maintenance_task.cc
@@ -4,6 +4,8 @@
 
 #include "components/offline_pages/core/model/startup_maintenance_task.h"
 
+#include <map>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -16,6 +18,7 @@
 #include "base/trace_event/trace_event.h"
 #include "components/offline_pages/core/archive_manager.h"
 #include "components/offline_pages/core/client_policy_controller.h"
+#include "components/offline_pages/core/model/delete_page_task.h"
 #include "components/offline_pages/core/offline_page_client_policy.h"
 #include "components/offline_pages/core/offline_page_metadata_store.h"
 #include "components/offline_pages/core/offline_store_utils.h"
@@ -68,20 +71,6 @@
   return result;
 }
 
-bool DeletePagesByOfflineIds(const std::vector<int64_t>& offline_ids,
-                             sql::Database* db) {
-  static const char kSql[] =
-      "DELETE FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id = ?";
-
-  for (const auto& offline_id : offline_ids) {
-    sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-    statement.BindInt64(0, offline_id);
-    if (!statement.Run())
-      return false;
-  }
-  return true;
-}
-
 bool DeleteFiles(const std::vector<base::FilePath>& file_paths) {
   bool result = true;
   for (const auto& file_path : file_paths)
@@ -140,7 +129,7 @@
   // If there's any database related errors, the function will return failure,
   // and the database operations will be rolled back since the transaction will
   // not be committed.
-  if (!DeletePagesByOfflineIds(offline_ids_to_delete, db))
+  if (!DeletePageTask::DeletePagesFromDbSync(offline_ids_to_delete, db))
     return SyncOperationResult::DB_OPERATION_ERROR;
 
   if (!transaction.Commit())
@@ -194,7 +183,7 @@
     // database related errors, the function will return false, and the database
     // operations will be rolled back since the transaction will not be
     // committed.
-    if (!DeletePagesByOfflineIds(offline_ids_to_delete, db))
+    if (!DeletePageTask::DeletePagesFromDbSync(offline_ids_to_delete, db))
       return SyncOperationResult::DB_OPERATION_ERROR;
     UMA_HISTOGRAM_COUNTS_1M(
         "OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount",
diff --git a/components/offline_pages/core/offline_page_metadata_store_test_util.cc b/components/offline_pages/core/offline_page_metadata_store_test_util.cc
index f171e40..2b67495 100644
--- a/components/offline_pages/core/offline_page_metadata_store_test_util.cc
+++ b/components/offline_pages/core/offline_page_metadata_store_test_util.cc
@@ -91,7 +91,7 @@
 std::unique_ptr<OfflinePageItem>
 OfflinePageMetadataStoreTestUtil::GetPageByOfflineId(int64_t offline_id) {
   PageCriteria criteria;
-  criteria.offline_id = offline_id;
+  criteria.offline_ids = std::vector<int64_t>{offline_id};
   OfflinePageItem* page = nullptr;
   auto task = std::make_unique<GetPagesTask>(
       store(), nullptr, criteria,
diff --git a/components/offline_pages/core/offline_page_model.cc b/components/offline_pages/core/offline_page_model.cc
index a9d7d9c2..3014ac4a 100644
--- a/components/offline_pages/core/offline_page_model.cc
+++ b/components/offline_pages/core/offline_page_model.cc
@@ -19,22 +19,6 @@
 
 OfflinePageModel::SavePageParams::~SavePageParams() = default;
 
-OfflinePageModel::DeletedPageInfo::DeletedPageInfo() = default;
-OfflinePageModel::DeletedPageInfo::DeletedPageInfo(
-    const DeletedPageInfo& other) = default;
-OfflinePageModel::DeletedPageInfo::~DeletedPageInfo() = default;
-OfflinePageModel::DeletedPageInfo::DeletedPageInfo(
-    int64_t offline_id,
-    int64_t system_download_id,
-    const ClientId& client_id,
-    const std::string& request_origin,
-    const GURL& url)
-    : offline_id(offline_id),
-      system_download_id(system_download_id),
-      client_id(client_id),
-      request_origin(request_origin),
-      url(url) {}
-
 // static
 bool OfflinePageModel::CanSaveURL(const GURL& url) {
   return url.is_valid() && url.SchemeIsHTTPOrHTTPS();
diff --git a/components/offline_pages/core/offline_page_model.h b/components/offline_pages/core/offline_page_model.h
index 028efae..f3c7acb 100644
--- a/components/offline_pages/core/offline_page_model.h
+++ b/components/offline_pages/core/offline_page_model.h
@@ -62,38 +62,6 @@
     std::string request_origin;
   };
 
-  // Information about a deleted page.
-  struct DeletedPageInfo {
-    DeletedPageInfo();
-    DeletedPageInfo(const DeletedPageInfo& other);
-    ~DeletedPageInfo();
-    DeletedPageInfo(int64_t offline_id,
-                    int64_t system_download_id,
-                    const ClientId& client_id,
-                    const std::string& request_origin,
-                    const GURL& url);
-
-    const GURL& GetOriginalUrl() const {
-      return original_url_if_different.is_empty() ? url
-                                                  : original_url_if_different;
-    }
-
-    // The ID of the deleted page.
-    int64_t offline_id;
-    // The system download manager id of the deleted page.  This will be 0 if
-    // there is no system download manager assigned id.
-    int64_t system_download_id;
-    // Client ID of the deleted page.
-    ClientId client_id;
-    // The origin that the page was saved on behalf of.
-    std::string request_origin;
-    // URL of the page that was deleted.
-    GURL url;
-    // Originally request URL of the page that was deleted. If this is empty,
-    // the final URL is not different than the original URL.
-    GURL original_url_if_different;
-  };
-
   // Observer of the OfflinePageModel.
   class Observer {
    public:
@@ -105,7 +73,7 @@
                                   const OfflinePageItem& added_page) = 0;
 
     // Invoked when an offline copy related to |offline_id| was deleted.
-    virtual void OfflinePageDeleted(const DeletedPageInfo& page_info) = 0;
+    virtual void OfflinePageDeleted(const OfflinePageItem& deleted_page) = 0;
 
     // Invoked when a thumbnail for an offline page is added.
     virtual void ThumbnailAdded(OfflinePageModel* model,
@@ -169,20 +137,9 @@
   // will be updated. Requires that the model is loaded.
   virtual void MarkPageAccessed(int64_t offline_id) = 0;
 
-  // Deletes pages based on |offline_ids|.
-  virtual void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
-                                      DeletePageCallback callback) = 0;
-
-  // Deletes all pages associated with any of |client_ids|.
-  virtual void DeletePagesByClientIds(const std::vector<ClientId>& client_ids,
-                                      DeletePageCallback callback) = 0;
-
-  // Deletes all pages associated with any of the |client_ids| provided the page
-  // also was created by origin.
-  virtual void DeletePagesByClientIdsAndOrigin(
-      const std::vector<ClientId>& client_ids,
-      const std::string& origin,
-      DeletePageCallback callback) = 0;
+  // Deletes pages that match |criteria|.
+  virtual void DeletePagesWithCriteria(const PageCriteria& criteria,
+                                       DeletePageCallback callback) = 0;
 
   // Deletes cached offline pages matching the URL predicate.
   virtual void DeleteCachedPagesByURLPredicate(const UrlPredicate& predicate,
diff --git a/components/offline_pages/core/page_criteria.cc b/components/offline_pages/core/page_criteria.cc
index 3e23981..4834d0fd 100644
--- a/components/offline_pages/core/page_criteria.cc
+++ b/components/offline_pages/core/page_criteria.cc
@@ -4,6 +4,7 @@
 
 #include "components/offline_pages/core/page_criteria.h"
 
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/offline_pages/core/client_policy_controller.h"
 #include "components/offline_pages/core/offline_page_client_policy.h"
@@ -33,18 +34,14 @@
     if (client_id.id != tab_id_str)
       return false;
   }
-  if (!criteria.client_ids.empty()) {
-    if (std::find(criteria.client_ids.begin(), criteria.client_ids.end(),
-                  client_id) == criteria.client_ids.end()) {
-      return false;
-    }
+  if (criteria.client_ids &&
+      !base::ContainsValue(criteria.client_ids.value(), client_id)) {
+    return false;
   }
-  if (!criteria.client_namespaces.empty()) {
-    if (std::find(criteria.client_namespaces.begin(),
-                  criteria.client_namespaces.end(),
-                  client_id.name_space) == criteria.client_namespaces.end()) {
-      return false;
-    }
+  if (criteria.client_namespaces &&
+      !base::ContainsValue(criteria.client_namespaces.value(),
+                           client_id.name_space)) {
+    return false;
   }
   if (criteria.supported_by_downloads &&
       !policy_controller.IsSupportedByDownload(client_id.name_space)) {
@@ -82,7 +79,12 @@
     return false;
   }
 
-  if (criteria.offline_id && criteria.offline_id.value() != item.offline_id)
+  if (criteria.offline_ids &&
+      !base::ContainsValue(criteria.offline_ids.value(), item.offline_id)) {
+    return false;
+  }
+
+  if (criteria.additional_criteria && !criteria.additional_criteria.Run(item))
     return false;
 
   return true;
@@ -93,12 +95,9 @@
     const PageCriteria& criteria) {
   std::vector<std::string> matching_namespaces;
   if (criteria.supported_by_downloads || criteria.removed_on_cache_reset) {
-    std::vector<std::string> allowed_namespaces;
-    if (criteria.client_namespaces.empty()) {
-      allowed_namespaces = policy_controller.GetAllNamespaces();
-    } else {
-      allowed_namespaces = criteria.client_namespaces;
-    }
+    std::vector<std::string> allowed_namespaces =
+        criteria.client_namespaces ? criteria.client_namespaces.value()
+                                   : policy_controller.GetAllNamespaces();
     std::vector<std::string> filtered;
     for (const std::string& name_space : allowed_namespaces) {
       if (criteria.supported_by_downloads &&
@@ -111,8 +110,8 @@
       }
       matching_namespaces.push_back(name_space);
     }
-  } else if (!criteria.client_namespaces.empty()) {
-    matching_namespaces = criteria.client_namespaces;
+  } else if (criteria.client_namespaces) {
+    matching_namespaces = criteria.client_namespaces.value();
   }
   // no filter otherwise.
 
diff --git a/components/offline_pages/core/page_criteria.h b/components/offline_pages/core/page_criteria.h
index 66910f8..84d6958 100644
--- a/components/offline_pages/core/page_criteria.h
+++ b/components/offline_pages/core/page_criteria.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/optional.h"
 #include "components/offline_pages/core/client_id.h"
 #include "url/gurl.h"
@@ -26,6 +27,11 @@
   PageCriteria(const PageCriteria&);
   PageCriteria(PageCriteria&&);
 
+  enum Order {
+    kDescendingCreationTime,
+    kAscendingAccessTime,
+  };
+
   // If non-empty, the page must match this URL. The provided URL
   // is matched both against the original and the actual URL fields (they
   // sometimes differ because of possible redirects).
@@ -45,18 +51,24 @@
   base::Optional<int64_t> file_size;
   // If non-empty, the page's digest must match.
   std::string digest;
-  // If non-empty, the page's namespace must match.
-  std::vector<std::string> client_namespaces;
-  // If non-empty, the page's client_id must match one of these.
-  std::vector<ClientId> client_ids;
+  // If set, the page's namespace must match.
+  base::Optional<std::vector<std::string>> client_namespaces;
+  // If set, the page's client_id must match one of these.
+  base::Optional<std::vector<ClientId>> client_ids;
   // If non-empty, the page's client_id.id must match this.
   std::string guid;
-  // If > 0, returns at most this many pages.
-  size_t maximum_matches = 0;
   // If non-empty, the page's request_origin must match.
   std::string request_origin;
   // If set, the page's offline_id must match.
-  base::Optional<int64_t> offline_id;
+  base::Optional<std::vector<int64_t>> offline_ids;
+  // If non-null, this function is executed for each matching item. If it
+  // returns false, the item will not be returned.
+  base::RepeatingCallback<bool(const OfflinePageItem&)> additional_criteria;
+  // If > 0, returns at most this many pages.
+  size_t maximum_matches = 0;
+  // The order results are returned. Affects which results are dropped with
+  // |maximum_matches|.
+  Order result_order = kDescendingCreationTime;
 };
 
 // Returns true if an offline page with |client_id| could potentially match
diff --git a/components/offline_pages/core/page_criteria_unittest.cc b/components/offline_pages/core/page_criteria_unittest.cc
index 05dd7db..a36b13fd 100644
--- a/components/offline_pages/core/page_criteria_unittest.cc
+++ b/components/offline_pages/core/page_criteria_unittest.cc
@@ -156,7 +156,7 @@
 
 TEST_F(PageCriteriaTest, MeetsCriteria_Namespaces) {
   PageCriteria criteria;
-  criteria.client_namespaces = {"namespace1"};
+  criteria.client_namespaces = std::vector<std::string>{"namespace1"};
 
   OfflinePageItem item;
   item.client_id.name_space = "namespace1";
@@ -174,7 +174,8 @@
 
 TEST_F(PageCriteriaTest, MeetsCriteria_MultipleNamespaces) {
   PageCriteria criteria;
-  criteria.client_namespaces = {"namespace1", "foobar1"};
+  criteria.client_namespaces =
+      std::vector<std::string>{"namespace1", "foobar1"};
 
   OfflinePageItem item;
   item.client_id.name_space = "namespace1";
@@ -195,7 +196,7 @@
 
 TEST_F(PageCriteriaTest, MeetsCriteria_ClientId) {
   PageCriteria criteria;
-  criteria.client_ids = {ClientId("namespace1", "id")};
+  criteria.client_ids = std::vector<ClientId>{ClientId("namespace1", "id")};
 
   OfflinePageItem item;
   item.client_id = ClientId("namespace1", "id");
@@ -213,9 +214,9 @@
 
 TEST_F(PageCriteriaTest, MeetsCriteria_MultipleClientId) {
   PageCriteria criteria;
-  criteria.client_ids = {ClientId("namespace1", "id"),
-                         ClientId("namespace2", "id"),
-                         ClientId("namespace3", "id3")};
+  criteria.client_ids = std::vector<ClientId>{ClientId("namespace1", "id"),
+                                              ClientId("namespace2", "id"),
+                                              ClientId("namespace3", "id3")};
 
   OfflinePageItem item;
   item.client_id = ClientId("namespace1", "id");
@@ -275,7 +276,20 @@
 
 TEST_F(PageCriteriaTest, MeetsCriteria_OfflineId) {
   PageCriteria criteria;
-  criteria.offline_id = 5;
+  criteria.offline_ids = std::vector<int64_t>{1, 5};
+
+  OfflinePageItem item;
+  item.offline_id = 5;
+  EXPECT_TRUE(MeetsCriteria(policy_controller_, criteria, item));
+
+  item.offline_id = 4;
+  EXPECT_FALSE(MeetsCriteria(policy_controller_, criteria, item));
+}
+
+TEST_F(PageCriteriaTest, MeetsCriteria_AdditionalCriteria) {
+  PageCriteria criteria;
+  criteria.additional_criteria = base::BindRepeating(
+      [](const OfflinePageItem& item) { return item.offline_id == 5; });
 
   OfflinePageItem item;
   item.offline_id = 5;
diff --git a/components/offline_pages/core/stub_offline_page_model.cc b/components/offline_pages/core/stub_offline_page_model.cc
index 2d83aef..7afa440 100644
--- a/components/offline_pages/core/stub_offline_page_model.cc
+++ b/components/offline_pages/core/stub_offline_page_model.cc
@@ -26,15 +26,8 @@
 void StubOfflinePageModel::AddPage(const OfflinePageItem& page,
                                    AddPageCallback callback) {}
 void StubOfflinePageModel::MarkPageAccessed(int64_t offline_id) {}
-void StubOfflinePageModel::DeletePagesByOfflineId(
-    const std::vector<int64_t>& offline_ids,
-    DeletePageCallback callback) {}
-void StubOfflinePageModel::DeletePagesByClientIds(
-    const std::vector<ClientId>& client_ids,
-    DeletePageCallback callback) {}
-void StubOfflinePageModel::DeletePagesByClientIdsAndOrigin(
-    const std::vector<ClientId>& client_ids,
-    const std::string& origin,
+void StubOfflinePageModel::DeletePagesWithCriteria(
+    const PageCriteria& criteria,
     DeletePageCallback callback) {}
 void StubOfflinePageModel::DeleteCachedPagesByURLPredicate(
     const UrlPredicate& predicate,
diff --git a/components/offline_pages/core/stub_offline_page_model.h b/components/offline_pages/core/stub_offline_page_model.h
index 7a0f55a..95285f4 100644
--- a/components/offline_pages/core/stub_offline_page_model.h
+++ b/components/offline_pages/core/stub_offline_page_model.h
@@ -33,13 +33,8 @@
                 SavePageCallback callback) override;
   void AddPage(const OfflinePageItem& page, AddPageCallback callback) override;
   void MarkPageAccessed(int64_t offline_id) override;
-  void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
-                              DeletePageCallback callback) override;
-  void DeletePagesByClientIds(const std::vector<ClientId>& client_ids,
-                              DeletePageCallback callback) override;
-  void DeletePagesByClientIdsAndOrigin(const std::vector<ClientId>& client_ids,
-                                       const std::string& origin,
-                                       DeletePageCallback callback) override;
+  void DeletePagesWithCriteria(const PageCriteria& criteria,
+                               DeletePageCallback callback) override;
   void DeleteCachedPagesByURLPredicate(const UrlPredicate& predicate,
                                        DeletePageCallback callback) override;
   void GetAllPages(MultipleOfflinePageItemCallback callback) override;
diff --git a/components/previews/content/previews_decider_impl.cc b/components/previews/content/previews_decider_impl.cc
index 94e87930..d569eaa 100644
--- a/components/previews/content/previews_decider_impl.cc
+++ b/components/previews/content/previews_decider_impl.cc
@@ -411,6 +411,11 @@
   // We allow all other Optimization Hint previews in the hopes that the missing
   // state will load in before commit.
   if (type == PreviewsType::LITE_PAGE_REDIRECT) {
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kIgnoreLitePageRedirectOptimizationBlacklist)) {
+      return PreviewsEligibilityReason::ALLOWED;
+    }
+
     if (!previews_opt_guide_ || !previews_opt_guide_->has_hints())
       return PreviewsEligibilityReason::OPTIMIZATION_HINTS_NOT_AVAILABLE;
     passed_reasons->push_back(
diff --git a/components/previews/content/previews_decider_impl_unittest.cc b/components/previews/content/previews_decider_impl_unittest.cc
index 0d2cd87..6942d20b 100644
--- a/components/previews/content/previews_decider_impl_unittest.cc
+++ b/components/previews/content/previews_decider_impl_unittest.cc
@@ -1160,6 +1160,44 @@
       1);
 }
 
+TEST_F(PreviewsDeciderImplTest,
+       LitePageRedirectAllowedByServerBlacklistWithFlag) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {features::kPreviews, features::kLitePageServerPreviews,
+       features::kOptimizationHints},
+      {});
+  InitializeUIService();
+  InitializeOptimizationGuideHints();
+
+  base::test::ScopedCommandLine scoped_command_line;
+  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
+  command_line->AppendSwitch(
+      switches::kIgnoreLitePageRedirectOptimizationBlacklist);
+  ASSERT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kIgnoreLitePageRedirectOptimizationBlacklist));
+
+  base::HistogramTester histogram_tester;
+
+  PreviewsUserData user_data(kDefaultPageId);
+  // First verify preview allowed for non-whitelisted url.
+  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
+      &user_data, GURL("https://www.google.com"), false,
+      PreviewsType::LITE_PAGE_REDIRECT));
+
+  histogram_tester.ExpectUniqueSample(
+      "Previews.EligibilityReason.LitePageRedirect",
+      static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
+
+  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
+      &user_data, GURL("https://blacklisted.example.com"), false,
+      PreviewsType::LITE_PAGE_REDIRECT));
+
+  histogram_tester.ExpectUniqueSample(
+      "Previews.EligibilityReason.LitePageRedirect",
+      static_cast<int>(PreviewsEligibilityReason::ALLOWED), 2);
+}
+
 TEST_F(PreviewsDeciderImplTest, OptimizationGuidePreviewsAllowedWithoutHints) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc
index 9d827542..45ee02c 100644
--- a/components/previews/content/previews_optimization_guide.cc
+++ b/components/previews/content/previews_optimization_guide.cc
@@ -184,10 +184,6 @@
   DCHECK(ui_task_runner_->BelongsToCurrentThread());
 
   if (type == PreviewsType::LITE_PAGE_REDIRECT) {
-    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kIgnoreLitePageRedirectOptimizationBlacklist)) {
-      return false;
-    }
 
     if (!hints_)
       return true;
diff --git a/components/previews/content/previews_optimization_guide_unittest.cc b/components/previews/content/previews_optimization_guide_unittest.cc
index 11d21eae..9e3445b 100644
--- a/components/previews/content/previews_optimization_guide_unittest.cc
+++ b/components/previews/content/previews_optimization_guide_unittest.cc
@@ -1691,22 +1691,6 @@
                                       PreviewsType::LITE_PAGE_REDIRECT));
 }
 
-TEST_F(PreviewsOptimizationGuideTest, LitePageRedirectSkipIsBlacklistedCheck) {
-  base::test::ScopedFeatureList scoped_list;
-  scoped_list.InitAndEnableFeature(features::kLitePageServerPreviews);
-  InitializeWithLitePageRedirectBlacklist();
-
-  EXPECT_TRUE(
-      guide()->IsBlacklisted(GURL("https://m.blacklisteddomain.com/path"),
-                             PreviewsType::LITE_PAGE_REDIRECT));
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kIgnoreLitePageRedirectOptimizationBlacklist);
-
-  EXPECT_FALSE(
-      guide()->IsBlacklisted(GURL("https://m.blacklisteddomain.com/path"),
-                             PreviewsType::LITE_PAGE_REDIRECT));
-}
-
 TEST_F(PreviewsOptimizationGuideTest,
        IsBlacklistedWithLitePageServerPreviewsDisabled) {
   base::test::ScopedFeatureList scoped_list;
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc
index 0a406c9..70f6833 100644
--- a/components/translate/content/browser/content_translate_driver.cc
+++ b/components/translate/content/browser/content_translate_driver.cc
@@ -4,6 +4,7 @@
 
 #include "components/translate/content/browser/content_translate_driver.h"
 
+#include <memory>
 #include <string>
 #include <utility>
 
@@ -11,6 +12,8 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/supports_user_data.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/google/core/common/google_util.h"
 #include "components/language/core/browser/url_language_histogram.h"
@@ -41,6 +44,15 @@
 // loading before giving up the translation
 const int kMaxTranslateLoadCheckAttempts = 20;
 
+// The key used to store page language in the NavigationEntry;
+const char kPageLanguageKey[] = "page_language";
+
+struct LanguageDectionData : public base::SupportsUserData::Data {
+  // The adopted language. An ISO 639 language code (two letters, except for
+  // Chinese where a localization is necessary).
+  std::string adopted_language;
+};
+
 }  // namespace
 
 ContentTranslateDriver::ContentTranslateDriver(
@@ -294,9 +306,18 @@
   translate_manager_->GetLanguageState().LanguageDetermined(
       details.adopted_language, page_needs_translation);
 
-  if (web_contents())
+  if (web_contents()) {
     translate_manager_->InitiateTranslation(details.adopted_language);
 
+    // Save the page language on the navigation entry so it can be synced.
+    auto* const entry = web_contents()->GetController().GetLastCommittedEntry();
+    if (entry != nullptr) {
+      auto data = std::make_unique<LanguageDectionData>();
+      data->adopted_language = details.adopted_language;
+      entry->SetUserData(kPageLanguageKey, std::move(data));
+    }
+  }
+
   for (auto& observer : observer_list_)
     observer.OnLanguageDetermined(details);
 }
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc
index dfc0147..2918bde 100644
--- a/components/translate/core/browser/translate_prefs.cc
+++ b/components/translate/core/browser/translate_prefs.cc
@@ -76,9 +76,6 @@
 // * translate_too_often_denied
 // * translate_language_blacklist
 
-const base::Feature kRegionalLocalesAsDisplayUI{
-    "RegionalLocalesAsDisplayUI", base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kTranslateRecentTarget{"TranslateRecentTarget",
                                            base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h
index ddea3c98..1acf50e 100644
--- a/components/translate/core/browser/translate_prefs.h
+++ b/components/translate/core/browser/translate_prefs.h
@@ -36,10 +36,6 @@
 
 namespace translate {
 
-// Enables or disables the regional locales as valid selection for the display
-// UI.
-extern const base::Feature kRegionalLocalesAsDisplayUI;
-
 // Enables or disables using the most recent target language as the default
 // target language option.
 extern const base::Feature kTranslateRecentTarget;
diff --git a/components/translate/core/common/BUILD.gn b/components/translate/core/common/BUILD.gn
index 94491e2..4ca3db7b 100644
--- a/components/translate/core/common/BUILD.gn
+++ b/components/translate/core/common/BUILD.gn
@@ -6,8 +6,6 @@
   sources = [
     "language_detection_details.cc",
     "language_detection_details.h",
-    "language_detection_logging_helper.cc",
-    "language_detection_logging_helper.h",
     "translate_constants.cc",
     "translate_constants.h",
     "translate_errors.h",
@@ -17,14 +15,11 @@
     "translate_switches.h",
     "translate_util.cc",
     "translate_util.h",
-    "translation_logging_helper.cc",
-    "translation_logging_helper.h",
   ]
 
   deps = [
     "//base",
     "//components/language/core/common",
-    "//components/sync/protocol",
     "//third_party/metrics_proto",
     "//url",
   ]
@@ -33,15 +28,12 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "language_detection_logging_helper_unittest.cc",
     "translate_metrics_unittest.cc",
     "translate_util_unittest.cc",
-    "translation_logging_helper_unittest.cc",
   ]
   deps = [
     ":common",
     "//base",
-    "//components/sync/protocol",
     "//testing/gtest",
     "//third_party/metrics_proto",
     "//url",
diff --git a/components/translate/core/common/language_detection_logging_helper.cc b/components/translate/core/common/language_detection_logging_helper.cc
deleted file mode 100644
index e580a1d..0000000
--- a/components/translate/core/common/language_detection_logging_helper.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/translate/core/common/language_detection_logging_helper.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "components/sync/protocol/user_event_specifics.pb.h"
-#include "components/translate/core/common/language_detection_details.h"
-
-namespace translate {
-
-std::unique_ptr<sync_pb::UserEventSpecifics> ConstructLanguageDetectionEvent(
-    const int64_t navigation_id,
-    const LanguageDetectionDetails& details) {
-  auto specifics = std::make_unique<sync_pb::UserEventSpecifics>();
-  specifics->set_event_time_usec(base::Time::Now().ToInternalValue());
-
-  specifics->set_navigation_id(navigation_id);
-
-  sync_pb::UserEventSpecifics::LanguageDetection lang_detection;
-  auto* const lang = lang_detection.add_detected_languages();
-  lang->set_language_code(details.cld_language);
-  lang->set_is_reliable(details.is_cld_reliable);
-  // Only set adopted_language when it's different from cld_language.
-  if (details.adopted_language != details.cld_language) {
-    lang_detection.set_adopted_language_code(details.adopted_language);
-  }
-  *specifics->mutable_language_detection_event() = lang_detection;
-  return specifics;
-}
-
-}  // namespace translate
diff --git a/components/translate/core/common/language_detection_logging_helper.h b/components/translate/core/common/language_detection_logging_helper.h
deleted file mode 100644
index 15ecaee5..0000000
--- a/components/translate/core/common/language_detection_logging_helper.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_TRANSLATE_CORE_COMMON_LANGUAGE_DETECTION_LOGGING_HELPER_H_
-#define COMPONENTS_TRANSLATE_CORE_COMMON_LANGUAGE_DETECTION_LOGGING_HELPER_H_
-
-#include <memory>
-
-namespace sync_pb {
-class UserEventSpecifics;
-}
-
-namespace translate {
-
-struct LanguageDetectionDetails;
-
-// Construct language detection based on navigation_id and language detection
-// details.
-std::unique_ptr<sync_pb::UserEventSpecifics> ConstructLanguageDetectionEvent(
-    int64_t navigation_id,
-    const LanguageDetectionDetails& details);
-
-}  // namespace translate
-
-#endif  // COMPONENTS_TRANSLATE_CORE_COMMON_LANGUAGE_DETECTION_LOGGING_HELPER_H_
diff --git a/components/translate/core/common/language_detection_logging_helper_unittest.cc b/components/translate/core/common/language_detection_logging_helper_unittest.cc
deleted file mode 100644
index 948fa9d..0000000
--- a/components/translate/core/common/language_detection_logging_helper_unittest.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/translate/core/common/language_detection_logging_helper.h"
-
-#include <string>
-
-#include "components/sync/protocol/user_event_specifics.pb.h"
-#include "components/translate/core/common/language_detection_details.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace translate {
-
-// Tests that sync_pb::UserEventSpecifics is correctly build.
-TEST(LanguageDetectionLoggingHelperTest, ConstructUserEventSpecifics) {
-  LanguageDetectionDetails details;
-  details.cld_language = "en";
-  details.is_cld_reliable = false;
-  details.adopted_language = "ja";
-  // Expected language detection.
-  sync_pb::UserEventSpecifics::LanguageDetection lang_detection;
-  auto* const lang = lang_detection.add_detected_languages();
-  lang->set_language_code(details.cld_language);
-  lang->set_is_reliable(details.is_cld_reliable);
-  lang_detection.set_adopted_language_code(details.adopted_language);
-  const int64_t navigation_id = 1000000000000000LL;
-  const std::unique_ptr<sync_pb::UserEventSpecifics> user_event =
-      ConstructLanguageDetectionEvent(navigation_id, details);
-  // Expect the navigation id is correctly set.
-  EXPECT_EQ(user_event->navigation_id(), navigation_id);
-  EXPECT_EQ(user_event->language_detection_event().SerializeAsString(),
-            lang_detection.SerializeAsString());
-}
-
-// Tests that sync_pb::UserEventSpecifics is correctly build.
-// If adopted_language is the same as cld_language, we don't set it.
-TEST(LanguageDetectionLoggingHelperTest, DontSetAdoptedLanguage) {
-  LanguageDetectionDetails details;
-  details.cld_language = "en";
-  details.is_cld_reliable = true;
-  details.adopted_language = "en";
-  // Expected language detection.
-  sync_pb::UserEventSpecifics::LanguageDetection lang_detection;
-  auto* const lang = lang_detection.add_detected_languages();
-  lang->set_language_code(details.cld_language);
-  lang->set_is_reliable(details.is_cld_reliable);
-  const std::unique_ptr<sync_pb::UserEventSpecifics> user_event =
-      ConstructLanguageDetectionEvent(100, details);
-  // Expect the navigation id is correctly set.
-  EXPECT_EQ(user_event->navigation_id(), 100);
-  EXPECT_EQ(user_event->language_detection_event().SerializeAsString(),
-            lang_detection.SerializeAsString());
-}
-
-}  // namespace translate
diff --git a/components/translate/core/common/translation_logging_helper.cc b/components/translate/core/common/translation_logging_helper.cc
deleted file mode 100644
index ef4bcdb..0000000
--- a/components/translate/core/common/translation_logging_helper.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/translate/core/common/translation_logging_helper.h"
-
-#include "base/logging.h"
-#include "base/time/time.h"
-#include "components/sync/protocol/user_event_specifics.pb.h"
-#include "third_party/metrics_proto/translate_event.pb.h"
-
-using Translation = sync_pb::UserEventSpecifics::Translation;
-
-namespace translate {
-namespace {
-using metrics::TranslateEventProto;
-}  // namespace
-
-bool ConstructTranslateEvent(const int64_t navigation_id,
-                             const TranslateEventProto& translate_event,
-                             sync_pb::UserEventSpecifics* const specifics) {
-  specifics->set_event_time_usec(base::Time::Now().ToInternalValue());
-
-  specifics->set_navigation_id(navigation_id);
-  auto* const translation = specifics->mutable_translation_event();
-  translation->set_from_language_code(translate_event.source_language());
-  translation->set_to_language_code(translate_event.target_language());
-  switch (translate_event.event_type()) {
-    case TranslateEventProto::UNKNOWN:
-      translation->set_interaction(Translation::UNKNOWN);
-      break;
-    case TranslateEventProto::USER_ACCEPT:
-      if (translate_event.has_modified_source_language() ||
-          translate_event.has_modified_target_language()) {
-        // Special case, since we don't have event enum telling us it's actually
-        // modified by user, we do this by check whether this event has modified
-        // source or target language.
-        if (translate_event.has_modified_source_language()) {
-          translation->set_from_language_code(
-              translate_event.modified_source_language());
-        }
-        if (translate_event.has_modified_target_language()) {
-          translation->set_to_language_code(
-              translate_event.modified_target_language());
-        }
-        translation->set_interaction(Translation::MANUAL);
-      } else {
-        translation->set_interaction(Translation::ACCEPT);
-      }
-      break;
-    case TranslateEventProto::USER_DECLINE:
-      translation->set_interaction(Translation::DECLINE);
-      break;
-    case TranslateEventProto::USER_IGNORE:
-      translation->set_interaction(Translation::IGNORED);
-      break;
-    case TranslateEventProto::USER_DISMISS:
-      translation->set_interaction(Translation::DISMISSED);
-      break;
-    case TranslateEventProto::USER_REVERT:
-      translation->set_interaction(Translation::TRANSLATION_REVERTED);
-      break;
-    case TranslateEventProto::AUTO_TRANSLATION_BY_PREF:
-      translation->set_interaction(Translation::AUTO_TRANSLATION_BY_PREF);
-      break;
-    case TranslateEventProto::AUTO_TRANSLATION_BY_LINK:
-      translation->set_interaction(Translation::AUTO_TRANSLATION_BY_LINK);
-      break;
-    case TranslateEventProto::INITIALIZATION_ERROR:
-      translation->set_interaction(Translation::INITIALIZATION_ERROR);
-      break;
-    default:  // We don't care about other events.
-      return false;
-  }
-  return true;
-}
-}  // namespace translate
diff --git a/components/translate/core/common/translation_logging_helper.h b/components/translate/core/common/translation_logging_helper.h
deleted file mode 100644
index 1e6e16a..0000000
--- a/components/translate/core/common/translation_logging_helper.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_TRANSLATE_CORE_COMMON_TRANSLATION_LOGGING_HELPER_H_
-#define COMPONENTS_TRANSLATE_CORE_COMMON_TRANSLATION_LOGGING_HELPER_H_
-
-#include <stdint.h>
-
-namespace metrics {
-class TranslateEventProto;
-}  // namespace metrics
-
-namespace sync_pb {
-class UserEventSpecifics;
-}  // namespace sync_pb
-
-namespace translate {
-
-// Construct the sync_pb::Translation proto.
-// If the event is the event that we care about, will return true, otherwise,
-// will return false.
-bool ConstructTranslateEvent(
-    int64_t navigation_id,
-    const metrics::TranslateEventProto& translate_event,
-    sync_pb::UserEventSpecifics* const specifics);
-}  // namespace translate
-
-#endif  // COMPONENTS_TRANSLATE_CORE_COMMON_TRANSLATION_LOGGING_HELPER_H_
\ No newline at end of file
diff --git a/components/translate/core/common/translation_logging_helper_unittest.cc b/components/translate/core/common/translation_logging_helper_unittest.cc
deleted file mode 100644
index 8b26b7a..0000000
--- a/components/translate/core/common/translation_logging_helper_unittest.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/translate/core/common/translation_logging_helper.h"
-
-#include <string>
-
-#include "base/logging.h"
-#include "components/sync/protocol/user_event_specifics.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/metrics_proto/translate_event.pb.h"
-
-using metrics::TranslateEventProto;
-using Translation = sync_pb::UserEventSpecifics::Translation;
-
-void EqualTranslationProto(const Translation& first,
-                           const Translation& second) {
-  EXPECT_EQ(first.from_language_code(), second.from_language_code());
-  EXPECT_EQ(first.to_language_code(), second.to_language_code());
-  EXPECT_EQ(first.interaction(), second.interaction());
-}
-
-namespace translate {
-
-// Tests that UserEventSpecifics is correctly built.
-TEST(TranslationLoggingHelperTest, ConstructUserEventSpecifics) {
-  // The event we have.
-  TranslateEventProto translation_event;
-  translation_event.set_source_language("ja");
-  translation_event.set_target_language("en");
-  translation_event.set_event_type(TranslateEventProto::USER_DECLINE);
-  // Expected user_event.
-  Translation user_translation_event;
-  user_translation_event.set_from_language_code("ja");
-  user_translation_event.set_to_language_code("en");
-  user_translation_event.set_interaction(Translation::DECLINE);
-  // The user event.
-  sync_pb::UserEventSpecifics user_specifics;
-  const int64_t navigation_id = 1000000000000000LL;
-  const bool needs_logging = ConstructTranslateEvent(
-      navigation_id, translation_event, &user_specifics);
-  EXPECT_TRUE(needs_logging);
-  EXPECT_EQ(user_specifics.navigation_id(), navigation_id);
-  EqualTranslationProto(user_translation_event,
-                        user_specifics.translation_event());
-}
-
-// Tests that if user change the target language, the event is MANUAL.
-TEST(TranslationLoggingHelperTest, UserManualEvent) {
-  // The event we have.
-  TranslateEventProto translation_event;
-  translation_event.set_source_language("ja");
-  translation_event.set_target_language("en");
-  translation_event.set_modified_target_language("fr");
-  translation_event.set_event_type(TranslateEventProto::USER_ACCEPT);
-  // Expected user_event.
-  Translation user_translation_event;
-  user_translation_event.set_from_language_code("ja");
-  user_translation_event.set_to_language_code("fr");
-  user_translation_event.set_interaction(Translation::MANUAL);
-  // The user event.
-  sync_pb::UserEventSpecifics user_specifics;
-  const int64_t navigation_id = 100;
-  const bool needs_logging = ConstructTranslateEvent(
-      navigation_id, translation_event, &user_specifics);
-  EXPECT_TRUE(needs_logging);
-  EXPECT_EQ(user_specifics.navigation_id(), navigation_id);
-  EqualTranslationProto(user_translation_event,
-                        user_specifics.translation_event());
-}
-
-// Tests that we don't build unnecessary events.
-TEST(TranslationLoggingHelperTest, DontBuildUnnecessaryEvent) {
-  // The event we have.
-  TranslateEventProto translation_event;
-  translation_event.set_source_language("ja");
-  translation_event.set_target_language("en");
-  // The event we don't care.
-  translation_event.set_event_type(TranslateEventProto::DISABLED_BY_RANKER);
-  // The user event.
-  sync_pb::UserEventSpecifics user_specifics;
-  const bool needs_logging =
-      ConstructTranslateEvent(100, translation_event, &user_specifics);
-  // We don't expect the event to be logged.
-  EXPECT_FALSE(needs_logging);
-}
-
-}  // namespace translate
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 00cef15..36494b1 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -699,6 +699,18 @@
       occluding_damage_rect_valid);
 }
 
+gfx::RRectF MapRoundedBounds(const gfx::RRectF& old_bounds,
+                             const gfx::Transform& transform) {
+  if (old_bounds.IsEmpty())
+    return old_bounds;
+  DCHECK(transform.Preserves2dAxisAlignment());
+  gfx::RRectF bounds(old_bounds);
+  SkMatrix matrix = transform.matrix();
+  bounds.Scale(matrix.getScaleX(), matrix.getScaleY());
+  bounds.Offset(transform.To2dTranslation());
+  return bounds;
+}
+
 SharedQuadState* SurfaceAggregator::CopyAndScaleSharedQuadState(
     const SharedQuadState* source_sqs,
     const gfx::Transform& scaled_quad_to_target_transform,
@@ -725,9 +737,14 @@
   gfx::Transform new_transform = scaled_quad_to_target_transform;
   new_transform.ConcatTransform(target_transform);
 
+  // The rounded corner bounds need to be in the space of the target. Since
+  // the target may have changed, apply the extra transform to the new target.
+  gfx::RRectF new_bounds =
+      MapRoundedBounds(*rounded_corner_info.bounds, target_transform);
+
   shared_quad_state->SetAll(
-      new_transform, quad_layer_rect, visible_quad_layer_rect,
-      *rounded_corner_info.bounds, new_clip_rect.rect, new_clip_rect.is_clipped,
+      new_transform, quad_layer_rect, visible_quad_layer_rect, new_bounds,
+      new_clip_rect.rect, new_clip_rect.is_clipped,
       source_sqs->are_contents_opaque, source_sqs->opacity,
       source_sqs->blend_mode, source_sqs->sorting_context_id);
   shared_quad_state->is_fast_rounded_corner =
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index 21d0f33..e79385b 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -173,7 +173,8 @@
                             float opacity,
                             const gfx::Transform& transform,
                             bool stretch_content_to_fill_bounds,
-                            bool ignores_input_event) {
+                            bool ignores_input_event,
+                            const gfx::RRectF& rounded_corner_bounds) {
       Quad quad;
       quad.material = DrawQuad::Material::kSurfaceContent;
       quad.primary_surface_rect = primary_surface_rect;
@@ -183,6 +184,7 @@
       quad.default_background_color = default_background_color;
       quad.stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
       quad.ignores_input_event = ignores_input_event;
+      quad.rounded_corner_bounds = rounded_corner_bounds;
       return quad;
     }
 
@@ -207,6 +209,7 @@
     gfx::Rect rect;
     // Set when material==DrawQuad::Material::kRenderPass.
     RenderPassId render_pass_id;
+    gfx::RRectF rounded_corner_bounds;
 
    private:
     Quad()
@@ -246,7 +249,7 @@
                        desc.to_target_transform, desc.surface_range,
                        desc.default_background_color,
                        desc.stretch_content_to_fill_bounds,
-                       desc.ignores_input_event);
+                       desc.ignores_input_event, desc.rounded_corner_bounds);
         break;
       case DrawQuad::Material::kRenderPass:
         AddRenderPassQuad(pass, desc.render_pass_id);
@@ -329,11 +332,11 @@
                              const SurfaceRange& surface_range,
                              SkColor default_background_color,
                              bool stretch_content_to_fill_bounds,
-                             bool ignores_input_event) {
+                             bool ignores_input_event,
+                             const gfx::RRectF& rounded_corner_bounds) {
     gfx::Transform layer_to_target_transform = transform;
     gfx::Rect layer_bounds(primary_surface_rect);
     gfx::Rect visible_layer_rect(primary_surface_rect);
-    gfx::RRectF rounded_corner_bounds = gfx::RRectF();
     gfx::Rect clip_rect(primary_surface_rect);
     bool is_clipped = false;
     bool are_contents_opaque = false;
@@ -504,7 +507,7 @@
       quads.push_back(Quad::SurfaceQuad(
           range, SK_ColorWHITE, gfx::Rect(5, 5), 1.f, gfx::Transform(),
           /*stretch_content_to_fill_bounds=*/false,
-          /*ignores_input_event=*/false));
+          /*ignores_input_event=*/false, gfx::RRectF()));
     }
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
     RenderPassList pass_list;
@@ -596,7 +599,7 @@
         Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
                           SK_ColorWHITE, gfx::Rect(5, 5), .5f, gfx::Transform(),
                           /*stretch_content_to_fill_bounds=*/false,
-                          /*ignores_input_event=*/false)};
+                          /*ignores_input_event=*/false, gfx::RRectF())};
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
     SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -620,7 +623,7 @@
         SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
         gfx::Rect(5, 5), .9999f, gfx::Transform(),
         /*stretch_content_to_fill_bounds=*/false,
-        /*ignores_input_event=*/false)};
+        /*ignores_input_event=*/false, gfx::RRectF())};
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
     SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -661,7 +664,7 @@
   std::vector<Quad> quads = {Quad::SurfaceQuad(
       SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
       gfx::Rect(5, 5), 1.f, rotate, /*stretch_content_to_fill_bounds=*/false,
-      /*ignores_input_event=*/false)};
+      /*ignores_input_event=*/false, gfx::RRectF())};
   std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
   SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -4902,7 +4905,7 @@
                         /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
                         /*opacity*/ 1.f, video_transform,
                         /*stretch_content_to_fill_bounds=*/false,
-                        /*ignores_input_event=*/false)};
+                        /*ignores_input_event=*/false, gfx::RRectF())};
 
   std::vector<Pass> root_passes = {
       Pass(root_surface_quads,
@@ -4999,7 +5002,7 @@
         /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
         /*opacity*/ 1.f, video_transform,
         /*stretch_content_to_fill_bounds=*/false,
-        /*ignores_input_event=*/false)};
+        /*ignores_input_event=*/false, gfx::RRectF())};
 
     std::vector<Pass> root_passes = {
         Pass(root_surface_quads,
@@ -5164,5 +5167,242 @@
     EXPECT_EQ(1u, aggregated_pass_list[2]->quad_list.size());
   }
 }
+
+// Tests that a rounded_corner_bounds field on a quad in a child
+// surface gets mapped up to the space of the parent surface, due to
+// change of target render surface. (rounded corner bounds are in the space
+// of the render surface).
+TEST_F(SurfaceAggregatorValidSurfaceTest, RoundedCornerTransformChange) {
+  auto middle_support = std::make_unique<CompositorFrameSinkSupport>(
+      nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
+      kNeedsSyncPoints);
+  // Child surface.
+  ParentLocalSurfaceIdAllocator child_allocator;
+  child_allocator.GenerateId();
+  LocalSurfaceId child_local_surface_id =
+      child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+  SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+                             child_local_surface_id);
+  {
+    std::vector<Quad> child_quads[1] = {
+        {Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))},
+    };
+    std::vector<Pass> child_passes = {Pass(child_quads[0], 1, SurfaceSize())};
+
+    CompositorFrame child_frame = MakeEmptyCompositorFrame();
+    AddPasses(&child_frame.render_pass_list, child_passes,
+              &child_frame.metadata.referenced_surfaces);
+
+    child_frame.render_pass_list[0]
+        ->shared_quad_state_list.front()
+        ->rounded_corner_bounds = gfx::RRectF(0, 0, 100, 10, 5);
+
+    child_sink_->SubmitCompositorFrame(child_local_surface_id,
+                                       std::move(child_frame));
+  }
+
+  // Root surface.
+  std::vector<Quad> surface_quads = {
+      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
+                        SK_ColorWHITE, gfx::Rect(5, 5), false, false)};
+  std::vector<Pass> root_passes = {Pass(surface_quads, SurfaceSize())};
+
+  CompositorFrame root_frame = MakeEmptyCompositorFrame();
+  AddPasses(&root_frame.render_pass_list, root_passes,
+            &root_frame.metadata.referenced_surfaces);
+
+  root_frame.render_pass_list[0]
+      ->shared_quad_state_list.front()
+      ->quad_to_target_transform.Translate(0, 7);
+  root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+                                    std::move(root_frame));
+
+  SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+                            root_local_surface_id_);
+
+  CompositorFrame aggregated_frame =
+      aggregator_.Aggregate(root_surface_id, GetNextDisplayTimeAndIncrement());
+  auto* aggregated_first_pass_sqs =
+      aggregated_frame.render_pass_list[0]->shared_quad_state_list.front();
+
+  EXPECT_EQ(gfx::RRectF(0, 7, 100, 10, 5),
+            aggregated_first_pass_sqs->rounded_corner_bounds);
+}
+
+// Tests that the rounded corner bounds of a surface quad that gets transformed
+// when drawing into an ancestor surface get properly mapped to the new
+// coordinate space of its final render surface. It also tests the specific case
+// where the surface is embedded in a parent surface that itself can't be
+// merged into the root surface (due to opacity).
+TEST_F(SurfaceAggregatorValidSurfaceTest, RoundedCornerTransformedSurfaceQuad) {
+  auto middle_support = std::make_unique<CompositorFrameSinkSupport>(
+      nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
+      kNeedsSyncPoints);
+  // Grandchild surface.
+  ParentLocalSurfaceIdAllocator child_allocator;
+  child_allocator.GenerateId();
+
+  LocalSurfaceId grandchild_local_surface_id =
+      child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+  SurfaceId grandchild_surface_id(child_sink_->frame_sink_id(),
+                                  grandchild_local_surface_id);
+  {
+    std::vector<Quad> child_quads[1] = {
+        {Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))},
+    };
+    std::vector<Pass> child_passes = {Pass(child_quads[0], 1, SurfaceSize())};
+
+    CompositorFrame child_frame = MakeEmptyCompositorFrame();
+    AddPasses(&child_frame.render_pass_list, child_passes,
+              &child_frame.metadata.referenced_surfaces);
+
+    child_sink_->SubmitCompositorFrame(grandchild_local_surface_id,
+                                       std::move(child_frame));
+  }
+
+  // Child surface.
+  child_allocator.GenerateId();
+  LocalSurfaceId child_local_surface_id =
+      child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+  SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+                             child_local_surface_id);
+  {
+    // Set an opacity in order to prevent merging into the root render pass.
+    std::vector<Quad> child_quads = {Quad::SurfaceQuad(
+        SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
+        gfx::Rect(5, 5), 0.5f, gfx::Transform(), false, false,
+        gfx::RRectF(0, 0, 96, 10, 5))};
+
+    std::vector<Pass> child_passes = {Pass(child_quads, 1, SurfaceSize())};
+
+    CompositorFrame child_frame = MakeEmptyCompositorFrame();
+    AddPasses(&child_frame.render_pass_list, child_passes,
+              &child_frame.metadata.referenced_surfaces);
+
+    child_sink_->SubmitCompositorFrame(child_local_surface_id,
+                                       std::move(child_frame));
+  }
+
+  // Root surface.
+  gfx::Transform surface_transform;
+  surface_transform.Translate(3, 4);
+  std::vector<Quad> secondary_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), 1.f, surface_transform, false, false, gfx::RRectF())};
+
+  std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize())};
+
+  CompositorFrame root_frame =
+      CompositorFrameBuilder().SetDeviceScaleFactor(2.0f).Build();
+  AddPasses(&root_frame.render_pass_list, root_passes,
+            &root_frame.metadata.referenced_surfaces);
+
+  root_frame.render_pass_list[0]
+      ->shared_quad_state_list.front()
+      ->quad_to_target_transform.Translate(0, 7);
+  root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+                                    std::move(root_frame));
+
+  SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+                            root_local_surface_id_);
+
+  CompositorFrame aggregated_frame =
+      aggregator_.Aggregate(root_surface_id, GetNextDisplayTimeAndIncrement());
+  auto* aggregated_first_pass_sqs =
+      aggregated_frame.render_pass_list[1]->shared_quad_state_list.front();
+
+  // Original rounded rect is (0, 0, 96, 10, 5). This then gets multiplied
+  // by a device scale factor of 2 to (0, 0, 192, 20, 10), then moved
+  // by a (3, 4) translation followed by a (0, 7) translation.
+  EXPECT_EQ(gfx::RRectF(3, 11, 192, 20, 10),
+            aggregated_first_pass_sqs->rounded_corner_bounds);
+}
+
+// This is a variant of RoundedCornerTransformedSurfaceQuad that does not
+// have opacity, and therefore can be merged into the root render pass.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+       RoundedCornerTransformedMergedSurfaceQuad) {
+  auto middle_support = std::make_unique<CompositorFrameSinkSupport>(
+      nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
+      kNeedsSyncPoints);
+  // Grandchild surface.
+  ParentLocalSurfaceIdAllocator child_allocator;
+  child_allocator.GenerateId();
+
+  LocalSurfaceId grandchild_local_surface_id =
+      child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+  SurfaceId grandchild_surface_id(child_sink_->frame_sink_id(),
+                                  grandchild_local_surface_id);
+  {
+    std::vector<Quad> child_quads[1] = {
+        {Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))},
+    };
+    std::vector<Pass> child_passes = {Pass(child_quads[0], 1, SurfaceSize())};
+
+    CompositorFrame child_frame = MakeEmptyCompositorFrame();
+    AddPasses(&child_frame.render_pass_list, child_passes,
+              &child_frame.metadata.referenced_surfaces);
+
+    child_sink_->SubmitCompositorFrame(grandchild_local_surface_id,
+                                       std::move(child_frame));
+  }
+
+  // Child surface.
+  child_allocator.GenerateId();
+  LocalSurfaceId child_local_surface_id =
+      child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+  SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+                             child_local_surface_id);
+  {
+    std::vector<Quad> child_quads = {
+        Quad::SurfaceQuad(SurfaceRange(base::nullopt, grandchild_surface_id),
+                          SK_ColorWHITE, gfx::Rect(5, 5), 1.f, gfx::Transform(),
+                          false, false, gfx::RRectF(0, 0, 96, 10, 5))};
+
+    std::vector<Pass> child_passes = {Pass(child_quads, 1, SurfaceSize())};
+
+    CompositorFrame child_frame = MakeEmptyCompositorFrame();
+    AddPasses(&child_frame.render_pass_list, child_passes,
+              &child_frame.metadata.referenced_surfaces);
+
+    child_sink_->SubmitCompositorFrame(child_local_surface_id,
+                                       std::move(child_frame));
+  }
+
+  // Root surface.
+  gfx::Transform surface_transform;
+  surface_transform.Translate(3, 4);
+  std::vector<Quad> secondary_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), 1.f, surface_transform, false, false, gfx::RRectF())};
+
+  std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize())};
+
+  CompositorFrame root_frame =
+      CompositorFrameBuilder().SetDeviceScaleFactor(2.0f).Build();
+  AddPasses(&root_frame.render_pass_list, root_passes,
+            &root_frame.metadata.referenced_surfaces);
+
+  root_frame.render_pass_list[0]
+      ->shared_quad_state_list.front()
+      ->quad_to_target_transform.Translate(0, 7);
+  root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+                                    std::move(root_frame));
+
+  SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+                            root_local_surface_id_);
+
+  CompositorFrame aggregated_frame =
+      aggregator_.Aggregate(root_surface_id, GetNextDisplayTimeAndIncrement());
+  auto* aggregated_first_pass_sqs =
+      aggregated_frame.render_pass_list[1]->shared_quad_state_list.front();
+
+  // Original rounded rect is (0, 0, 96, 10, 5). This then gets multiplied
+  // by a device scale factor of 2 to (0, 0, 192, 20, 10), then moved
+  // by a (3, 4) translation followed by a (0, 7) translation.
+  EXPECT_EQ(gfx::RRectF(3, 11, 192, 20, 10),
+            aggregated_first_pass_sqs->rounded_corner_bounds);
+}
+
 }  // namespace
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_device_offscreen.cc b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
index 318f607..e676c698 100644
--- a/components/viz/service/display_embedder/skia_output_device_offscreen.cc
+++ b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
@@ -33,7 +33,8 @@
   // kRGBA_8888_SkColorType instead and initialize surface to opaque alpha.
   image_info_ =
       SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType,
-                        has_alpha_ ? kPremul_SkAlphaType : kOpaque_SkAlphaType);
+                        has_alpha_ ? kPremul_SkAlphaType : kOpaque_SkAlphaType,
+                        color_space.ToSkColorSpace());
   draw_surface_ = SkSurface::MakeRenderTarget(
       gr_context_, SkBudgeted::kNo, image_info_, 0 /* sampleCount */,
       capabilities_.flipped_output_surface ? kTopLeft_GrSurfaceOrigin
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc b/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc
index 32c62d39..538dfa51 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc
@@ -336,6 +336,8 @@
       .fNumSemaphores = pending_semaphores_.size(),
       .fSignalSemaphores = pending_semaphores_.data(),
   };
+  gpu::CreateCleanupCallbackForSkiaFlush(
+      shared_context_state_->vk_context_provider(), &flush_info);
   auto result = sk_current_surface_->flush(access, flush_info);
   DCHECK_EQ(result, GrSemaphoresSubmitted::kYes);
   pending_semaphores_.clear();
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index aa31956..f3d71eb 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -464,6 +464,8 @@
         .fSignalSemaphores =
             scoped_promise_image_access.end_semaphores().data(),
     };
+    gpu::CreateCleanupCallbackForSkiaFlush(vulkan_context_provider_,
+                                           &flush_info);
     auto result = output_sk_surface()->flush(
         SkSurface::BackendSurfaceAccess::kPresent, flush_info);
     if (result != GrSemaphoresSubmitted::kYes &&
@@ -562,7 +564,8 @@
         .fSignalSemaphores =
             scoped_promise_image_access.end_semaphores().data(),
     };
-
+    gpu::CreateCleanupCallbackForSkiaFlush(vulkan_context_provider_,
+                                           &flush_info);
     auto result = offscreen.surface()->flush(
         SkSurface::BackendSurfaceAccess::kNoAccess, flush_info);
     if (result != GrSemaphoresSubmitted::kYes &&
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
index 625566d..8739456 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -166,7 +166,7 @@
     const viz::LocalSurfaceIdAllocation& child_local_surface_id_allocation) {
   if (dfh_local_surface_id_allocator_.UpdateFromChild(
           child_local_surface_id_allocation)) {
-    dfh_display_.set_device_scale_factor(new_device_scale_factor);
+    dfh_display_.SetDeviceScaleFactor(new_device_scale_factor);
     dfh_size_dip_ = gfx::ConvertSizeToDIP(dfh_display_.device_scale_factor(),
                                           new_size_in_pixels);
     dfh_size_pixels_ = new_size_in_pixels;
@@ -402,7 +402,7 @@
 
 bool BrowserCompositorMac::ForceNewSurfaceForTesting() {
   display::Display new_display(dfh_display_);
-  new_display.set_device_scale_factor(new_display.device_scale_factor() * 2.0f);
+  new_display.SetDeviceScaleFactor(new_display.device_scale_factor() * 2.0f);
   return UpdateSurfaceFromNSView(dfh_size_dip_, new_display);
 }
 
diff --git a/content/common/cursors/webcursor_unittest.cc b/content/common/cursors/webcursor_unittest.cc
index 0c48c9fa..203f1c99 100644
--- a/content/common/cursors/webcursor_unittest.cc
+++ b/content/common/cursors/webcursor_unittest.cc
@@ -126,7 +126,7 @@
   WebCursor cursor(info);
 
   display::Display display;
-  display.set_device_scale_factor(4.2f);
+  display.SetDeviceScaleFactor(4.2f);
   cursor.SetDisplayInfo(display);
 
 #if defined(USE_OZONE)
@@ -171,7 +171,7 @@
   WebCursor cursor(info);
 
   display::Display display;
-  display.set_device_scale_factor(scale);
+  display.SetDeviceScaleFactor(scale);
   cursor.SetDisplayInfo(display);
 
   HCURSOR windows_cursor_handle = cursor.GetNativeCursor().platform();
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 1d32d72..d10d5ee 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -217,7 +217,6 @@
   IPC_STRUCT_TRAITS_MEMBER(wide_viewport_quirk)
   IPC_STRUCT_TRAITS_MEMBER(use_wide_viewport)
   IPC_STRUCT_TRAITS_MEMBER(force_zero_layout_height)
-  IPC_STRUCT_TRAITS_MEMBER(viewport_meta_layout_size_quirk)
   IPC_STRUCT_TRAITS_MEMBER(viewport_meta_merge_content_quirk)
   IPC_STRUCT_TRAITS_MEMBER(viewport_meta_non_user_scalable_quirk)
   IPC_STRUCT_TRAITS_MEMBER(viewport_meta_zero_values_quirk)
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index 65a18cd..9a22b00 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -194,7 +194,6 @@
       wide_viewport_quirk(false),
       use_wide_viewport(true),
       force_zero_layout_height(false),
-      viewport_meta_layout_size_quirk(false),
       viewport_meta_merge_content_quirk(false),
       viewport_meta_non_user_scalable_quirk(false),
       viewport_meta_zero_values_quirk(false),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index 653f39410..663c846 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -241,7 +241,6 @@
   bool wide_viewport_quirk;
   bool use_wide_viewport;
   bool force_zero_layout_height;
-  bool viewport_meta_layout_size_quirk;
   bool viewport_meta_merge_content_quirk;
   bool viewport_meta_non_user_scalable_quirk;
   bool viewport_meta_zero_values_quirk;
diff --git a/content/renderer/input/main_thread_event_queue.cc b/content/renderer/input/main_thread_event_queue.cc
index 4a77a0e..cd94fbf 100644
--- a/content/renderer/input/main_thread_event_queue.cc
+++ b/content/renderer/input/main_thread_event_queue.cc
@@ -68,8 +68,8 @@
     // There is no pointermove at this point in the queue.
     DCHECK(event().GetType() != WebInputEvent::kPointerMove &&
            other_event->event().GetType() != WebInputEvent::kPointerMove);
-    return event().GetType() == WebInputEvent::kPointerRawMove &&
-           other_event->event().GetType() == WebInputEvent::kPointerRawMove;
+    return event().GetType() == WebInputEvent::kPointerRawUpdate &&
+           other_event->event().GetType() == WebInputEvent::kPointerRawUpdate;
   }
 
   FilterResult FilterNewEvent(MainThreadEventQueueTask* other_task) override {
@@ -88,7 +88,7 @@
 
     if (!ScopedWebInputEventWithLatencyInfo::CanCoalesceWith(*other_event)) {
       // Two pointerevents may not be able to coalesce but we should continue
-      // looking further down the queue if both of them were rawmove or move
+      // looking further down the queue if both of them were rawupdate or move
       // events and only their pointer_type, id, or event_type was different.
       if (ArePointerMoveEventTypes(other_event))
         return FilterResult::KeepIterating;
@@ -323,10 +323,10 @@
     event_callback = std::move(callback);
   }
 
-  if (has_pointerrawmove_handlers_) {
+  if (has_pointerrawupdate_handlers_) {
     if (event->GetType() == WebInputEvent::kMouseMove) {
       ui::WebScopedInputEvent raw_event(new blink::WebPointerEvent(
-          WebInputEvent::kPointerRawMove,
+          WebInputEvent::kPointerRawUpdate,
           *(static_cast<blink::WebMouseEvent*>(event.get()))));
       std::unique_ptr<QueuedWebInputEvent> raw_queued_event(
           new QueuedWebInputEvent(std::move(raw_event), latency, false,
@@ -341,7 +341,7 @@
         if (touch_point.state == blink::WebTouchPoint::kStateMoved) {
           ui::WebScopedInputEvent raw_event(
               new blink::WebPointerEvent(touch_event, touch_point));
-          raw_event->SetType(WebInputEvent::kPointerRawMove);
+          raw_event->SetType(WebInputEvent::kPointerRawUpdate);
           std::unique_ptr<QueuedWebInputEvent> raw_queued_event(
               new QueuedWebInputEvent(std::move(raw_event), latency, false,
                                       HandledEventCallback(), false));
@@ -443,7 +443,7 @@
       if (current_task_index >= queue_size ||
           current_task_index >= shared_state_.events_.size())
         break;
-      if (IsRawMoveEvent(shared_state_.events_.at(current_task_index))) {
+      if (IsRawUpdateEvent(shared_state_.events_.at(current_task_index))) {
         task = shared_state_.events_.remove(current_task_index);
         --queue_size;
         --current_task_index;
@@ -571,17 +571,17 @@
     SetNeedsMainFrame();
 }
 
-bool MainThreadEventQueue::IsRawMoveEvent(
+bool MainThreadEventQueue::IsRawUpdateEvent(
     const std::unique_ptr<MainThreadEventQueueTask>& item) const {
   return item->IsWebInputEvent() &&
          static_cast<const QueuedWebInputEvent*>(item.get())
                  ->event()
-                 .GetType() == blink::WebInputEvent::kPointerRawMove;
+                 .GetType() == blink::WebInputEvent::kPointerRawUpdate;
 }
 
 bool MainThreadEventQueue::ShouldFlushQueue(
     const std::unique_ptr<MainThreadEventQueueTask>& item) const {
-  if (IsRawMoveEvent(item))
+  if (IsRawUpdateEvent(item))
     return false;
   return !IsRafAlignedEvent(item);
 }
@@ -676,8 +676,8 @@
   needs_unbuffered_input_for_debugger_ = unbuffered;
 }
 
-void MainThreadEventQueue::HasPointerRawMoveEventHandlers(bool has_handlers) {
-  has_pointerrawmove_handlers_ = has_handlers;
+void MainThreadEventQueue::HasPointerRawUpdateEventHandlers(bool has_handlers) {
+  has_pointerrawupdate_handlers_ = has_handlers;
 }
 
 void MainThreadEventQueue::RequestUnbufferedInputEvents() {
diff --git a/content/renderer/input/main_thread_event_queue.h b/content/renderer/input/main_thread_event_queue.h
index 161eab61..ccb56ead 100644
--- a/content/renderer/input/main_thread_event_queue.h
+++ b/content/renderer/input/main_thread_event_queue.h
@@ -104,7 +104,7 @@
   void SetNeedsLowLatency(bool low_latency);
   void SetNeedsUnbufferedInputForDebugger(bool unbuffered);
 
-  void HasPointerRawMoveEventHandlers(bool has_handlers);
+  void HasPointerRawUpdateEventHandlers(bool has_handlers);
 
   // Request unbuffered input events until next pointerup.
   void RequestUnbufferedInputEvents();
@@ -133,7 +133,7 @@
                                const ui::LatencyInfo& latency,
                                HandledEventCallback handled_callback);
 
-  bool IsRawMoveEvent(
+  bool IsRawUpdateEvent(
       const std::unique_ptr<MainThreadEventQueueTask>& item) const;
   bool ShouldFlushQueue(
       const std::unique_ptr<MainThreadEventQueueTask>& item) const;
@@ -155,7 +155,7 @@
   bool needs_unbuffered_input_for_debugger_;
   bool allow_raf_aligned_input_;
   bool needs_low_latency_until_pointer_up_ = false;
-  bool has_pointerrawmove_handlers_ = false;
+  bool has_pointerrawupdate_handlers_ = false;
 
   // Contains data to be shared between main thread and compositor thread.
   struct SharedState {
diff --git a/content/renderer/input/main_thread_event_queue_unittest.cc b/content/renderer/input/main_thread_event_queue_unittest.cc
index 7f794fe..6dca0c6 100644
--- a/content/renderer/input/main_thread_event_queue_unittest.cc
+++ b/content/renderer/input/main_thread_event_queue_unittest.cc
@@ -1357,7 +1357,7 @@
 }
 
 TEST_F(MainThreadEventQueueTest, PointerEventsCoalescing) {
-  queue_->HasPointerRawMoveEventHandlers(true);
+  queue_->HasPointerRawUpdateEventHandlers(true);
   WebMouseEvent mouse_move = SyntheticWebMouseEventBuilder::Build(
       WebInputEvent::kMouseMove, 10, 10, 0);
   SyntheticWebTouchEvent touch_move;
@@ -1385,7 +1385,7 @@
   EXPECT_FALSE(needs_main_frame_);
 }
 
-TEST_F(MainThreadEventQueueTest, PointerRawMoveEvents) {
+TEST_F(MainThreadEventQueueTest, PointerRawUpdateEvents) {
   WebMouseEvent mouse_move = SyntheticWebMouseEventBuilder::Build(
       WebInputEvent::kMouseMove, 10, 10, 0);
 
@@ -1402,14 +1402,14 @@
   EXPECT_EQ(0u, event_queue().size());
   EXPECT_FALSE(needs_main_frame_);
 
-  queue_->HasPointerRawMoveEventHandlers(true);
+  queue_->HasPointerRawUpdateEventHandlers(true);
   HandleEvent(mouse_move, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
   EXPECT_EQ(2u, event_queue().size());
   RunPendingTasksWithSimulatedRaf();
   EXPECT_EQ(0u, event_queue().size());
   EXPECT_FALSE(needs_main_frame_);
 
-  queue_->HasPointerRawMoveEventHandlers(false);
+  queue_->HasPointerRawUpdateEventHandlers(false);
   SyntheticWebTouchEvent touch_move;
   touch_move.PressPoint(10, 10);
   touch_move.MovePoint(0, 50, 50);
@@ -1419,7 +1419,7 @@
   EXPECT_EQ(0u, event_queue().size());
   EXPECT_FALSE(needs_main_frame_);
 
-  queue_->HasPointerRawMoveEventHandlers(true);
+  queue_->HasPointerRawUpdateEventHandlers(true);
   HandleEvent(touch_move, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
   EXPECT_EQ(2u, event_queue().size());
   RunPendingTasksWithSimulatedRaf();
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 09cbfae..f8eb65e 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -860,8 +860,6 @@
   settings->SetWideViewportQuirkEnabled(prefs.wide_viewport_quirk);
   settings->SetUseWideViewport(prefs.use_wide_viewport);
   settings->SetForceZeroLayoutHeight(prefs.force_zero_layout_height);
-  settings->SetViewportMetaLayoutSizeQuirk(
-      prefs.viewport_meta_layout_size_quirk);
   settings->SetViewportMetaMergeContentQuirk(
       prefs.viewport_meta_merge_content_quirk);
   settings->SetViewportMetaNonUserScalableQuirk(
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index d9077a5..a6183ad 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -3227,9 +3227,9 @@
   return actual;
 }
 
-void RenderWidget::HasPointerRawMoveEventHandlers(bool has_handlers) {
+void RenderWidget::HasPointerRawUpdateEventHandlers(bool has_handlers) {
   if (input_event_queue_)
-    input_event_queue_->HasPointerRawMoveEventHandlers(has_handlers);
+    input_event_queue_->HasPointerRawUpdateEventHandlers(has_handlers);
 }
 
 void RenderWidget::HasTouchEventHandlers(bool has_handlers) {
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 2ff45a00..0681fcb 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -423,7 +423,7 @@
                      const gfx::Point& image_offset) override;
   void SetTouchAction(cc::TouchAction touch_action) override;
   void RequestUnbufferedInputEvents() override;
-  void HasPointerRawMoveEventHandlers(bool has_handlers) override;
+  void HasPointerRawUpdateEventHandlers(bool has_handlers) override;
   void HasTouchEventHandlers(bool has_handlers) override;
   void SetNeedsLowLatencyInput(bool) override;
   void SetNeedsUnbufferedInputForDebugger(bool) override;
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc
index 67c7dcb..33856d1f 100644
--- a/device/vr/android/gvr/gvr_device_provider.cc
+++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -5,6 +5,7 @@
 #include "device/vr/android/gvr/gvr_device_provider.h"
 
 #include "base/android/build_info.h"
+#include "base/android/bundle_utils.h"
 #include "device/vr/android/gvr/gvr_device.h"
 
 namespace device {
@@ -19,14 +20,18 @@
     base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
     base::OnceClosure initialization_complete) {
   // Version check should match MIN_SDK_VERSION in VrCoreVersionChecker.java.
-  // We only expose GvrDevice if we could potentially install VRServices to
-  // support presentation.
+  // We only expose GvrDevice if
+  //  - we could potentially install VRServices to support presentation, and
+  //  - this build is a bundle and, thus, supports installing the VR module.
   if (base::android::BuildInfo::GetInstance()->sdk_int() >=
-      base::android::SDK_VERSION_KITKAT)
+          base::android::SDK_VERSION_LOLLIPOP &&
+      base::android::BundleUtils::IsBundle()) {
     vr_device_ = base::WrapUnique(new GvrDevice());
-  if (vr_device_)
+  }
+  if (vr_device_) {
     add_device_callback.Run(vr_device_->GetId(), vr_device_->GetVRDisplayInfo(),
                             vr_device_->BindXRRuntimePtr());
+  }
   initialized_ = true;
   std::move(initialization_complete).Run();
 }
diff --git a/docs/win_order_files.md b/docs/win_order_files.md
index 893b6cf..49bda3d 100644
--- a/docs/win_order_files.md
+++ b/docs/win_order_files.md
@@ -83,7 +83,7 @@
 
     ```shell
     cd chrome\build\
-    upload_to_google_storage.py -b chromium-browser-clang/orderfiles chrome.x64.orderfile chrome.x86.orderfile chrome_child.x64.orderfile chrome_child.x86.orderfile
+    upload_to_google_storage.py -b chromium-browser-clang/orderfiles -z orderfile chrome.x64.orderfile chrome.x86.orderfile chrome_child.x64.orderfile chrome_child.x86.orderfile
     gsutil.py setacl public-read gs://chromium-browser-clang/orderfiles/*
     ```
 
diff --git a/fuchsia/base/frame_test_util.cc b/fuchsia/base/frame_test_util.cc
index 943e8a7..463c19b 100644
--- a/fuchsia/base/frame_test_util.cc
+++ b/fuchsia/base/frame_test_util.cc
@@ -12,16 +12,16 @@
 namespace cr_fuchsia {
 
 bool LoadUrlAndExpectResponse(
-    fuchsia::web::NavigationControllerPtr* navigation_controller,
+    fuchsia::web::NavigationController* navigation_controller,
     fuchsia::web::LoadUrlParams load_url_params,
     std::string url) {
   DCHECK(navigation_controller);
   base::RunLoop run_loop;
   ResultReceiver<fuchsia::web::NavigationController_LoadUrl_Result> result(
       run_loop.QuitClosure());
-  (*navigation_controller)
-      ->LoadUrl(url, std::move(load_url_params),
-                CallbackToFitFunction(result.GetReceiveCallback()));
+  navigation_controller->LoadUrl(
+      url, std::move(load_url_params),
+      CallbackToFitFunction(result.GetReceiveCallback()));
   run_loop.Run();
   return result->is_response();
 }
diff --git a/fuchsia/base/frame_test_util.h b/fuchsia/base/frame_test_util.h
index ba4962b..d4340f7 100644
--- a/fuchsia/base/frame_test_util.h
+++ b/fuchsia/base/frame_test_util.h
@@ -13,7 +13,7 @@
 // after the load is completed. Returns true if the load was successful, false
 // otherwise.
 bool LoadUrlAndExpectResponse(
-    fuchsia::web::NavigationControllerPtr* navigation_controller,
+    fuchsia::web::NavigationController* navigation_controller,
     fuchsia::web::LoadUrlParams load_url_params,
     std::string url);
 
diff --git a/fuchsia/engine/browser/context_impl_browsertest.cc b/fuchsia/engine/browser/context_impl_browsertest.cc
index 3959112..41d63a8 100644
--- a/fuchsia/engine/browser/context_impl_browsertest.cc
+++ b/fuchsia/engine/browser/context_impl_browsertest.cc
@@ -92,8 +92,9 @@
   fuchsia::web::NavigationControllerPtr navigation_controller;
   frame->GetNavigationController(navigation_controller.NewRequest());
 
-  cr_fuchsia::LoadUrlAndExpectResponse(
-      &navigation_controller, fuchsia::web::LoadUrlParams(), cookie_url.spec());
+  cr_fuchsia::LoadUrlAndExpectResponse(navigation_controller.get(),
+                                       fuchsia::web::LoadUrlParams(),
+                                       cookie_url.spec());
   navigation_listener_.RunUntilUrlEquals(cookie_url);
 
   auto cookies = GetCookies();
@@ -146,7 +147,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
+      controller.get(), fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
   navigation_listener_.RunUntilUrlEquals(GURL(url::kAboutBlankURL));
 
   frame.Unbind();
@@ -161,7 +162,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), cookie_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), cookie_url.spec()));
   navigation_listener_.RunUntilUrlEquals(cookie_url);
 
   auto cookies = GetCookies();
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc
index d75f0a7..234285b1 100644
--- a/fuchsia/engine/browser/frame_impl_browsertest.cc
+++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -143,7 +143,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
+      controller.get(), fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
   navigation_listener_.RunUntilUrlAndTitleEquals(GURL(url::kAboutBlankURL),
                                                  url::kAboutBlankURL);
 }
@@ -155,7 +155,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), kDataUrl));
+      controller.get(), fuchsia::web::LoadUrlParams(), kDataUrl));
   navigation_listener_.RunUntilUrlAndTitleEquals(GURL(kDataUrl), kDataUrl);
 }
 
@@ -175,7 +175,7 @@
   fuchsia::web::NavigationControllerPtr controller;
   frame->GetNavigationController(controller.NewRequest());
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
+      controller.get(), fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
 
   frame.Unbind();
   run_loop.Run();
@@ -229,7 +229,7 @@
   GURL title3(embedded_test_server()->GetURL(kPage3Path));
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title3.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title3.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(title3, kPage3Title);
 }
 
@@ -243,12 +243,12 @@
   GURL title2(embedded_test_server()->GetURL(kPage2Path));
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title1.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
   navigation_listener_.RunUntilUrlTitleBackForwardEquals(title1, kPage1Title,
                                                          false, false);
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title2.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title2.spec()));
   navigation_listener_.RunUntilUrlTitleBackForwardEquals(title2, kPage2Title,
                                                          true, false);
 
@@ -290,7 +290,7 @@
 
   EXPECT_CALL(*this, OnServeHttpRequest(_)).Times(testing::AtLeast(1));
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, kPage1Title);
 
   // Reload with NO_CACHE.
@@ -344,7 +344,7 @@
 
   // Navigate to a page.
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title1.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(title1, kPage1Title);
 
   // Verify that GetVisibleEntry() reflects the new Frame navigation state.
@@ -365,7 +365,7 @@
 
   // Navigate to another page.
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title2.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title2.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(title2, kPage2Title);
 
   // Verify the navigation with GetVisibleEntry().
@@ -386,7 +386,7 @@
 
   // Navigate back to the first page.
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title1.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(title1, kPage1Title);
 
   // Verify the navigation with GetVisibleEntry().
@@ -425,7 +425,7 @@
     EXPECT_CALL(observer, DidStartNavigation(NavigationHandleUrlEquals(title1)))
         .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
     EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-        &controller, fuchsia::web::LoadUrlParams(), title1.spec()));
+        controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
     run_loop.Run();
   }
 
@@ -434,7 +434,7 @@
     EXPECT_CALL(observer, DidStartNavigation(NavigationHandleUrlEquals(title2)))
         .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
     EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-        &controller, fuchsia::web::LoadUrlParams(), title2.spec()));
+        controller.get(), fuchsia::web::LoadUrlParams(), title2.spec()));
     run_loop.Run();
   }
 }
@@ -457,7 +457,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlEquals(url);
 }
 
@@ -490,7 +490,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, "clobber");
 }
 
@@ -521,7 +521,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, "hello there");
 }
 
@@ -555,7 +555,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, "foo");
 }
 
@@ -570,7 +570,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, kPage1Title);
 }
 
@@ -586,7 +586,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title1.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(title1, kPage1Title);
 
   frame->ExecuteJavaScriptNoResult(
@@ -616,7 +616,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, "hello");
 }
 
@@ -638,7 +638,7 @@
   // Expect that the original HTML title is used, because we didn't inject a
   // script with a replacement title.
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(
       url, "Welcome to Stan the Offline Dino's Homepage");
 }
@@ -660,18 +660,18 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, "hello");
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
+      controller.get(), fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
   navigation_listener_.RunUntilUrlEquals(GURL(url::kAboutBlankURL));
 
   // Test script injection using a different origin ("localhost"), which should
   // still be picked up by the wildcard.
   GURL alt_url = embedded_test_server()->GetURL("localhost", kDynamicTitlePath);
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), alt_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), alt_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(alt_url, "hello");
 }
 
@@ -700,7 +700,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, "hello there");
 }
 
@@ -723,7 +723,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, "hello");
 
   frame->AddBeforeLoadJavaScript(
@@ -735,12 +735,12 @@
 
   // Navigate away to clean the slate.
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
+      controller.get(), fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
   navigation_listener_.RunUntilUrlEquals(GURL(url::kAboutBlankURL));
 
   // Navigate back and see if both scripts are working.
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, "hello there");
 }
 
@@ -754,7 +754,7 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(url, kPage1Title);
 
   base::RunLoop run_loop;
@@ -788,7 +788,7 @@
               DidStartNavigation(NavigationHandleUrlEquals(title1)));
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title1.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(title1, kPage1Title);
 
   // Disconnect the listener & spin the runloop to propagate the disconnection
@@ -801,7 +801,7 @@
               DidStartNavigation(NavigationHandleUrlEquals(title2)))
       .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title2.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title2.spec()));
   run_loop.Run();
 }
 
@@ -826,7 +826,7 @@
       base::Unretained(&captured_ack_cb)));
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), title1.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(title1, kPage1Title);
   EXPECT_TRUE(captured_ack_cb);
 
@@ -842,7 +842,7 @@
                 DidStartNavigation(NavigationHandleUrlEquals(title2)))
         .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
     EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-        &controller, fuchsia::web::LoadUrlParams(), title2.spec()));
+        controller.get(), fuchsia::web::LoadUrlParams(), title2.spec()));
     run_loop.Run();
   }
 
@@ -855,7 +855,7 @@
                 DidStartNavigation(NavigationHandleUrlEquals(title1)))
         .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
     EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-        &controller, fuchsia::web::LoadUrlParams(), title1.spec()));
+        controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
     run_loop.Run();
   }
 
@@ -926,7 +926,8 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), post_message_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(),
+      post_message_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(post_message_url,
                                                  "postmessage");
 
@@ -956,7 +957,8 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), post_message_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(),
+      post_message_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(post_message_url,
                                                  "messageport");
 
@@ -1016,7 +1018,8 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), post_message_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(),
+      post_message_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(post_message_url,
                                                  "messageport");
 
@@ -1053,7 +1056,7 @@
     message_port.set_error_handler(
         [&run_loop](zx_status_t) { run_loop.Quit(); });
     EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-        &controller, fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
+        controller.get(), fuchsia::web::LoadUrlParams(), url::kAboutBlankURL));
     run_loop.Run();
   }
 }
@@ -1071,7 +1074,8 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), post_message_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(),
+      post_message_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(post_message_url,
                                                  "messageport");
 
@@ -1173,7 +1177,8 @@
   frame->GetNavigationController(controller.NewRequest());
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), post_message_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(),
+      post_message_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(post_message_url,
                                                  "messageport");
 
@@ -1254,7 +1259,7 @@
   // Verify that the Frame can navigate, prior to the View being created.
   const GURL page1_url(embedded_test_server()->GetURL(kPage1Path));
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), page1_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), page1_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(page1_url, kPage1Title);
 
   // Request a View from the Frame, and pump the loop to process the request.
@@ -1269,7 +1274,7 @@
   // Verify that the Frame still works, by navigating to Page #2.
   const GURL page2_url(embedded_test_server()->GetURL(kPage2Path));
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), page2_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), page2_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(page2_url, kPage2Title);
 
   // Create new View tokens and request a new view.
@@ -1283,7 +1288,7 @@
 
   // Verify that the Frame still works, by navigating back to Page #1.
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), page1_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), page1_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(page1_url, kPage1Title);
 }
 
@@ -1344,7 +1349,7 @@
   load_url_params.set_headers({header1, header2});
 
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, std::move(load_url_params), page_url.spec()));
+      controller.get(), std::move(load_url_params), page_url.spec()));
   navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
 
   // At this point, the page should be loaded, the server should have received
diff --git a/fuchsia/runners/cast/named_message_port_connector_browsertest.cc b/fuchsia/runners/cast/named_message_port_connector_browsertest.cc
index b0ad7e9..2c60735 100644
--- a/fuchsia/runners/cast/named_message_port_connector_browsertest.cc
+++ b/fuchsia/runners/cast/named_message_port_connector_browsertest.cc
@@ -85,7 +85,7 @@
                           base::Unretained(&message_port)),
       frame_.get());
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), test_url.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), test_url.spec()));
   navigation_listener_.RunUntilUrlEquals(test_url);
 
   receive_port_run_loop.Run();
@@ -122,7 +122,7 @@
       run_loop.Quit();
     });
     EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-        &controller, fuchsia::web::LoadUrlParams(), "about:blank"));
+        controller.get(), fuchsia::web::LoadUrlParams(), "about:blank"));
     run_loop.Run();
   }
 
diff --git a/fuchsia/runners/cast/queryable_data_bindings_browsertest.cc b/fuchsia/runners/cast/queryable_data_bindings_browsertest.cc
index 955264a..edefa66 100644
--- a/fuchsia/runners/cast/queryable_data_bindings_browsertest.cc
+++ b/fuchsia/runners/cast/queryable_data_bindings_browsertest.cc
@@ -147,7 +147,7 @@
   frame_->GetNavigationController(controller.NewRequest());
   frame_->SetJavaScriptLogLevel(fuchsia::web::ConsoleLogLevel::INFO);
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), test_url_.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), test_url_.spec()));
   navigation_listener_.RunUntilUrlEquals(test_url_);
 
   EXPECT_EQ(CallQueryPlatformValue("string"), "\"foo\"");
@@ -166,7 +166,7 @@
   frame_->GetNavigationController(controller.NewRequest());
   frame_->SetJavaScriptLogLevel(fuchsia::web::ConsoleLogLevel::INFO);
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), test_url_.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), test_url_.spec()));
   navigation_listener_.RunUntilUrlEquals(test_url_);
 
   EXPECT_EQ(CallQueryPlatformValue("string"), "null");
@@ -186,7 +186,7 @@
   frame_->GetNavigationController(controller.NewRequest());
   frame_->SetJavaScriptLogLevel(fuchsia::web::ConsoleLogLevel::INFO);
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), test_url_.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), test_url_.spec()));
   navigation_listener_.RunUntilUrlEquals(test_url_);
 
   SynchronizeWithPage();
@@ -224,7 +224,7 @@
   frame_->GetNavigationController(controller.NewRequest());
   frame_->SetJavaScriptLogLevel(fuchsia::web::ConsoleLogLevel::INFO);
   EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
-      &controller, fuchsia::web::LoadUrlParams(), test_url_.spec()));
+      controller.get(), fuchsia::web::LoadUrlParams(), test_url_.spec()));
   navigation_listener_.RunUntilUrlEquals(test_url_);
 
   SynchronizeWithPage();
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 1c5a29e6..28ebdbe 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -774,6 +774,8 @@
           .fNumSemaphores = end_semaphores_.size(),
           .fSignalSemaphores = end_semaphores_.data(),
       };
+      CreateCleanupCallbackForSkiaFlush(
+          shared_context_state_->vk_context_provider(), &flush_info);
       auto result = sk_surface_->flush(
           SkSurface::BackendSurfaceAccess::kPresent, flush_info);
       DCHECK(result == GrSemaphoresSubmitted::kYes || end_semaphores_.empty());
@@ -2207,6 +2209,8 @@
         .fNumSemaphores = end_semaphores_.size(),
         .fSignalSemaphores = end_semaphores_.data(),
     };
+    CreateCleanupCallbackForSkiaFlush(
+        shared_context_state_->vk_context_provider(), &flush_info);
     auto result = sk_surface_->flush(SkSurface::BackendSurfaceAccess::kPresent,
                                      flush_info);
     DCHECK(result == GrSemaphoresSubmitted::kYes || end_semaphores_.empty());
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc
index e53cf04..58dfb8e7 100644
--- a/gpu/command_buffer/service/skia_utils.cc
+++ b/gpu/command_buffer/service/skia_utils.cc
@@ -5,6 +5,7 @@
 #include "gpu/command_buffer/service/skia_utils.h"
 
 #include "base/logging.h"
+#include "components/viz/common/gpu/vulkan_context_provider.h"
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/gl/GrGLTypes.h"
@@ -13,6 +14,11 @@
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_version_info.h"
 
+#if BUILDFLAG(ENABLE_VULKAN)
+#include "gpu/vulkan/vulkan_device_queue.h"
+#include "gpu/vulkan/vulkan_fence_helper.h"
+#endif
+
 namespace gpu {
 
 bool GetGrBackendTexture(const gl::GLVersionInfo* version_info,
@@ -37,4 +43,19 @@
   return true;
 }
 
+void CreateCleanupCallbackForSkiaFlush(
+    viz::VulkanContextProvider* context_provider,
+    GrFlushInfo* flush_info) {
+  DCHECK(!flush_info->fFinishedProc);
+  DCHECK(!flush_info->fFinishedContext);
+#if BUILDFLAG(ENABLE_VULKAN)
+  if (context_provider) {
+    context_provider->GetDeviceQueue()
+        ->GetFenceHelper()
+        ->EnqueueExternalCallback(&flush_info->fFinishedProc,
+                                  &flush_info->fFinishedContext);
+  }
+#endif
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/skia_utils.h b/gpu/command_buffer/service/skia_utils.h
index 1663146..5f47e70 100644
--- a/gpu/command_buffer/service/skia_utils.h
+++ b/gpu/command_buffer/service/skia_utils.h
@@ -7,6 +7,8 @@
 
 #include "components/viz/common/resources/resource_format.h"
 #include "gpu/gpu_gles2_export.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
 
 // Forwardly declare a few GL types to avoid including GL header files.
 typedef int GLint;
@@ -23,6 +25,10 @@
 struct GLVersionInfo;
 }  // namespace gl
 
+namespace viz {
+class VulkanContextProvider;
+}  // namespace viz
+
 namespace gpu {
 // Creates a GrBackendTexture from a service ID. Skia does not take ownership.
 // Returns true on success.
@@ -33,6 +39,12 @@
                                           viz::ResourceFormat resource_format,
                                           GrBackendTexture* gr_texture);
 
+// Helper which associates cleanup callbacks with a Skia GrFlushInfo's callback.
+// Is a no-op if |context_provider| is null.
+GPU_GLES2_EXPORT void CreateCleanupCallbackForSkiaFlush(
+    viz::VulkanContextProvider* context_provider,
+    GrFlushInfo* flush_info);
+
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_SERVICE_SKIA_UTILS_H_
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 1d216dac..3af660fa 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -4024,7 +4024,8 @@
       level_info->format == GL_DEPTH_STENCIL ||
       level_info->format == GL_LUMINANCE_ALPHA ||
       level_info->format == GL_LUMINANCE || level_info->format == GL_ALPHA ||
-      level_info->format == GL_BGRA_EXT || level_info->format == GL_SRGB_EXT;
+      level_info->format == GL_BGRA_EXT || level_info->format == GL_SRGB_EXT ||
+      level_info->format == GL_SRGB_ALPHA_EXT;
   if (normalized) {
     // All normalized texture formats are sampled as float.
     return category == SAMPLER_FLOAT;
diff --git a/gpu/vulkan/vulkan_fence_helper.cc b/gpu/vulkan/vulkan_fence_helper.cc
index 3bbafcf..cf8f62e 100644
--- a/gpu/vulkan/vulkan_fence_helper.cc
+++ b/gpu/vulkan/vulkan_fence_helper.cc
@@ -19,7 +19,7 @@
     const FenceHandle& other) = default;
 
 VulkanFenceHelper::VulkanFenceHelper(VulkanDeviceQueue* device_queue)
-    : device_queue_(device_queue) {}
+    : device_queue_(device_queue), weak_factory_(this) {}
 
 VulkanFenceHelper::~VulkanFenceHelper() {
   DCHECK(tasks_pending_fence_.empty());
@@ -79,18 +79,26 @@
   VkDevice device = device_queue_->GetVulkanDevice();
 
   // Iterate over our pending cleanup fences / tasks, advancing
-  // |current_generation_| as far as possible. This assumes that fences pass in
-  // order, which isn't a hard API guarantee, but should be close enough /
-  // efficient enough for the purpose or processing cleanup tasks.
+  // |current_generation_| as far as possible.
   for (const auto& tasks_for_fence : cleanup_tasks_) {
-    VkResult result = vkGetFenceStatus(device, tasks_for_fence.handle.fence_);
+    // If we're already ahead of this task (callback modified |generation_id_|),
+    // continue.
+    if (tasks_for_fence.generation_id <= current_generation_)
+      continue;
+
+    // Callback based tasks have no actual fence to wait on, keep checking
+    // future fences, as a callback may be delayed.
+    if (tasks_for_fence.UsingCallback())
+      continue;
+
+    VkResult result = vkGetFenceStatus(device, tasks_for_fence.fence);
     if (result == VK_NOT_READY)
       break;
     if (result != VK_SUCCESS) {
       PerformImmediateCleanup();
       return;
     }
-    current_generation_ = tasks_for_fence.handle.generation_id_;
+    current_generation_ = tasks_for_fence.generation_id;
   }
 
   // Runs any cleanup tasks for generations that have passed. Create a temporary
@@ -98,11 +106,12 @@
   std::vector<CleanupTask> tasks_to_run;
   while (!cleanup_tasks_.empty()) {
     TasksForFence& tasks_for_fence = cleanup_tasks_.front();
-    if (tasks_for_fence.handle.generation_id_ > current_generation_)
+    if (tasks_for_fence.generation_id > current_generation_)
       break;
-    DCHECK_EQ(vkGetFenceStatus(device, tasks_for_fence.handle.fence_),
-              VK_SUCCESS);
-    vkDestroyFence(device, tasks_for_fence.handle.fence_, nullptr);
+    if (tasks_for_fence.fence != VK_NULL_HANDLE) {
+      DCHECK_EQ(vkGetFenceStatus(device, tasks_for_fence.fence), VK_SUCCESS);
+      vkDestroyFence(device, tasks_for_fence.fence, nullptr);
+    }
     tasks_to_run.insert(tasks_to_run.end(),
                         std::make_move_iterator(tasks_for_fence.tasks.begin()),
                         std::make_move_iterator(tasks_for_fence.tasks.end()));
@@ -133,6 +142,42 @@
   return EnqueueFence(fence);
 }
 
+void VulkanFenceHelper::EnqueueExternalCallback(
+    ExternalCallback* callback,
+    ExternalCallbackContext* context) {
+  // No need to do callback tracking if there are no cleanup tasks to run.
+  if (tasks_pending_fence_.empty())
+    return;
+
+  // Get a generaiton ID for this callback and associate existing cleanup
+  // tasks.
+  uint64_t generation_id = next_generation_++;
+  cleanup_tasks_.emplace_back(generation_id, std::move(tasks_pending_fence_));
+  tasks_pending_fence_ = std::vector<CleanupTask>();
+
+  // Populate |callback| and |context|.
+  struct ExternalCallbackData {
+    base::WeakPtr<VulkanFenceHelper> fence_helper;
+    uint64_t generation_id;
+  };
+  // As we must pass a void* which may outlive this class, use "new" here. We
+  // will delete |context| in the callback below.
+  *context =
+      new ExternalCallbackData{weak_factory_.GetWeakPtr(), generation_id};
+  *callback = [](ExternalCallbackContext context) {
+    auto* callback_data = static_cast<ExternalCallbackData*>(context);
+    if (auto* fence_helper = callback_data->fence_helper.get()) {
+      // If |current_generation_| is ahead of the callback's |generation_id|,
+      // the callback came late. Ignore it.
+      if (callback_data->generation_id > fence_helper->current_generation_) {
+        fence_helper->current_generation_ = callback_data->generation_id;
+        fence_helper->ProcessCleanupTasks();
+      }
+    }
+    delete callback_data;
+  };
+}
+
 void VulkanFenceHelper::EnqueueSemaphoreCleanupForSubmittedWork(
     VkSemaphore semaphore) {
   if (semaphore == VK_NULL_HANDLE)
@@ -175,7 +220,14 @@
 }
 
 void VulkanFenceHelper::PerformImmediateCleanup() {
-  // Rather than caring about fences, just wait for queue idle if possible.
+  if (cleanup_tasks_.empty() && tasks_pending_fence_.empty())
+    return;
+
+  // We want to run all tasks immediately, so just use vkQueueWaitIdle which
+  // ensures that all fences have passed.
+  // Even if exclusively using callbacks, the callbacks use WeakPtr and will
+  // not keep this class alive, so it's important to wait / run all cleanup
+  // immediately.
   VkResult result = vkQueueWaitIdle(device_queue_->GetVulkanQueue());
   // Wait can only fail for three reasons - device loss, host OOM, device OOM.
   // If we hit an OOM, treat this as a crash. There isn't a great way to
@@ -190,8 +242,8 @@
   std::vector<CleanupTask> tasks_to_run;
   while (!cleanup_tasks_.empty()) {
     auto& tasks_for_fence = cleanup_tasks_.front();
-    vkDestroyFence(device_queue_->GetVulkanDevice(),
-                   tasks_for_fence.handle.fence_, nullptr);
+    vkDestroyFence(device_queue_->GetVulkanDevice(), tasks_for_fence.fence,
+                   nullptr);
     tasks_to_run.insert(tasks_to_run.end(),
                         std::make_move_iterator(tasks_for_fence.tasks.begin()),
                         std::make_move_iterator(tasks_for_fence.tasks.end()));
@@ -207,12 +259,14 @@
 
 VulkanFenceHelper::TasksForFence::TasksForFence(FenceHandle handle,
                                                 std::vector<CleanupTask> tasks)
-    : handle(handle), tasks(std::move(tasks)) {}
+    : fence(handle.fence_),
+      generation_id(handle.generation_id_),
+      tasks(std::move(tasks)) {}
+VulkanFenceHelper::TasksForFence::TasksForFence(uint64_t generation_id,
+                                                std::vector<CleanupTask> tasks)
+    : generation_id(generation_id), tasks(std::move(tasks)) {}
 VulkanFenceHelper::TasksForFence::~TasksForFence() = default;
 VulkanFenceHelper::TasksForFence::TasksForFence(TasksForFence&& other) =
     default;
-VulkanFenceHelper::TasksForFence&
-VulkanFenceHelper::TasksForFence::TasksForFence::operator=(
-    TasksForFence&& other) = default;
 
 }  // namespace gpu
diff --git a/gpu/vulkan/vulkan_fence_helper.h b/gpu/vulkan/vulkan_fence_helper.h
index 36a7416..feef902 100644
--- a/gpu/vulkan/vulkan_fence_helper.h
+++ b/gpu/vulkan/vulkan_fence_helper.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/containers/circular_deque.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "gpu/vulkan/vulkan_export.h"
 
 namespace gpu {
@@ -50,10 +51,9 @@
   // In typical cases, callers will call GetFence to generate/reuse a fence,
   // submit this fence, then call EnqueueFence to register it with this system.
   //
-  // In cases where fences are not being generated by Chrome (or in cases where
-  // we can't use this helper, such as Skia), consumers should ensure that
-  // GenerateCleanupFence is called once per frame to allow cleanup tasks to be
-  // processed.
+  // In cases where fences are not being generated by Chrome, consumers should
+  // ensure that GenerateCleanupFence is called once per frame to allow cleanup
+  // tasks to be processed.
   //
   // Creates or recycles a fence.
   VkResult GetFence(VkFence* fence);
@@ -69,6 +69,19 @@
   // TODO(ericrk): We should avoid this in all cases if possible.
   FenceHandle GenerateCleanupFence();
 
+  // Helper for associating cleanup tasks with a callback which will be run
+  // after a future fence submission. Used in cases where an external
+  // component (Skia) is submitting / waiting on a fence and cannot share that
+  // fence with this class.
+  // Note: It is important that no new cleanup tasks or fences are inserted
+  // between this call and the submission of the fence which will eventually
+  // trigger this callback. Doing so could cause the callbacks associated
+  // with this call to run out of order / incorrectly.
+  using ExternalCallbackContext = void*;
+  using ExternalCallback = void (*)(ExternalCallbackContext);
+  void EnqueueExternalCallback(ExternalCallback* callback,
+                               ExternalCallbackContext* context);
+
   // Helper functions which allow clients to wait for or check the statusof a
   // fence submitted with EnqueueFence.
   //
@@ -107,16 +120,25 @@
   uint64_t current_generation_ = 0;
 
   struct TasksForFence {
+    // Constructor when tasks associated with a fence.
     TasksForFence(FenceHandle handle, std::vector<CleanupTask> tasks);
+    // Constructor when tasks associated with Skia callback.
+    TasksForFence(uint64_t generation_id, std::vector<CleanupTask> tasks);
     ~TasksForFence();
     TasksForFence(TasksForFence&& other);
     TasksForFence& operator=(TasksForFence&& other);
 
-    FenceHandle handle;
+    bool UsingCallback() const { return fence == VK_NULL_HANDLE; }
+
+    const VkFence fence = VK_NULL_HANDLE;
+    const uint64_t generation_id = 0;
+
     std::vector<CleanupTask> tasks;
   };
   base::circular_deque<TasksForFence> cleanup_tasks_;
 
+  base::WeakPtrFactory<VulkanFenceHelper> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(VulkanFenceHelper);
 };
 
diff --git a/gpu/vulkan/vulkan_fence_helper_unittest.cc b/gpu/vulkan/vulkan_fence_helper_unittest.cc
index 2b68af3..9efcca1 100644
--- a/gpu/vulkan/vulkan_fence_helper_unittest.cc
+++ b/gpu/vulkan/vulkan_fence_helper_unittest.cc
@@ -93,4 +93,100 @@
   fence_helper->Wait(fence_handle, UINT64_MAX);
   EXPECT_EQ(10u, cleanups_run);
 }
+
+TEST_F(VulkanFenceHelperTest, TestSkiaCallback) {
+  VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
+  bool cleanup_run = false;
+  fence_helper->EnqueueCleanupTaskForSubmittedWork(
+      base::BindOnce([](bool* cleanup_run, VulkanDeviceQueue* device_queue,
+                        bool is_lost) { *cleanup_run = true; },
+                     &cleanup_run));
+  VulkanFenceHelper::ExternalCallback callback;
+  VulkanFenceHelper::ExternalCallbackContext context;
+  fence_helper->EnqueueExternalCallback(&callback, &context);
+  EXPECT_FALSE(cleanup_run);
+  callback(context);
+  EXPECT_TRUE(cleanup_run);
+}
+
+TEST_F(VulkanFenceHelperTest, SkiaCallbackBeforeFences) {
+  VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
+  uint32_t cleanups_run = 0;
+  auto increment_cleanups_callback =
+      [](uint32_t expected_index, uint32_t* cleanups_run,
+         VulkanDeviceQueue* device_queue, bool is_lost) {
+        EXPECT_EQ(expected_index, *cleanups_run);
+        *cleanups_run = *cleanups_run + 1;
+      };
+
+  // Enqueue 5 callbacks.
+  for (int i = 0; i < 5; i++) {
+    fence_helper->EnqueueCleanupTaskForSubmittedWork(
+        base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
+  }
+
+  // The first 5 callbacks use a callback to trigger.
+  VulkanFenceHelper::ExternalCallback callback;
+  VulkanFenceHelper::ExternalCallbackContext context;
+  fence_helper->EnqueueExternalCallback(&callback, &context);
+
+  // Enqueue 5 more callbacks.
+  for (int i = 5; i < 10; i++) {
+    fence_helper->EnqueueCleanupTaskForSubmittedWork(
+        base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
+  }
+
+  // Generate a cleanup fence for the next 5 callbacks.
+  VulkanFenceHelper::FenceHandle fence_handle =
+      fence_helper->GenerateCleanupFence();
+  EXPECT_TRUE(fence_handle.is_valid());
+
+  // After waiting for the second fence, all callbacks should have run, Skia
+  // callbacks can be delayed, so we check future fences as well.
+  EXPECT_TRUE(fence_helper->Wait(fence_handle, UINT64_MAX));
+  EXPECT_EQ(10u, cleanups_run);
+
+  // Running the callback now should be a no-op.
+  callback(context);
+  EXPECT_EQ(10u, cleanups_run);
+}
+
+TEST_F(VulkanFenceHelperTest, SkiaCallbackAfterFences) {
+  VulkanFenceHelper* fence_helper = GetDeviceQueue()->GetFenceHelper();
+  uint32_t cleanups_run = 0;
+  auto increment_cleanups_callback =
+      [](uint32_t expected_index, uint32_t* cleanups_run,
+         VulkanDeviceQueue* device_queue, bool is_lost) {
+        EXPECT_EQ(expected_index, *cleanups_run);
+        *cleanups_run = *cleanups_run + 1;
+      };
+
+  // Enqueue 5 callbacks.
+  for (int i = 0; i < 5; i++) {
+    fence_helper->EnqueueCleanupTaskForSubmittedWork(
+        base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
+  }
+
+  // The first 5 callbacks use a fence to trigger.
+  VulkanFenceHelper::FenceHandle fence_handle =
+      fence_helper->GenerateCleanupFence();
+  EXPECT_TRUE(fence_handle.is_valid());
+
+  // Enqueue 5 more callbacks.
+  for (int i = 5; i < 10; i++) {
+    fence_helper->EnqueueCleanupTaskForSubmittedWork(
+        base::BindOnce(increment_cleanups_callback, i, &cleanups_run));
+  }
+
+  // The next 5 callbacks use a callback to trigger.
+  VulkanFenceHelper::ExternalCallback callback;
+  VulkanFenceHelper::ExternalCallbackContext context;
+  fence_helper->EnqueueExternalCallback(&callback, &context);
+
+  // Signal the fence, all callbacks should run.
+  // Generate a cleanup fence for the next 5 callbacks.
+  callback(context);
+  EXPECT_EQ(10u, cleanups_run);
+}
+
 }  // namespace gpu
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index 9b75927..3bb7e49 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -24,7 +24,7 @@
 
 group("headless_lib") {
   deps = [
-    ":headless",
+    ":headless_non_renderer",
   ]
 }
 
@@ -227,7 +227,7 @@
 }
 
 inspector_protocol_generate("protocol_sources") {
-  visibility = [ "//headless" ]
+  visibility = [ "//headless:headless_shared_sources" ]
   deps = [
     "//third_party/blink/renderer/core/inspector:protocol_version",
   ]
@@ -262,10 +262,75 @@
   ]
 }
 
-jumbo_component("headless") {
+# Code needed in both processes. Only exposed through |headless| and
+# |headless_non_renderer| components.
+jumbo_source_set("headless_shared_sources") {
+  visibility = [
+    "//headless:headless_non_renderer",
+    "//headless:headless",
+  ]
+
   sources = [
     "app/headless_shell_switches.cc",
     "app/headless_shell_switches.h",
+    "lib/headless_content_client.cc",
+    "lib/headless_content_client.h",
+    "public/headless_browser.cc",
+    "public/headless_browser.h",
+    "public/headless_export.h",
+    "public/internal/headless_devtools_client_impl.h",
+    "public/internal/message_dispatcher.h",
+    "public/internal/value_conversions.h",
+    "public/util/error_reporter.cc",
+    "public/util/error_reporter.h",
+    "public/util/user_agent.cc",
+    "public/util/user_agent.h",
+  ]
+
+  sources += generated_devtools_api
+  sources += get_target_outputs(":protocol_sources")
+
+  if (!is_fuchsia) {
+    sources += [
+      "lib/headless_crash_reporter_client.cc",
+      "lib/headless_crash_reporter_client.h",
+    ]
+  }
+
+  deps = [
+    ":gen_devtools_client_api",
+    ":protocol_sources",
+    "//base:base_static",
+    "//content/public/common",
+    "//content/public/common:service_names",
+    "//ui/base",
+    "//url",
+  ]
+
+  if (!is_fuchsia) {
+    deps += [ "//components/crash/content/browser" ]
+  }
+  if (is_win) {
+    deps += [ "//components/crash/content/app:crash_export_thunks" ]
+  }
+
+  if (is_linux && !is_chromeos) {
+    deps += [ "//components/os_crypt" ]
+  }
+
+  configs += [ ":inside_headless_component" ]
+}
+
+# Code that is needed in a renderer process.
+jumbo_component("headless") {
+  deps = [
+    ":headless_shared_sources",
+  ]
+}
+
+# Code that is not needed in a renderer process.
+jumbo_component("headless_non_renderer") {
+  sources = [
     "lib/browser/headless_browser_context_impl.cc",
     "lib/browser/headless_browser_context_impl.h",
     "lib/browser/headless_browser_context_options.cc",
@@ -308,35 +373,13 @@
     "lib/browser/protocol/page_handler.h",
     "lib/browser/protocol/target_handler.cc",
     "lib/browser/protocol/target_handler.h",
-    "lib/headless_content_client.cc",
-    "lib/headless_content_client.h",
-    "public/headless_browser.cc",
-    "public/headless_browser.h",
     "public/headless_browser_context.h",
     "public/headless_devtools_channel.h",
     "public/headless_devtools_client.h",
     "public/headless_devtools_target.h",
-    "public/headless_export.h",
     "public/headless_web_contents.h",
-    "public/internal/headless_devtools_client_impl.h",
-    "public/internal/message_dispatcher.h",
-    "public/internal/value_conversions.h",
-    "public/util/error_reporter.cc",
-    "public/util/error_reporter.h",
-    "public/util/user_agent.cc",
-    "public/util/user_agent.h",
   ]
 
-  if (!is_fuchsia) {
-    sources += [
-      "lib/headless_crash_reporter_client.cc",
-      "lib/headless_crash_reporter_client.h",
-    ]
-  }
-
-  sources += generated_devtools_api
-  sources += get_target_outputs(":protocol_sources")
-
   if (use_aura) {
     sources += [
       "lib/browser/headless_browser_impl_aura.cc",
@@ -372,8 +415,7 @@
   }
 
   deps = [
-    ":gen_devtools_client_api",
-    ":protocol_sources",
+    ":headless_shared_sources",
     ":version_header",
     "//base:base_static",
     "//components/cookie_config",
@@ -389,10 +431,6 @@
     "//url",
   ]
 
-  if (is_linux && !is_chromeos) {
-    deps += [ "//components/os_crypt" ]
-  }
-
   if (enable_basic_printing) {
     deps += [ "//components/printing/browser" ]
   }
@@ -534,7 +572,7 @@
   # component.
   group("headless_renderer") {
     deps = [
-      ":headless",
+      ":headless_non_renderer",
     ]
   }
 }
@@ -567,7 +605,7 @@
   }
 
   deps = [
-    ":headless_renderer",
+    ":headless_shell_lib",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
     "//components/security_state/content",
@@ -719,7 +757,7 @@
   }
 
   deps = [
-    ":headless_renderer",
+    ":headless_shell_lib",
     "//base",
     "//components/security_state/content",
     "//components/services/pdf_compositor/public/cpp:manifest",
@@ -732,10 +770,7 @@
   ]
 
   if (!is_fuchsia) {
-    deps += [
-      "//components/crash/content/app:test_support",
-      "//components/crash/content/browser",
-    ]
+    deps += [ "//components/crash/content/browser" ]
   }
 
   if (is_linux) {
@@ -774,7 +809,7 @@
       "public/headless_shell.h",
     ]
     deps = [
-      ":headless",
+      ":headless_non_renderer",
       "//components/services/pdf_compositor/public/cpp:manifest",
       "//components/services/pdf_compositor/public/interfaces",
       "//content:sandbox_helper_win",
@@ -871,6 +906,10 @@
     "//base",
   ]
 
+  if (!is_component_build) {
+    public_deps += [ ":headless_non_renderer" ]
+  }
+
   if (!is_fuchsia) {
     deps += [ "//components/crash/content/browser" ]
   }
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index a70e178..c29b23e 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -32,7 +32,7 @@
 #include "content/public/common/content_switches.h"
 #include "headless/app/headless_shell.h"
 #include "headless/app/headless_shell_switches.h"
-#include "headless/lib/browser/headless_devtools.h"
+#include "headless/lib/headless_content_main_delegate.h"
 #include "headless/public/headless_devtools_target.h"
 #include "net/base/filename_util.h"
 #include "net/base/host_port_pair.h"
@@ -52,6 +52,11 @@
 #include "sandbox/win/src/sandbox_types.h"
 #endif
 
+#if !defined(CHROME_MULTIPLE_DLL_CHILD)
+#include "headless/lib/browser/headless_browser_impl.h"
+#include "headless/lib/browser/headless_devtools.h"
+#endif
+
 namespace headless {
 
 namespace {
@@ -137,6 +142,34 @@
 
 #endif
 
+int RunContentMain(
+    HeadlessBrowser::Options options,
+    base::OnceCallback<void(HeadlessBrowser*)> on_browser_start_callback) {
+  content::ContentMainParams params(nullptr);
+#if defined(OS_WIN)
+  // Sandbox info has to be set and initialized.
+  CHECK(options.sandbox_info);
+  params.instance = options.instance;
+  params.sandbox_info = std::move(options.sandbox_info);
+#elif !defined(OS_ANDROID)
+  params.argc = options.argc;
+  params.argv = options.argv;
+#endif
+
+  // TODO(skyostil): Implement custom message pumps.
+  DCHECK(!options.message_pump);
+
+#if !defined(CHROME_MULTIPLE_DLL_CHILD)
+  std::unique_ptr<HeadlessBrowserImpl> browser(new HeadlessBrowserImpl(
+      std::move(on_browser_start_callback), std::move(options)));
+  HeadlessContentMainDelegate delegate(std::move(browser));
+#else
+  HeadlessContentMainDelegate delegate(std::move(options));
+#endif
+  params.delegate = &delegate;
+  return content::ContentMain(params);
+}
+
 }  // namespace
 
 HeadlessShell::HeadlessShell()
@@ -776,4 +809,50 @@
 #endif
 }
 
+#if defined(OS_WIN)
+void RunChildProcessIfNeeded(HINSTANCE instance,
+                             sandbox::SandboxInterfaceInfo* sandbox_info) {
+  base::CommandLine::Init(0, nullptr);
+  HeadlessBrowser::Options::Builder builder(0, nullptr);
+  builder.SetInstance(instance);
+  builder.SetSandboxInfo(std::move(sandbox_info));
+#else
+void RunChildProcessIfNeeded(int argc, const char** argv) {
+  base::CommandLine::Init(argc, argv);
+  HeadlessBrowser::Options::Builder builder(argc, argv);
+#endif  // defined(OS_WIN)
+  const base::CommandLine& command_line(
+      *base::CommandLine::ForCurrentProcess());
+
+  if (!command_line.HasSwitch(::switches::kProcessType))
+    return;
+
+  if (command_line.HasSwitch(switches::kUserAgent)) {
+    std::string ua = command_line.GetSwitchValueASCII(switches::kUserAgent);
+    if (net::HttpUtil::IsValidHeaderValue(ua))
+      builder.SetUserAgent(ua);
+  }
+
+  exit(RunContentMain(builder.Build(),
+                      base::OnceCallback<void(HeadlessBrowser*)>()));
+}
+
+int HeadlessBrowserMain(
+    HeadlessBrowser::Options options,
+    base::OnceCallback<void(HeadlessBrowser*)> on_browser_start_callback) {
+  DCHECK(!on_browser_start_callback.is_null());
+#if DCHECK_IS_ON()
+  // The browser can only be initialized once.
+  static bool browser_was_initialized;
+  DCHECK(!browser_was_initialized);
+  browser_was_initialized = true;
+
+  // Child processes should not end up here.
+  DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+      ::switches::kProcessType));
+#endif
+  return RunContentMain(std::move(options),
+                        std::move(on_browser_start_callback));
+}
+
 }  // namespace headless
diff --git a/headless/lib/browser/headless_browser_impl.cc b/headless/lib/browser/headless_browser_impl.cc
index 9395614..8759337 100644
--- a/headless/lib/browser/headless_browser_impl.cc
+++ b/headless/lib/browser/headless_browser_impl.cc
@@ -34,36 +34,6 @@
 #endif
 
 namespace headless {
-namespace {
-
-int RunContentMain(
-    HeadlessBrowser::Options options,
-    base::OnceCallback<void(HeadlessBrowser*)> on_browser_start_callback) {
-  content::ContentMainParams params(nullptr);
-#if defined(OS_WIN)
-  // Sandbox info has to be set and initialized.
-  CHECK(options.sandbox_info);
-  params.instance = options.instance;
-  params.sandbox_info = std::move(options.sandbox_info);
-#elif !defined(OS_ANDROID)
-  params.argc = options.argc;
-  params.argv = options.argv;
-#endif
-
-  // TODO(skyostil): Implement custom message pumps.
-  DCHECK(!options.message_pump);
-
-  std::unique_ptr<HeadlessBrowserImpl> browser(new HeadlessBrowserImpl(
-      std::move(on_browser_start_callback), std::move(options)));
-  HeadlessContentMainDelegate delegate(std::move(browser));
-  params.delegate = &delegate;
-  return content::ContentMain(params);
-}
-
-}  // namespace
-
-const base::FilePath::CharType kDefaultProfileName[] =
-    FILE_PATH_LITERAL("Default");
 
 HeadlessBrowserImpl::HeadlessBrowserImpl(
     base::OnceCallback<void(HeadlessBrowser*)> on_start_callback,
@@ -242,50 +212,4 @@
   return agent_host_->IsAttached();
 }
 
-#if defined(OS_WIN)
-void RunChildProcessIfNeeded(HINSTANCE instance,
-                             sandbox::SandboxInterfaceInfo* sandbox_info) {
-  base::CommandLine::Init(0, nullptr);
-  HeadlessBrowser::Options::Builder builder(0, nullptr);
-  builder.SetInstance(instance);
-  builder.SetSandboxInfo(std::move(sandbox_info));
-#else
-void RunChildProcessIfNeeded(int argc, const char** argv) {
-  base::CommandLine::Init(argc, argv);
-  HeadlessBrowser::Options::Builder builder(argc, argv);
-#endif  // defined(OS_WIN)
-  const base::CommandLine& command_line(
-      *base::CommandLine::ForCurrentProcess());
-
-  if (!command_line.HasSwitch(::switches::kProcessType))
-    return;
-
-  if (command_line.HasSwitch(switches::kUserAgent)) {
-    std::string ua = command_line.GetSwitchValueASCII(switches::kUserAgent);
-    if (net::HttpUtil::IsValidHeaderValue(ua))
-      builder.SetUserAgent(ua);
-  }
-
-  exit(RunContentMain(builder.Build(),
-                      base::OnceCallback<void(HeadlessBrowser*)>()));
-}
-
-int HeadlessBrowserMain(
-    HeadlessBrowser::Options options,
-    base::OnceCallback<void(HeadlessBrowser*)> on_browser_start_callback) {
-  DCHECK(!on_browser_start_callback.is_null());
-#if DCHECK_IS_ON()
-  // The browser can only be initialized once.
-  static bool browser_was_initialized;
-  DCHECK(!browser_was_initialized);
-  browser_was_initialized = true;
-
-  // Child processes should not end up here.
-  DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
-      ::switches::kProcessType));
-#endif
-  return RunContentMain(std::move(options),
-                        std::move(on_browser_start_callback));
-}
-
 }  // namespace headless
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc
index 2288d967..37b2d21 100644
--- a/headless/lib/headless_content_main_delegate.cc
+++ b/headless/lib/headless_content_main_delegate.cc
@@ -66,6 +66,9 @@
                                  base::FEATURE_DISABLED_BY_DEFAULT};
 }
 
+const base::FilePath::CharType kDefaultProfileName[] =
+    FILE_PATH_LITERAL("Default");
+
 namespace {
 // Keep in sync with content/common/content_constants_internal.h.
 #if !defined(CHROME_MULTIPLE_DLL_CHILD)
@@ -86,10 +89,20 @@
 
 HeadlessContentMainDelegate::HeadlessContentMainDelegate(
     std::unique_ptr<HeadlessBrowserImpl> browser)
-    : browser_(std::move(browser)),
-      headless_crash_key_(base::debug::AllocateCrashKeyString(
-          kHeadlessCrashKey,
-          base::debug::CrashKeySize::Size32)) {
+    : browser_(std::move(browser)) {
+  Init();
+}
+
+HeadlessContentMainDelegate::HeadlessContentMainDelegate(
+    HeadlessBrowser::Options options)
+    : options_(std::make_unique<HeadlessBrowser::Options>(std::move(options))) {
+  Init();
+}
+
+void HeadlessContentMainDelegate::Init() {
+  headless_crash_key_ = base::debug::AllocateCrashKeyString(
+      kHeadlessCrashKey, base::debug::CrashKeySize::Size32);
+
   DCHECK(!g_current_headless_content_main_delegate);
   g_current_headless_content_main_delegate = this;
 
@@ -109,13 +122,13 @@
   if (!command_line->HasSwitch(::switches::kHeadless))
     command_line->AppendSwitch(::switches::kHeadless);
 
-  if (browser_->options()->single_process_mode)
+  if (options()->single_process_mode)
     command_line->AppendSwitch(::switches::kSingleProcess);
 
-  if (browser_->options()->disable_sandbox)
+  if (options()->disable_sandbox)
     command_line->AppendSwitch(service_manager::switches::kNoSandbox);
 
-  if (!browser_->options()->enable_resource_scheduler)
+  if (!options()->enable_resource_scheduler)
     command_line->AppendSwitch(::switches::kDisableResourceScheduler);
 
 #if defined(USE_OZONE)
@@ -134,9 +147,9 @@
       command_line->AppendSwitch(::switches::kDisableGpuCompositing);
     }
   } else {
-    if (!browser_->options()->gl_implementation.empty()) {
+    if (!options()->gl_implementation.empty()) {
       command_line->AppendSwitchASCII(::switches::kUseGL,
-                                      browser_->options()->gl_implementation);
+                                      options()->gl_implementation);
     } else {
       command_line->AppendSwitch(::switches::kDisableGpu);
     }
@@ -195,8 +208,8 @@
 
 // In release builds we should log into the user profile directory.
 #ifdef NDEBUG
-  if (!browser_->options()->user_data_dir.empty()) {
-    log_path = browser_->options()->user_data_dir;
+  if (!options()->user_data_dir.empty()) {
+    log_path = options()->user_data_dir;
     log_path = log_path.Append(kDefaultProfileName);
     base::CreateDirectory(log_path);
     log_path = log_path.Append(log_filename);
@@ -241,12 +254,12 @@
       command_line.GetSwitchValueASCII(::switches::kProcessType);
   crash_reporter::SetCrashReporterClient(g_headless_crash_client.Pointer());
   g_headless_crash_client.Pointer()->set_crash_dumps_dir(
-      browser_->options()->crash_dumps_dir);
+      options()->crash_dumps_dir);
 
   crash_reporter::InitializeCrashKeys();
 
 #if defined(HEADLESS_USE_BREAKPAD)
-  if (!browser_->options()->enable_crash_reporter) {
+  if (!options()->enable_crash_reporter) {
     DCHECK(!breakpad::IsCrashReporterEnabled());
     return;
   }
@@ -353,6 +366,12 @@
   return g_current_headless_content_main_delegate;
 }
 
+HeadlessBrowser::Options* HeadlessContentMainDelegate::options() {
+  if (browser_)
+    return browser_->options();
+  return options_.get();
+}
+
 // static
 void HeadlessContentMainDelegate::InitializeResourceBundle() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -433,8 +452,8 @@
 
 content::ContentUtilityClient*
 HeadlessContentMainDelegate::CreateContentUtilityClient() {
-  utility_client_ = std::make_unique<HeadlessContentUtilityClient>(
-      browser_->options()->user_agent);
+  utility_client_ =
+      std::make_unique<HeadlessContentUtilityClient>(options()->user_agent);
   return utility_client_.get();
 }
 #endif  // !defined(CHROME_MULTIPLE_DLL_BROWSER)
diff --git a/headless/lib/headless_content_main_delegate.h b/headless/lib/headless_content_main_delegate.h
index 3fa162e..cc55c1b 100644
--- a/headless/lib/headless_content_main_delegate.h
+++ b/headless/lib/headless_content_main_delegate.h
@@ -14,10 +14,13 @@
 #include "content/public/app/content_main_delegate.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/renderer/content_renderer_client.h"
-#include "headless/lib/browser/headless_platform_event_source.h"
 #include "headless/lib/headless_content_client.h"
 #include "headless/public/headless_export.h"
 
+#if !defined(CHROME_MULTIPLE_DLL_CHILD)
+#include "headless/lib/browser/headless_platform_event_source.h"
+#endif
+
 namespace base {
 namespace debug {
 struct CrashKeyString;
@@ -35,6 +38,7 @@
  public:
   explicit HeadlessContentMainDelegate(
       std::unique_ptr<HeadlessBrowserImpl> browser);
+  explicit HeadlessContentMainDelegate(HeadlessBrowser::Options options);
   ~HeadlessContentMainDelegate() override;
 
   // content::ContentMainDelegate implementation:
@@ -61,6 +65,10 @@
  private:
   friend class HeadlessBrowserTest;
 
+  void Init();
+
+  HeadlessBrowser::Options* options();
+
   static void InitializeResourceBundle();
   static HeadlessContentMainDelegate* GetInstance();
 
@@ -71,9 +79,13 @@
   std::unique_ptr<content::ContentBrowserClient> browser_client_;
   std::unique_ptr<content::ContentUtilityClient> utility_client_;
   HeadlessContentClient content_client_;
+#if !defined(CHROME_MULTIPLE_DLL_CHILD)
   HeadlessPlatformEventSource platform_event_source_;
+#endif
 
   std::unique_ptr<HeadlessBrowserImpl> browser_;
+  std::unique_ptr<HeadlessBrowser::Options> options_;
+
   base::debug::CrashKeyString* headless_crash_key_;  // Note: never deallocated.
 
   DISALLOW_COPY_AND_ASSIGN(HeadlessContentMainDelegate);
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h
index 130c2ee..812086f 100644
--- a/headless/public/headless_browser.h
+++ b/headless/public/headless_browser.h
@@ -293,16 +293,15 @@
 //
 // [1]
 // https://chromium.googlesource.com/chromium/src/+/master/docs/linux_zygote.md
-HEADLESS_EXPORT void RunChildProcessIfNeeded(int argc, const char** argv);
+void RunChildProcessIfNeeded(int argc, const char** argv);
 #else
 // In Windows, the headless browser may need to create child processes. This is
 // done by re-executing the parent process which may have been initialized with
 // different libraries (e.g. child_dll). In this case, the embedder has to pass
 // the appropiate HINSTANCE and initalization sandbox_info to properly launch
 // the child process.
-HEADLESS_EXPORT void RunChildProcessIfNeeded(
-    HINSTANCE instance,
-    sandbox::SandboxInterfaceInfo* sandbox_info);
+void RunChildProcessIfNeeded(HINSTANCE instance,
+                             sandbox::SandboxInterfaceInfo* sandbox_info);
 #endif  // !defined(OS_WIN)
 
 // Main entry point for running the headless browser. This function constructs
@@ -311,7 +310,7 @@
 // the main loop, it will only return after HeadlessBrowser::Shutdown() is
 // called, returning the exit code for the process. It is not possible to
 // initialize the browser again after it has been torn down.
-HEADLESS_EXPORT int HeadlessBrowserMain(
+int HeadlessBrowserMain(
     HeadlessBrowser::Options options,
     base::OnceCallback<void(HeadlessBrowser*)> on_browser_start_callback);
 
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 722fe3e..9be27bbe 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -147,7 +147,6 @@
 #include "ios/chrome/common/app_group/app_group_field_trial_version.h"
 #include "ios/chrome/common/app_group/app_group_utils.h"
 #include "ios/net/cookies/cookie_store_ios.h"
-#import "ios/net/crn_http_protocol_handler.h"
 #import "ios/net/empty_nsurlcache.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h"
@@ -597,7 +596,6 @@
 }
 
 - (void)dealloc {
-  net::HTTPProtocolHandlerDelegate::SetInstance(nullptr);
   net::RequestTracker::SetRequestTrackerFactory(nullptr);
   [NSObject cancelPreviousPerformRequestsWithTarget:self];
 }
diff --git a/ios/chrome/browser/crash_report/breakpad_helper.mm b/ios/chrome/browser/crash_report/breakpad_helper.mm
index 2ecb37d4..11f9c16 100644
--- a/ios/chrome/browser/crash_report/breakpad_helper.mm
+++ b/ios/chrome/browser/crash_report/breakpad_helper.mm
@@ -15,6 +15,7 @@
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/path_service.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/post_task.h"
@@ -112,6 +113,11 @@
   return false;
 }
 
+// Called after Breakpad finishes uploading each report.
+void UploadResultHandler(NSString* report_id, NSError* error) {
+  base::UmaHistogramSparse("CrashReport.BreakpadIOSUploadOutcome", error.code);
+}
+
 }  // namespace
 
 void Start(const std::string& channel_name) {
@@ -153,6 +159,13 @@
 void SetBreakpadUploadingEnabled(bool enabled) {
   if (!g_crash_reporter_enabled)
     return;
+  if (enabled) {
+    static dispatch_once_t once_token;
+    dispatch_once(&once_token, ^{
+      [[BreakpadController sharedInstance]
+          setUploadCallback:UploadResultHandler];
+    });
+  }
   [[BreakpadController sharedInstance] setUploadingEnabled:enabled];
 }
 
diff --git a/ios/chrome/browser/overlays/BUILD.gn b/ios/chrome/browser/overlays/BUILD.gn
index caab1345..7364da96f 100644
--- a/ios/chrome/browser/overlays/BUILD.gn
+++ b/ios/chrome/browser/overlays/BUILD.gn
@@ -43,6 +43,7 @@
   testonly = true
   sources = [
     "overlay_manager_impl_unittest.mm",
+    "overlay_presenter_unittest.mm",
     "overlay_request_impl_unittest.cc",
     "overlay_request_queue_impl_unittest.mm",
     "overlay_request_unittest.cc",
diff --git a/ios/chrome/browser/overlays/overlay_presenter.h b/ios/chrome/browser/overlays/overlay_presenter.h
index a3c6cfa..48b0960c 100644
--- a/ios/chrome/browser/overlays/overlay_presenter.h
+++ b/ios/chrome/browser/overlays/overlay_presenter.h
@@ -5,17 +5,19 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_PRESENTER_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_PRESENTER_H_
 
+#include "base/memory/weak_ptr.h"
 #import "ios/chrome/browser/overlays/overlay_request_queue_impl_observer.h"
 #import "ios/chrome/browser/overlays/public/overlay_modality.h"
+#import "ios/chrome/browser/overlays/public/overlay_ui_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
 
 class OverlayUIDelegate;
 
 // OverlayPresenter is responsible for triggering the presentation of overlay UI
-// at a given modality.  It observes OverlayRequestQueue modifications for the
-// active WebState and triggers the presentation for added requests using the UI
-// delegate.  Additionally, the presenter will manage hiding and showing
-// overlays when the foreground tab is updated.
+// at a given modality.  The presenter:
+// - observes OverlayRequestQueue modifications for the active WebState and
+//   triggers the presentation for added requests using the UI delegate.
+// - manages hiding and showing overlays for active WebState changes.
 class OverlayPresenter : public OverlayRequestQueueImplObserver,
                          public WebStateListObserver {
  public:
@@ -31,13 +33,39 @@
   void Disconnect();
 
  private:
-  // Fetches the request queue for |web_state|, creating it if necessary.
-  OverlayRequestQueueImpl* GetQueueForWebState(web::WebState* web_state);
+  // Setter for the active WebState.  Setting to a new value will hide any
+  // presented overlays and show the next overlay for the new active WebState.
+  void SetActiveWebState(web::WebState* web_state,
+                         WebStateListObserver::ChangeReason reason);
 
-  // Starts and stops observing |web_state_list_| and its WebStates request
-  // queues.
-  void StartObserving();
-  void StopObserving();
+  // Fetches the request queue for |web_state|, creating it if necessary.
+  OverlayRequestQueueImpl* GetQueueForWebState(web::WebState* web_state) const;
+
+  // Returns the request queue for the active WebState.
+  OverlayRequestQueueImpl* GetActiveQueue() const;
+
+  // Returns the front request for the active queue.
+  OverlayRequest* GetActiveRequest() const;
+
+  // Triggers the presentation of the overlay UI for the active request.  Does
+  // nothing if there is no active request or if there is no UI delegate.  Must
+  // only be called when |presenting_| is false.
+  void PresentOverlayForActiveRequest();
+
+  // Notifies this object that |ui_delegate| has finished dismissing the
+  // overlay UI corresponding with |request| in |queue| for |reason|.  This
+  // function is called when the OverlayDismissalCallback provided to the UI
+  // delegate is excuted.
+  void OverlayWasDismissed(OverlayUIDelegate* ui_delegate,
+                           OverlayRequest* request,
+                           OverlayRequestQueueImpl* queue,
+                           OverlayDismissalReason reason);
+
+  // Cancels all overlays for |web_state|.
+  void CancelOverlayUIForWebState(web::WebState* web_state);
+
+  // Cancels all overlays for the Browser.
+  void CancelAllOverlayUI();
 
   // OverlayRequestQueueImplObserver:
   void OnRequestAdded(OverlayRequestQueueImpl* queue,
@@ -63,7 +91,11 @@
 
   OverlayModality modality_;
   WebStateList* web_state_list_ = nullptr;
+  web::WebState* active_web_state_ = nullptr;
   OverlayUIDelegate* ui_delegate_ = nullptr;
+  bool presenting_ = false;
+  bool detaching_active_web_state_ = false;
+  base::WeakPtrFactory<OverlayPresenter> weak_factory_;
 };
 
 #endif  // IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_PRESENTER_H_
diff --git a/ios/chrome/browser/overlays/overlay_presenter.mm b/ios/chrome/browser/overlays/overlay_presenter.mm
index 26608ef7..2d81826a 100644
--- a/ios/chrome/browser/overlays/overlay_presenter.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter.mm
@@ -6,7 +6,6 @@
 
 #include "base/logging.h"
 #import "ios/chrome/browser/overlays/overlay_request_queue_impl.h"
-#import "ios/chrome/browser/overlays/public/overlay_ui_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -15,8 +14,15 @@
 
 OverlayPresenter::OverlayPresenter(OverlayModality modality,
                                    WebStateList* web_state_list)
-    : modality_(modality), web_state_list_(web_state_list) {
+    : modality_(modality),
+      web_state_list_(web_state_list),
+      weak_factory_(this) {
   DCHECK(web_state_list_);
+  web_state_list_->AddObserver(this);
+  for (int i = 0; i < web_state_list_->count(); ++i) {
+    GetQueueForWebState(web_state_list_->GetWebStateAt(i))->AddObserver(this);
+  }
+  SetActiveWebState(web_state_list_->GetActiveWebState(), CHANGE_REASON_NONE);
 }
 
 OverlayPresenter::~OverlayPresenter() {
@@ -28,56 +34,172 @@
 #pragma mark - Public
 
 void OverlayPresenter::SetUIDelegate(OverlayUIDelegate* ui_delegate) {
-  if (ui_delegate_) {
-    // TODO:(crbug.com/941745): Cancel all overlays for previous UI delegate.
-    StopObserving();
-  }
+  // When the UI delegate is reset, the presenter will begin showing overlays in
+  // the new delegate's presentation context.  Cancel overlay state from the
+  // previous delegate since this Browser's overlays will no longer be presented
+  // there.
+  if (ui_delegate_)
+    CancelAllOverlayUI();
+
   ui_delegate_ = ui_delegate;
-  if (ui_delegate_) {
-    StartObserving();
-    // TODO:(crbug.com/941745): Show overlay for frontmost request in active
-    // WebState's queue.
-  }
+
+  // Reset |presenting| since it was tracking the status for the previous
+  // delegate's presentation context.
+  presenting_ = false;
+  if (ui_delegate_)
+    PresentOverlayForActiveRequest();
 }
 
 void OverlayPresenter::Disconnect() {
   SetUIDelegate(nullptr);
-  web_state_list_ = nullptr;
-}
+  SetActiveWebState(nullptr, CHANGE_REASON_NONE);
 
-#pragma mark - Private
-
-OverlayRequestQueueImpl* OverlayPresenter::GetQueueForWebState(
-    web::WebState* web_state) {
-  OverlayRequestQueueImpl::Container::CreateForWebState(web_state);
-  return OverlayRequestQueueImpl::Container::FromWebState(web_state)
-      ->QueueForModality(modality_);
-}
-
-void OverlayPresenter::StartObserving() {
-  web_state_list_->AddObserver(this);
-  for (int i = 0; i < web_state_list_->count(); ++i) {
-    GetQueueForWebState(web_state_list_->GetWebStateAt(i))->AddObserver(this);
-  }
-}
-
-void OverlayPresenter::StopObserving() {
   for (int i = 0; i < web_state_list_->count(); ++i) {
     GetQueueForWebState(web_state_list_->GetWebStateAt(i))
         ->RemoveObserver(this);
   }
   web_state_list_->RemoveObserver(this);
+  web_state_list_ = nullptr;
+}
+
+#pragma mark -
+#pragma mark Accessors
+
+void OverlayPresenter::SetActiveWebState(
+    web::WebState* web_state,
+    WebStateListObserver::ChangeReason reason) {
+  if (active_web_state_ == web_state)
+    return;
+
+  web::WebState* previously_active_web_state = active_web_state_;
+
+  // The UI should be cancelled instead of hidden if the presenter does not
+  // expect to show any more overlay UI for previously active WebState in the UI
+  // delegate's presentation context.  This occurs:
+  // - when the active WebState is replaced, and
+  // - when the active WebState is detached from the WebStateList.
+  bool should_cancel_ui =
+      (reason & CHANGE_REASON_REPLACED) || detaching_active_web_state_;
+
+  active_web_state_ = web_state;
+  detaching_active_web_state_ = false;
+
+  // Early return if there's no UI delegate, since presentation cannot occur.
+  if (!ui_delegate_)
+    return;
+
+  // If not already presenting, immediately show the next overlay.
+  if (!presenting_) {
+    PresentOverlayForActiveRequest();
+    return;
+  }
+
+  // If the active WebState changes while an overlay is being presented, the
+  // presented UI needs to be dismissed before the next overlay for the new
+  // active WebState can be shown.  The new active WebState's overlays will be
+  // presented when the previous overlay's dismissal callback is executed.
+  DCHECK(previously_active_web_state);
+  if (should_cancel_ui) {
+    CancelOverlayUIForWebState(previously_active_web_state);
+  } else {
+    // For WebState activations, the overlay UI for the previously active
+    // WebState should be hidden, as it may be shown again upon reactivating.
+    ui_delegate_->HideOverlayUIForWebState(previously_active_web_state,
+                                           modality_);
+  }
+}
+
+OverlayRequestQueueImpl* OverlayPresenter::GetQueueForWebState(
+    web::WebState* web_state) const {
+  if (!web_state)
+    return nullptr;
+  OverlayRequestQueueImpl::Container::CreateForWebState(web_state);
+  return OverlayRequestQueueImpl::Container::FromWebState(web_state)
+      ->QueueForModality(modality_);
+}
+
+OverlayRequestQueueImpl* OverlayPresenter::GetActiveQueue() const {
+  return GetQueueForWebState(active_web_state_);
+}
+
+OverlayRequest* OverlayPresenter::GetActiveRequest() const {
+  OverlayRequestQueueImpl* queue = GetActiveQueue();
+  return queue ? queue->front_request() : nullptr;
+}
+
+#pragma mark UI Presentation and Dismissal helpers
+
+void OverlayPresenter::PresentOverlayForActiveRequest() {
+  // Overlays cannot be presented if one is already presented.
+  DCHECK(!presenting_);
+
+  // Overlays cannot be shown without a UI delegate.
+  if (!ui_delegate_)
+    return;
+
+  // No presentation is necessary if there is no active reqeust.
+  OverlayRequest* request = GetActiveRequest();
+  if (!request)
+    return;
+
+  presenting_ = true;
+
+  OverlayDismissalCallback dismissal_callback = base::BindOnce(
+      &OverlayPresenter::OverlayWasDismissed, weak_factory_.GetWeakPtr(),
+      ui_delegate_, request, GetActiveQueue());
+  ui_delegate_->ShowOverlayUIForWebState(active_web_state_, modality_,
+                                         std::move(dismissal_callback));
+}
+
+void OverlayPresenter::OverlayWasDismissed(OverlayUIDelegate* ui_delegate,
+                                           OverlayRequest* request,
+                                           OverlayRequestQueueImpl* queue,
+                                           OverlayDismissalReason reason) {
+  // If the UI delegate is reset while presenting an overlay, that overlay will
+  // be cancelled and dismissed.  The presenter is now using the new UI
+  // delegate's presentation context, so this dismissal should not trigger
+  // presentation logic.
+  if (ui_delegate_ != ui_delegate)
+    return;
+
+  // If the overlay was dismissed for user interaction, pop it from the queue
+  // since it will never be shown again.
+  // TODO(crbug.com/941745): Prevent the queue from being accessed if deleted.
+  // This is possible if a WebState is closed during an overlay dismissal
+  // animation triggered by user interaction.
+  if (reason == OverlayDismissalReason::kUserInteraction)
+    queue->PopFrontRequest();
+
+  presenting_ = false;
+
+  // Only show the next overlay if the active request has changed, either
+  // because the frontmost request was popped or because the active WebState has
+  // changed.
+  if (GetActiveRequest() != request)
+    PresentOverlayForActiveRequest();
+}
+
+#pragma mark Cancellation helpers
+
+void OverlayPresenter::CancelOverlayUIForWebState(web::WebState* web_state) {
+  if (ui_delegate_)
+    ui_delegate_->CancelOverlayUIForWebState(web_state, modality_);
+}
+
+void OverlayPresenter::CancelAllOverlayUI() {
+  for (int i = 0; i < web_state_list_->count(); ++i) {
+    CancelOverlayUIForWebState(web_state_list_->GetWebStateAt(i));
+  }
 }
 
 #pragma mark - OverlayRequestQueueImplObserver
 
 void OverlayPresenter::OnRequestAdded(OverlayRequestQueueImpl* queue,
                                       OverlayRequest* request) {
-  // If the added request is first in the queue, trigger the UI presentation for
-  // that reqeust.
-  if (request == queue->front_request()) {
-    // TODO:(crbug.com/941745): Trigger presentation for request.
-  }
+  // If |queue| is active and the added request is the front request, trigger
+  // the UI presentation for that request.
+  if (queue == GetActiveQueue() && request == queue->front_request())
+    PresentOverlayForActiveRequest();
 }
 
 #pragma mark - WebStateListObserver
@@ -87,10 +209,6 @@
                                           int index,
                                           bool activating) {
   GetQueueForWebState(web_state)->AddObserver(this);
-  if (activating) {
-    // TODO:(crbug.com/941745): If showing an overlay, dismiss it.  Then show
-    // the overlay for the frontmost request in |web_state|'s queue.
-  }
 }
 
 void OverlayPresenter::WebStateReplacedAt(WebStateList* web_state_list,
@@ -99,15 +217,25 @@
                                           int index) {
   GetQueueForWebState(old_web_state)->RemoveObserver(this);
   GetQueueForWebState(new_web_state)->AddObserver(this);
-  // TODO:(crbug.com/941745): Show overlay for first request in |new_web_state|
-  // if it's active.
+  if (old_web_state != active_web_state_) {
+    // If the active WebState is being replaced, its overlay UI will be
+    // cancelled later when |new_web_state| is activated.  For inactive WebState
+    // replacements, the overlay UI can be cancelled immediately.
+    CancelOverlayUIForWebState(old_web_state);
+  }
 }
 
 void OverlayPresenter::WillDetachWebStateAt(WebStateList* web_state_list,
                                             web::WebState* web_state,
                                             int index) {
   GetQueueForWebState(web_state)->RemoveObserver(this);
-  // TODO:(crbug.com/941745): Cancel overlays for |web_state|.
+  detaching_active_web_state_ = web_state == active_web_state_;
+  if (!detaching_active_web_state_) {
+    // If the active WebState is being detached, its overlay UI will be
+    // cancelled later when the active WebState is reset.  For inactive WebState
+    // replacements, the overlay UI can be cancelled immediately.
+    CancelOverlayUIForWebState(web_state);
+  }
 }
 
 void OverlayPresenter::WebStateActivatedAt(WebStateList* web_state_list,
@@ -115,6 +243,6 @@
                                            web::WebState* new_web_state,
                                            int active_index,
                                            int reason) {
-  // TODO:(crbug.com/941745): If showing an overlay, dismiss it.  Then show the
-  // overlay for the frontmost request in |web_state|'s queue.
+  SetActiveWebState(new_web_state,
+                    static_cast<WebStateListObserver::ChangeReason>(reason));
 }
diff --git a/ios/chrome/browser/overlays/overlay_presenter_unittest.mm b/ios/chrome/browser/overlays/overlay_presenter_unittest.mm
new file mode 100644
index 0000000..9d364f9
--- /dev/null
+++ b/ios/chrome/browser/overlays/overlay_presenter_unittest.mm
@@ -0,0 +1,277 @@
+// 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 "ios/chrome/browser/overlays/overlay_presenter.h"
+
+#include "ios/chrome/browser/overlays/overlay_request_queue_impl.h"
+#include "ios/chrome/browser/overlays/public/overlay_modality.h"
+#include "ios/chrome/browser/overlays/public/overlay_request.h"
+#include "ios/chrome/browser/overlays/test/fake_overlay_ui_delegate.h"
+#include "ios/chrome/browser/overlays/test/fake_overlay_user_data.h"
+#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_opener.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Test fixture for OverlayPresenter.
+class OverlayPresenterTest : public PlatformTest {
+ public:
+  OverlayPresenterTest()
+      : web_state_list_(&web_state_list_delegate_),
+        presenter_(OverlayModality::kWebContentArea, &web_state_list_) {}
+  ~OverlayPresenterTest() override { presenter_.Disconnect(); }
+
+  WebStateList& web_state_list() { return web_state_list_; }
+  web::WebState* active_web_state() {
+    return web_state_list_.GetActiveWebState();
+  }
+  OverlayPresenter& presenter() { return presenter_; }
+  FakeOverlayUIDelegate& ui_delegate() { return ui_delegate_; }
+
+  OverlayRequestQueueImpl* GetQueueForWebState(web::WebState* web_state) {
+    if (!web_state)
+      return nullptr;
+    OverlayRequestQueueImpl::Container::CreateForWebState(web_state);
+    return OverlayRequestQueueImpl::Container::FromWebState(web_state)
+        ->QueueForModality(OverlayModality::kWebContentArea);
+  }
+
+ private:
+  FakeWebStateListDelegate web_state_list_delegate_;
+  WebStateList web_state_list_;
+  FakeOverlayUIDelegate ui_delegate_;
+  OverlayPresenter presenter_;
+};
+
+// Tests that setting the UI delegate will present overlays requested before the
+// delegate is provided.
+TEST_F(OverlayPresenterTest, PresentAfterSettingUIDelegate) {
+  // Add a WebState to the list and add a request to that WebState's queue.
+  web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+  web::WebState* web_state = active_web_state();
+  GetQueueForWebState(web_state)->AddRequest(
+      OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  ASSERT_EQ(FakeOverlayUIDelegate::PresentationState::kNotPresented,
+            ui_delegate().GetPresentationState(web_state));
+
+  // Set the UI delegate and verify that the request has been presented.
+  presenter().SetUIDelegate(&ui_delegate());
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(web_state));
+}
+
+// Tests that requested overlays are presented when added to the active queue
+// after the UI delegate has been provided.
+TEST_F(OverlayPresenterTest, PresentAfterRequestAddedToActiveQueue) {
+  // Add a WebState to the list and add a request to that WebState's queue.
+  presenter().SetUIDelegate(&ui_delegate());
+  web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+  web::WebState* web_state = active_web_state();
+  GetQueueForWebState(web_state)->AddRequest(
+      OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  // Verify that the requested overlay has been presented.
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(web_state));
+}
+
+// Tests resetting the UI delegate.  The UI should be cancelled in the previous
+// UI delegate and presented in the new delegate.
+TEST_F(OverlayPresenterTest, ResetUIDelegate) {
+  // Add a WebState to the list and add a request to that WebState's queue.
+  presenter().SetUIDelegate(&ui_delegate());
+  web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+  web::WebState* web_state = active_web_state();
+  OverlayRequestQueueImpl* queue = GetQueueForWebState(web_state);
+  queue->AddRequest(
+      OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  OverlayRequest* request = queue->front_request();
+
+  ASSERT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(web_state));
+
+  // Reset the UI delegate and verify that the overlay UI is cancelled in the
+  // previous delegate's context and presented in the new delegate's context.
+  FakeOverlayUIDelegate new_ui_delegate;
+  presenter().SetUIDelegate(&new_ui_delegate);
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kCancelled,
+            ui_delegate().GetPresentationState(web_state));
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            new_ui_delegate.GetPresentationState(web_state));
+  EXPECT_EQ(request, queue->front_request());
+
+  // Reset the UI delegate to nullptr and verify that the overlay UI is
+  // cancelled in |new_ui_delegate|'s context.
+  presenter().SetUIDelegate(nullptr);
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kCancelled,
+            new_ui_delegate.GetPresentationState(web_state));
+  EXPECT_EQ(request, queue->front_request());
+}
+
+// Tests changing the active WebState while no overlays are presented over the
+// current active WebState.
+TEST_F(OverlayPresenterTest, ChangeActiveWebStateWhileNotPresenting) {
+  // Add a WebState to the list and activate it.
+  presenter().SetUIDelegate(&ui_delegate());
+  web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+  web::WebState* first_web_state = active_web_state();
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kNotPresented,
+            ui_delegate().GetPresentationState(first_web_state));
+
+  // Create a new WebState with a queued request and add it as the new active
+  // WebState.
+  std::unique_ptr<web::WebState> passed_web_state =
+      std::make_unique<web::TestWebState>();
+  web::WebState* second_web_state = passed_web_state.get();
+  GetQueueForWebState(second_web_state)
+      ->AddRequest(
+          OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  web_state_list().InsertWebState(1, std::move(passed_web_state),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+
+  // Verify that the new active WebState's overlay is being presented.
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kNotPresented,
+            ui_delegate().GetPresentationState(first_web_state));
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(second_web_state));
+}
+
+// Tests changing the active WebState while is it presenting an overlay.
+TEST_F(OverlayPresenterTest, ChangeActiveWebStateWhilePresenting) {
+  // Add a WebState to the list and add a request to that WebState's queue.
+  presenter().SetUIDelegate(&ui_delegate());
+  web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+  web::WebState* first_web_state = active_web_state();
+  GetQueueForWebState(first_web_state)
+      ->AddRequest(
+          OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  ASSERT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(first_web_state));
+
+  // Create a new WebState with a queued request and add it as the new active
+  // WebState.
+  std::unique_ptr<web::WebState> passed_web_state =
+      std::make_unique<web::TestWebState>();
+  web::WebState* second_web_state = passed_web_state.get();
+  GetQueueForWebState(second_web_state)
+      ->AddRequest(
+          OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  web_state_list().InsertWebState(1, std::move(passed_web_state),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+
+  // Verify that the previously shown overlay is hidden and that the overlay for
+  // the new active WebState is presented.
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kHidden,
+            ui_delegate().GetPresentationState(first_web_state));
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(second_web_state));
+
+  // Reactivate the first WebState and verify that its overlay is presented
+  // while the second WebState's overlay is hidden.
+  web_state_list().ActivateWebStateAt(0);
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(first_web_state));
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kHidden,
+            ui_delegate().GetPresentationState(second_web_state));
+}
+
+// Tests replacing the active WebState while it is presenting an overlay.
+TEST_F(OverlayPresenterTest, ReplaceActiveWebState) {
+  // Add a WebState to the list and add a request to that WebState's queue.
+  presenter().SetUIDelegate(&ui_delegate());
+  web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+  web::WebState* first_web_state = active_web_state();
+  GetQueueForWebState(first_web_state)
+      ->AddRequest(
+          OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  ASSERT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(first_web_state));
+
+  // Replace |first_web_state| with a new active WebState with a queued request.
+  std::unique_ptr<web::WebState> passed_web_state =
+      std::make_unique<web::TestWebState>();
+  web::WebState* replacement_web_state = passed_web_state.get();
+  GetQueueForWebState(replacement_web_state)
+      ->AddRequest(
+          OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  web_state_list().ReplaceWebStateAt(0, std::move(passed_web_state));
+
+  // Verify that the previously shown overlay is canceled and that the overlay
+  // for the replacement WebState is presented.
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kCancelled,
+            ui_delegate().GetPresentationState(first_web_state));
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(replacement_web_state));
+}
+
+// Tests removing the active WebState while it is presenting an overlay.
+TEST_F(OverlayPresenterTest, RemoveActiveWebState) {
+  // Add a WebState to the list and add a request to that WebState's queue.
+  presenter().SetUIDelegate(&ui_delegate());
+  web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+  web::WebState* web_state = active_web_state();
+  GetQueueForWebState(web_state)->AddRequest(
+      OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr));
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(web_state));
+
+  // Remove the WebState and verify that its overlay was cancelled.
+  web_state_list().CloseWebStateAt(0, 0);
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kCancelled,
+            ui_delegate().GetPresentationState(web_state));
+}
+
+// Tests dismissing an overlay for user interaction.
+TEST_F(OverlayPresenterTest, DismissForUserInteraction) {
+  // Add a WebState to the list and add two request to that WebState's queue.
+  presenter().SetUIDelegate(&ui_delegate());
+  web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(),
+                                  WebStateList::InsertionFlags::INSERT_ACTIVATE,
+                                  WebStateOpener());
+  web::WebState* web_state = active_web_state();
+  OverlayRequestQueueImpl* queue = GetQueueForWebState(web_state);
+  std::unique_ptr<OverlayRequest> passed_request =
+      OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr);
+  OverlayRequest* first_request = passed_request.get();
+  queue->AddRequest(std::move(passed_request));
+  passed_request =
+      OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr);
+  OverlayRequest* second_request = passed_request.get();
+  queue->AddRequest(std::move(passed_request));
+
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(web_state));
+  EXPECT_EQ(first_request, queue->front_request());
+  EXPECT_EQ(2U, queue->size());
+
+  // Dismiss the overlay and check that the second request's overlay is
+  // presented.
+  ui_delegate().SimulateDismissalForWebState(
+      web_state, OverlayDismissalReason::kUserInteraction);
+
+  EXPECT_EQ(FakeOverlayUIDelegate::PresentationState::kPresented,
+            ui_delegate().GetPresentationState(web_state));
+  EXPECT_EQ(second_request, queue->front_request());
+  EXPECT_EQ(1U, queue->size());
+}
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
index 5b67e01..12e5f257 100644
--- a/ios/chrome/browser/translate/chrome_ios_translate_client.mm
+++ b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
@@ -21,8 +21,6 @@
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/browser/translate_step.h"
 #include "components/translate/core/common/language_detection_details.h"
-#include "components/translate/core/common/language_detection_logging_helper.h"
-#include "components/translate/core/common/translation_logging_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/infobars/infobar.h"
 #include "ios/chrome/browser/infobars/infobar_controller.h"
diff --git a/ios/chrome/browser/ui/safe_mode/safe_mode_view_controller_unittest.mm b/ios/chrome/browser/ui/safe_mode/safe_mode_view_controller_unittest.mm
index 44bf68b..196f9e7a 100644
--- a/ios/chrome/browser/ui/safe_mode/safe_mode_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/safe_mode/safe_mode_view_controller_unittest.mm
@@ -112,6 +112,9 @@
 
   // Test when crash reporter and crash report uploading are enabled.
   [[mock_breakpad_controller_ expect] setUploadingEnabled:YES];
+  [[mock_breakpad_controller_ expect]
+      setUploadCallback:reinterpret_cast<BreakpadUploadCompletionCallback>(
+                            [OCMArg anyPointer])];
   breakpad_helper::SetUploadingEnabled(true);
   EXPECT_OCMOCK_VERIFY(mock_breakpad_controller_);
 
diff --git a/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.h b/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.h
index 6360a86..89caecf 100644
--- a/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.h
+++ b/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.h
@@ -21,6 +21,10 @@
 // Whether or not the cell should show a checkmark.
 @property(nonatomic, assign) BOOL checked;
 
+// If not nil, specified color will be cell's backgroundColor
+// when self.checked == YES
+@property(nonatomic, strong) UIColor* checkedBackgroundColor;
+
 // Mask of the data to be cleared.
 @property(nonatomic, assign) BrowsingDataRemoveMask dataTypeMask;
 
diff --git a/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm b/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm
index a0de40d4..92c65f6 100644
--- a/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm
@@ -46,6 +46,10 @@
     image = [UIImage imageNamed:self.imageName];
   }
   [cell setImage:image];
+  if (self.checkedBackgroundColor) {
+    // Overrides |styler|'s cellBackgroundColor (if set in the call to super).
+    cell.backgroundColor = self.checked ? self.checkedBackgroundColor : nil;
+  }
   cell.textLabel.text = self.text;
   cell.detailTextLabel.text = self.detailText;
   cell.optionalTextLabel.text = self.optionalText;
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
index 82742c31..6fe461c 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
@@ -64,6 +64,9 @@
 const int kMaxTimesHistoryNoticeShown = 1;
 // The tableView button red background color.
 const CGFloat kTableViewButtonBackgroundColor = 0xE94235;
+// Highlighted background color for cells in the Data Types section.
+const CGFloat kCellHightlightedColorAlpha = 0.05;
+const int kCellHighlightedColorRGB = 0x4285F4;
 
 // List of flags that have corresponding counters.
 const std::vector<BrowsingDataRemoveMask> _browsingDataRemoveFlags = {
@@ -491,6 +494,8 @@
     tableViewClearDataItem.prefName = prefName;
     if (IsNewClearBrowsingDataUIEnabled()) {
       tableViewClearDataItem.useCustomSeparator = YES;
+      tableViewClearDataItem.checkedBackgroundColor =
+          UIColorFromRGB(kCellHighlightedColorRGB, kCellHightlightedColorAlpha);
       tableViewClearDataItem.imageName = [_imageNamesByItemTypes
           objectForKey:[NSNumber numberWithInteger:itemType]];
       if (itemType == ItemTypeDataTypeCookiesSiteData) {
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
index 3d5330f..b4698482 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
@@ -26,7 +26,6 @@
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
-#include "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -35,11 +34,6 @@
 #error "This file requires ARC support."
 #endif
 
-namespace {
-const CGFloat kCellHightlightColorAlpha = 0.05;
-const int kCellHighlightColorRgb = 0x4285F4;
-}  // namespace
-
 @interface ClearBrowsingDataTableViewController () <
     TableViewTextLinkCellDelegate,
     ClearBrowsingDataConsumer>
@@ -132,8 +126,6 @@
   [super viewDidLoad];
   if (IsNewClearBrowsingDataUIEnabled()) {
     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
-    self.styler.cellHighlightColor =
-        UIColorFromRGB(kCellHighlightColorRgb, kCellHightlightColorAlpha);
   }
   self.styler.tableViewBackgroundColor = UIColor.whiteColor;
   self.tableView.accessibilityIdentifier =
@@ -264,6 +256,12 @@
     case ItemTypeDataTypeCache:
     case ItemTypeDataTypeSavedPasswords:
     case ItemTypeDataTypeAutofill:
+      // For these cells the selection style application is specified in the
+      // corresponding item definition.
+      if (IsNewClearBrowsingDataUIEnabled()) {
+        cellToReturn.selectionStyle = UITableViewCellSelectionStyleNone;
+      }
+      break;
     default:
       break;
   }
diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc
index 71c6ea7..b37ee05 100644
--- a/media/audio/win/audio_low_latency_input_win.cc
+++ b/media/audio/win/audio_low_latency_input_win.cc
@@ -618,38 +618,40 @@
   // Retrieve the IMMDevice by using the specified role or the specified
   // unique endpoint device-identification string.
 
-  if (device_id_ == AudioDeviceDescription::kDefaultDeviceId) {
-    // Retrieve the default capture audio endpoint for the specified role.
-    // Note that, in Windows Vista, the MMDevice API supports device roles
-    // but the system-supplied user interface programs do not.
-    hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole,
-                                             endpoint_device_.GetAddressOf());
-  } else if (device_id_ == AudioDeviceDescription::kCommunicationsDeviceId) {
-    hr = enumerator->GetDefaultAudioEndpoint(eCapture, eCommunications,
-                                             endpoint_device_.GetAddressOf());
-  } else if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId) {
-    // Capture the default playback stream.
-    hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
-                                             endpoint_device_.GetAddressOf());
-
-    if (SUCCEEDED(hr)) {
-      endpoint_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL,
-                                 NULL, &system_audio_volume_);
-    }
-  } else if (device_id_ == AudioDeviceDescription::kLoopbackInputDeviceId) {
-    // Capture the default playback stream.
-    hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
-                                             endpoint_device_.GetAddressOf());
+  // To open a stream in loopback mode, the client must obtain an IMMDevice
+  // interface for the rendering endpoint device. Make that happen if needed;
+  // otherwise use default capture data-flow direction.
+  const EDataFlow data_flow =
+      AudioDeviceDescription::IsLoopbackDevice(device_id_) ? eRender : eCapture;
+  // Determine selected role to be used if the device is a default device.
+  const ERole role = AudioDeviceDescription::IsCommunicationsDevice(device_id_)
+                         ? eCommunications
+                         : eConsole;
+  if (AudioDeviceDescription::IsDefaultDevice(device_id_) ||
+      AudioDeviceDescription::IsCommunicationsDevice(device_id_) ||
+      AudioDeviceDescription::IsLoopbackDevice(device_id_)) {
+    hr =
+        enumerator->GetDefaultAudioEndpoint(data_flow, role, &endpoint_device_);
   } else {
     hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id_).c_str(),
                                endpoint_device_.GetAddressOf());
   }
-
   if (FAILED(hr)) {
     open_result_ = OPEN_RESULT_NO_ENDPOINT;
     return hr;
   }
 
+  // If loopback device with muted system audio is requested, get the volume
+  // interface for the endpoint.
+  if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId) {
+    hr = endpoint_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL,
+                                    nullptr, &system_audio_volume_);
+    if (FAILED(hr)) {
+      open_result_ = OPEN_RESULT_ACTIVATION_FAILED;
+      return hr;
+    }
+  }
+
   // Verify that the audio endpoint device is active, i.e., the audio
   // adapter that connects to the endpoint device is present and enabled.
   DWORD state = DEVICE_STATE_DISABLED;
@@ -807,7 +809,7 @@
       100 * 1000 * 10,  // Buffer duration, 100 ms expressed in 100-ns units.
       0,                // Device period, n/a for shared mode.
       reinterpret_cast<const WAVEFORMATEX*>(&input_format_),
-      device_id_ == AudioDeviceDescription::kCommunicationsDeviceId
+      AudioDeviceDescription::IsCommunicationsDevice(device_id_)
           ? &kCommunicationsSessionId
           : nullptr);
 
@@ -887,7 +889,10 @@
     hr = audio_render_client_for_loopback_->Initialize(
         AUDCLNT_SHAREMODE_SHARED,
         AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, 0, 0,
-        reinterpret_cast<const WAVEFORMATEX*>(&input_format_), NULL);
+        reinterpret_cast<const WAVEFORMATEX*>(&input_format_),
+        AudioDeviceDescription::IsCommunicationsDevice(device_id_)
+            ? &kCommunicationsSessionId
+            : nullptr);
     if (FAILED(hr)) {
       open_result_ = OPEN_RESULT_LOOPBACK_INIT_FAILED;
       return hr;
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc
index 6b5278db..87c732a7 100644
--- a/media/audio/win/core_audio_util_win.cc
+++ b/media/audio/win/core_audio_util_win.cc
@@ -443,6 +443,27 @@
                                        ERole role,
                                        const UMALogCallback& uma_log_cb) {
   ComPtr<IMMDevice> endpoint_device;
+  // In loopback mode, a client of WASAPI can capture the audio stream that
+  // is being played by a rendering endpoint device.
+  // See https://crbug.com/956526 for why we use both a DCHECK and then deal
+  // with the error here and below.
+  DCHECK(!(AudioDeviceDescription::IsLoopbackDevice(device_id) &&
+           data_flow != eCapture));
+  if (AudioDeviceDescription::IsLoopbackDevice(device_id) &&
+      data_flow != eCapture) {
+    LOG(WARNING) << "Loopback device must be an input device";
+    return endpoint_device;
+  }
+
+  // Usage of AudioDeviceDescription::kCommunicationsDeviceId as |device_id|
+  // is not allowed. Instead, set |device_id| to kDefaultDeviceId and select
+  // between default device and default communication device by using different
+  // |role| values (eConsole or eCommunications).
+  DCHECK(!AudioDeviceDescription::IsCommunicationsDevice(device_id));
+  if (AudioDeviceDescription::IsCommunicationsDevice(device_id)) {
+    LOG(WARNING) << "Invalid device identifier";
+    return endpoint_device;
+  }
 
   // Create the IMMDeviceEnumerator interface.
   ComPtr<IMMDeviceEnumerator> device_enum(
@@ -455,9 +476,8 @@
     hr =
         device_enum->GetDefaultAudioEndpoint(data_flow, role, &endpoint_device);
   } else if (AudioDeviceDescription::IsLoopbackDevice(device_id)) {
-    // Obtain an IMMDevice interface for the rendering endpoint device since
-    // loopback mode is selected.
-    // TODO(http://crbug/956526): clean up code related to loopback mode.
+    // To open a stream in loopback mode, the client must obtain an IMMDevice
+    // interface for the *rendering* endpoint device.
     hr = device_enum->GetDefaultAudioEndpoint(eRender, role, &endpoint_device);
   } else {
     hr = device_enum->GetDevice(base::UTF8ToUTF16(device_id).c_str(),
@@ -1070,6 +1090,15 @@
   UMALogCallback uma_log_cb(
       is_output_device ? base::BindRepeating(&LogUMAPreferredOutputParams)
                        : base::BindRepeating(&LogUMAEmptyCb));
+
+  // Loopback audio streams must be input streams.
+  DCHECK(!(AudioDeviceDescription::IsLoopbackDevice(device_id) &&
+           is_output_device));
+  if (AudioDeviceDescription::IsLoopbackDevice(device_id) && is_output_device) {
+    LOG(WARNING) << "Loopback device must be an input device";
+    return E_FAIL;
+  }
+
   ComPtr<IMMDevice> device(
       CreateDeviceByID(device_id, is_output_device, uma_log_cb));
   if (!device.Get())
@@ -1103,7 +1132,10 @@
 
 ChannelConfig CoreAudioUtil::GetChannelConfig(const std::string& device_id,
                                               EDataFlow data_flow) {
-  ComPtr<IAudioClient> client(CreateClient(device_id, data_flow, eConsole));
+  const ERole role = AudioDeviceDescription::IsCommunicationsDevice(device_id)
+                         ? eCommunications
+                         : eConsole;
+  ComPtr<IAudioClient> client(CreateClient(device_id, data_flow, role));
 
   WAVEFORMATEXTENSIBLE mix_format;
   if (!client.Get() ||
diff --git a/media/audio/win/core_audio_util_win.h b/media/audio/win/core_audio_util_win.h
index 61ed472..1a797e3 100644
--- a/media/audio/win/core_audio_util_win.h
+++ b/media/audio/win/core_audio_util_win.h
@@ -205,8 +205,6 @@
   // speaker, and so on, continuing in the order defined in KsMedia.h.
   // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff537083(v=vs.85).aspx
   // for more details.
-  // To get the channel config of the default device, pass an empty string
-  // for |device_id|.
   static ChannelConfig GetChannelConfig(const std::string& device_id,
                                         EDataFlow data_flow);
 
diff --git a/media/audio/win/core_audio_util_win_unittest.cc b/media/audio/win/core_audio_util_win_unittest.cc
index dffdc64..8fc1330 100644
--- a/media/audio/win/core_audio_util_win_unittest.cc
+++ b/media/audio/win/core_audio_util_win_unittest.cc
@@ -131,6 +131,18 @@
   EXPECT_TRUE(enumerator.Get());
 }
 
+TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceIDs) {
+  ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
+  std::string default_device_id = CoreAudioUtil::GetDefaultInputDeviceID();
+  EXPECT_FALSE(default_device_id.empty());
+  default_device_id = CoreAudioUtil::GetDefaultOutputDeviceID();
+  EXPECT_FALSE(default_device_id.empty());
+  default_device_id = CoreAudioUtil::GetCommunicationsInputDeviceID();
+  EXPECT_FALSE(default_device_id.empty());
+  default_device_id = CoreAudioUtil::GetCommunicationsOutputDeviceID();
+  EXPECT_FALSE(default_device_id.empty());
+}
+
 TEST_F(CoreAudioUtilWinTest, CreateDefaultDevice) {
   ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
 
@@ -171,7 +183,7 @@
   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(
       default_render_device.Get(), &default_render_name)));
 
-  // Use the uniqe ID as input to CreateDevice() and create a corresponding
+  // Use the unique ID as input to CreateDevice() and create a corresponding
   // IMMDevice.
   ComPtr<IMMDevice> audio_device = CoreAudioUtil::CreateDevice(
       default_render_name.unique_id, EDataFlow(), ERole());
@@ -383,10 +395,17 @@
   // and capture devices.
   for (size_t i = 0; i < base::size(data); ++i) {
     AudioParameters params;
+    const bool is_output_device = (data[i] == eRender);
     EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
-        AudioDeviceDescription::kDefaultDeviceId, data[i] == eRender,
-        &params)));
+        AudioDeviceDescription::kDefaultDeviceId, is_output_device, &params)));
     EXPECT_TRUE(params.IsValid());
+    if (!is_output_device) {
+      // Loopack devices are supported for input streams.
+      EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
+          AudioDeviceDescription::kLoopbackInputDeviceId, is_output_device,
+          &params)));
+      EXPECT_TRUE(params.IsValid());
+    }
   }
 }
 
@@ -396,10 +415,22 @@
   EDataFlow data_flows[] = {eRender, eCapture};
 
   for (auto data_flow : data_flows) {
-    ChannelConfig config =
+    ChannelConfig config1 =
         CoreAudioUtil::GetChannelConfig(std::string(), data_flow);
-    EXPECT_NE(config, CHANNEL_LAYOUT_NONE);
-    EXPECT_NE(config, CHANNEL_LAYOUT_UNSUPPORTED);
+    EXPECT_NE(config1, CHANNEL_LAYOUT_NONE);
+    EXPECT_NE(config1, CHANNEL_LAYOUT_UNSUPPORTED);
+    ChannelConfig config2 = CoreAudioUtil::GetChannelConfig(
+        AudioDeviceDescription::kDefaultDeviceId, data_flow);
+    EXPECT_EQ(config1, config2);
+    // For loopback input devices, verify that the channel configuration is
+    // same as for the default output device.
+    if (data_flow == eCapture) {
+      config1 = CoreAudioUtil::GetChannelConfig(
+          AudioDeviceDescription::kLoopbackInputDeviceId, data_flow);
+      config2 = CoreAudioUtil::GetChannelConfig(
+          AudioDeviceDescription::kDefaultDeviceId, eRender);
+      EXPECT_EQ(config1, config2);
+    }
   }
 }
 
@@ -583,13 +614,6 @@
   EXPECT_TRUE(found_a_pair);
 }
 
-TEST_F(CoreAudioUtilWinTest, GetDefaultOutputDeviceID) {
-  ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
-
-  std::string default_device_id(CoreAudioUtil::GetDefaultOutputDeviceID());
-  EXPECT_FALSE(default_device_id.empty());
-}
-
 TEST_F(CoreAudioUtilWinTest, CheckGetPreferredAudioParametersUMAStats) {
   base::HistogramTester tester;
   ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 2ebf67a..1dce4bf 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -459,7 +459,6 @@
       "base/ip_pattern.h",
       "base/layered_network_delegate.cc",
       "base/layered_network_delegate.h",
-      "base/linked_hash_map.h",
       "base/load_flags.h",
       "base/load_flags_list.h",
       "base/load_states.h",
@@ -1057,6 +1056,9 @@
       "quic/quic_stream_factory.h",
       "quic/quic_utils_chromium.cc",
       "quic/quic_utils_chromium.h",
+      "quiche/common/platform/impl/quiche_logging_impl.h",
+      "quiche/common/platform/impl/quiche_ptr_util_impl.h",
+      "quiche/common/platform/impl/quiche_unordered_containers_impl.h",
       "socket/client_socket_factory.cc",
       "socket/client_socket_factory.h",
       "socket/client_socket_pool.cc",
@@ -1208,7 +1210,6 @@
       "third_party/mozilla_security_manager/nsPKCS12Blob.h",
       "third_party/quiche/src/common/platform/api/quiche_logging.h",
       "third_party/quiche/src/common/platform/api/quiche_ptr_util.h",
-      "third_party/quiche/src/common/platform/api/quiche_test.h",
       "third_party/quiche/src/common/platform/api/quiche_unordered_containers.h",
       "third_party/quiche/src/common/simple_linked_hash_map.h",
       "third_party/quiche/src/http2/decoder/decode_buffer.cc",
@@ -3263,6 +3264,18 @@
   ]
 }
 
+source_set("quiche_test_tools") {
+  testonly = true
+  sources = [
+    "quiche/common/platform/impl/quiche_test_impl.h",
+    "third_party/quiche/src/common/platform/api/quiche_test.h",
+  ]
+  deps = [
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
 source_set("quic_test_tools") {
   testonly = true
   sources = [
@@ -5213,6 +5226,7 @@
     "test/run_all_unittests.cc",
     "test/tcp_socket_proxy_unittest.cc",
     "third_party/nist-pkits/pkits_testcases-inl.h",
+    "third_party/quiche/src/common/simple_linked_hash_map_test.cc",
     "third_party/quiche/src/http2/decoder/decode_buffer_test.cc",
     "third_party/quiche/src/http2/decoder/decode_http2_structures_test.cc",
     "third_party/quiche/src/http2/decoder/frame_decoder_state_test_util.cc",
@@ -5544,6 +5558,7 @@
   deps = [
     ":net",
     ":quic_test_tools",
+    ":quiche_test_tools",
     ":simple_quic_tools",
     ":spdy_test_tools",
     ":test_support",
diff --git a/net/base/linked_hash_map.h b/net/base/linked_hash_map.h
deleted file mode 100644
index 921764f..0000000
--- a/net/base/linked_hash_map.h
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright (c) 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.
-//
-// This is a simplistic insertion-ordered map.  It behaves similarly to an STL
-// map, but only implements a small subset of the map's methods.  Internally, we
-// just keep a map and a list going in parallel.
-//
-// This class provides no thread safety guarantees, beyond what you would
-// normally see with std::list.
-//
-// Iterators should be stable in the face of mutations, except for an
-// iterator pointing to an element that was just deleted.
-
-#ifndef NET_BASE_LINKED_HASH_MAP_H_
-#define NET_BASE_LINKED_HASH_MAP_H_
-
-#include <stddef.h>
-
-#include <list>
-#include <unordered_map>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/macros.h"
-
-namespace net {
-
-// This holds a list of pair<Key, Value> items.  This list is what gets
-// traversed, and it's iterators from this list that we return from
-// begin/end/find.
-//
-// We also keep a map<Key, list::iterator> for find.  Since std::list is a
-// doubly-linked list, the iterators should remain stable.
-template <class Key, class Value, class Hash = std::hash<Key>>
-class linked_hash_map {
- private:
-  typedef std::list<std::pair<Key, Value> > ListType;
-  typedef std::unordered_map<Key, typename ListType::iterator, Hash> MapType;
-
- public:
-  typedef typename ListType::iterator iterator;
-  typedef typename ListType::reverse_iterator reverse_iterator;
-  typedef typename ListType::const_iterator const_iterator;
-  typedef typename ListType::const_reverse_iterator const_reverse_iterator;
-  typedef typename MapType::key_type key_type;
-  typedef typename ListType::value_type value_type;
-  typedef typename ListType::size_type size_type;
-
-  linked_hash_map() = default;
-  explicit linked_hash_map(size_type bucket_count) : map_(bucket_count) {}
-
-  linked_hash_map(linked_hash_map&& other) = default;
-  linked_hash_map& operator=(linked_hash_map&& other) = default;
-
-  // Returns an iterator to the first (insertion-ordered) element.  Like a map,
-  // this can be dereferenced to a pair<Key, Value>.
-  iterator begin() {
-    return list_.begin();
-  }
-  const_iterator begin() const {
-    return list_.begin();
-  }
-
-  // Returns an iterator beyond the last element.
-  iterator end() {
-    return list_.end();
-  }
-  const_iterator end() const {
-    return list_.end();
-  }
-
-  // Returns an iterator to the last (insertion-ordered) element.  Like a map,
-  // this can be dereferenced to a pair<Key, Value>.
-  reverse_iterator rbegin() {
-    return list_.rbegin();
-  }
-  const_reverse_iterator rbegin() const {
-    return list_.rbegin();
-  }
-
-  // Returns an iterator beyond the first element.
-  reverse_iterator rend() {
-    return list_.rend();
-  }
-  const_reverse_iterator rend() const {
-    return list_.rend();
-  }
-
-  // Front and back accessors common to many stl containers.
-
-  // Returns the earliest-inserted element
-  const value_type& front() const {
-    return list_.front();
-  }
-
-  // Returns the earliest-inserted element.
-  value_type& front() {
-    return list_.front();
-  }
-
-  // Returns the most-recently-inserted element.
-  const value_type& back() const {
-    return list_.back();
-  }
-
-  // Returns the most-recently-inserted element.
-  value_type& back() {
-    return list_.back();
-  }
-
-  // Clears the map of all values.
-  void clear() {
-    map_.clear();
-    list_.clear();
-  }
-
-  // Returns true iff the map is empty.
-  bool empty() const {
-    return list_.empty();
-  }
-
-  // Removes the first element from the list.
-  void pop_front() { erase(begin()); }
-
-  // Erases values with the provided key.  Returns the number of elements
-  // erased.  In this implementation, this will be 0 or 1.
-  size_type erase(const Key& key) {
-    typename MapType::iterator found = map_.find(key);
-    if (found == map_.end()) return 0;
-
-    list_.erase(found->second);
-    map_.erase(found);
-
-    return 1;
-  }
-
-  // Erases the item that 'position' points to. Returns an iterator that points
-  // to the item that comes immediately after the deleted item in the list, or
-  // end().
-  // If the provided iterator is invalid or there is inconsistency between the
-  // map and list, a CHECK() error will occur.
-  iterator erase(iterator position) {
-    typename MapType::iterator found = map_.find(position->first);
-    CHECK(found->second == position)
-        << "Inconsisent iterator for map and list, or the iterator is invalid.";
-
-    map_.erase(found);
-    return list_.erase(position);
-  }
-
-  // Erases all the items in the range [first, last).  Returns an iterator that
-  // points to the item that comes immediately after the last deleted item in
-  // the list, or end().
-  iterator erase(iterator first, iterator last) {
-    while (first != last && first != end()) {
-      first = erase(first);
-    }
-    return first;
-  }
-
-  // Finds the element with the given key.  Returns an iterator to the
-  // value found, or to end() if the value was not found.  Like a map, this
-  // iterator points to a pair<Key, Value>.
-  iterator find(const Key& key) {
-    typename MapType::iterator found = map_.find(key);
-    if (found == map_.end()) {
-      return end();
-    }
-    return found->second;
-  }
-
-  const_iterator find(const Key& key) const {
-    typename MapType::const_iterator found = map_.find(key);
-    if (found == map_.end()) {
-      return end();
-    }
-    return found->second;
-  }
-
-  // Returns the bounds of a range that includes all the elements in the
-  // container with a key that compares equal to x.
-  std::pair<iterator, iterator> equal_range(const key_type& key) {
-    std::pair<typename MapType::iterator, typename MapType::iterator> eq_range =
-        map_.equal_range(key);
-
-    return std::make_pair(eq_range.first->second, eq_range.second->second);
-  }
-
-  std::pair<const_iterator, const_iterator> equal_range(
-      const key_type& key) const {
-    std::pair<typename MapType::const_iterator,
-        typename MapType::const_iterator> eq_range =
-        map_.equal_range(key);
-    const const_iterator& start_iter = eq_range.first != map_.end() ?
-        eq_range.first->second : end();
-    const const_iterator& end_iter = eq_range.second != map_.end() ?
-        eq_range.second->second : end();
-
-    return std::make_pair(start_iter, end_iter);
-  }
-
-  // Returns the value mapped to key, or an inserted iterator to that position
-  // in the map.
-  Value& operator[](const key_type& key) {
-    return (*((this->insert(std::make_pair(key, Value()))).first)).second;
-  }
-
-  // Inserts an element into the map
-  std::pair<iterator, bool> insert(const std::pair<Key, Value>& pair) {
-    // First make sure the map doesn't have a key with this value.  If it does,
-    // return a pair with an iterator to it, and false indicating that we
-    // didn't insert anything.
-    typename MapType::iterator found = map_.find(pair.first);
-    if (found != map_.end()) return std::make_pair(found->second, false);
-
-    // Otherwise, insert into the list first.
-    list_.push_back(pair);
-
-    // Obtain an iterator to the newly added element.  We do -- instead of -
-    // since list::iterator doesn't implement operator-().
-    typename ListType::iterator last = list_.end();
-    --last;
-
-    CHECK(map_.insert(std::make_pair(pair.first, last)).second)
-        << "Map and list are inconsistent";
-
-    return std::make_pair(last, true);
-  }
-
-  size_type size() const {
-    return list_.size();
-  }
-
-  template <typename... Args>
-  std::pair<iterator, bool> emplace(Args&&... args) {
-    ListType node_donor;
-    auto node_pos =
-        node_donor.emplace(node_donor.end(), std::forward<Args>(args)...);
-    const auto& k = node_pos->first;
-    auto ins = map_.insert({k, node_pos});
-    if (!ins.second)
-      return {ins.first->second, false};
-    list_.splice(list_.end(), node_donor, node_pos);
-    return {ins.first->second, true};
-  }
-
-  void swap(linked_hash_map& other) {
-    map_.swap(other.map_);
-    list_.swap(other.list_);
-  }
-
- private:
-  // The map component, used for speedy lookups
-  MapType map_;
-
-  // The list component, used for maintaining insertion order
-  ListType list_;
-
-  // |map_| contains iterators to |list_|, therefore a default copy constructor
-  // or copy assignment operator would result in an inconsistent state.
-  DISALLOW_COPY_AND_ASSIGN(linked_hash_map);
-};
-
-}  // namespace net
-
-#endif  // NET_BASE_LINKED_HASH_MAP_H_
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index 86a4429..560918f 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -166,7 +166,6 @@
   // '/login' and '/' do not match '/login/en').
   bool IsEquivalentForSecureCookieMatching(const CanonicalCookie& ecc) const;
 
-  void SetSecure(bool is_secure) { secure_ = is_secure; }
   void SetLastAccessDate(const base::Time& date) {
     last_access_date_ = date;
   }
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 30a2fe0..5772e2ac 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -1210,25 +1210,18 @@
 
   // If both SameSiteByDefaultCookies and CookiesWithoutSameSiteMustBeSecure
   // are enabled, non-SameSite cookies without the Secure attribute will be
-  // treated as secure if set from a secure context, or rejected if set from an
-  // insecure context.
+  // rejected.
   if (base::FeatureList::IsEnabled(features::kSameSiteByDefaultCookies) &&
       base::FeatureList::IsEnabled(
           features::kCookiesWithoutSameSiteMustBeSecure) &&
       cc->GetEffectiveSameSite() == CookieSameSite::NO_RESTRICTION &&
       !cc->IsSecure()) {
-    if (!secure_source) {
-      DVLOG(net::cookie_util::kVlogSetCookies)
-          << "SetCookie() rejecting insecure cookie with SameSite=None.";
-      status = CanonicalCookie::CookieInclusionStatus::
-          EXCLUDE_SAMESITE_NONE_INSECURE;
-      MaybeRunCookieCallback(std::move(callback), status);
-      return;
-    }
     DVLOG(net::cookie_util::kVlogSetCookies)
-        << "SetCookie() treating cookie without SameSite restrictions as "
-           "secure.";
-    cc->SetSecure(true);
+        << "SetCookie() rejecting insecure cookie with SameSite=None.";
+    status =
+        CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE;
+    MaybeRunCookieCallback(std::move(callback), status);
+    return;
   }
 
   const std::string key(GetKey(cc->Domain()));
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index ae1a44c..120e04f 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -3273,8 +3273,7 @@
          features::kCookiesWithoutSameSiteMustBeSecure} /* enabled_features */,
         {} /* disabled_features */);
 
-    // Cookie set from a secure URL with SameSite enabled is not forced to be
-    // secure.
+    // Cookie set from a secure URL with SameSite enabled is not rejected.
     result = SetCookieReturnStatus(cm.get(), secure_url, "A=B; SameSite=Lax");
     EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
     CookieList cookies = GetAllCookiesForURL(cm.get(), secure_url);
@@ -3282,8 +3281,8 @@
     EXPECT_EQ(CookieSameSite::LAX_MODE, cookies[0].SameSite());
     EXPECT_FALSE(cookies[0].IsSecure());
 
-    // Cookie set from a secure URL which defaults into LAX_MODE is not forced
-    // to be secure.
+    // Cookie set from a secure URL which defaults into LAX_MODE is not
+    // rejected.
     result = SetCookieReturnStatus(cm.get(), secure_url, "A=B");
     EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
     cookies = GetAllCookiesForURL(cm.get(), secure_url);
@@ -3292,15 +3291,22 @@
     EXPECT_EQ(CookieSameSite::LAX_MODE, cookies[0].GetEffectiveSameSite());
     EXPECT_FALSE(cookies[0].IsSecure());
 
-    // Cookie set from a secure URL with SameSite=None but not specifying Secure
-    // is converted to a secure cookie.
-    result = SetCookieReturnStatus(cm.get(), secure_url, "A=B; SameSite=None");
+    // Cookie set from a secure URL with SameSite=None and Secure is set.
+    result = SetCookieReturnStatus(cm.get(), secure_url,
+                                   "A=B; SameSite=None; Secure");
     EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
     cookies = GetAllCookiesForURL(cm.get(), secure_url);
-    ASSERT_EQ(1u, cookies.size());  // We overwrote the previous cookie.
+    ASSERT_EQ(1u, cookies.size());
     EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookies[0].SameSite());
     EXPECT_TRUE(cookies[0].IsSecure());
 
+    // Cookie set from a secure URL with SameSite=None but not specifying Secure
+    // is rejected.
+    result = SetCookieReturnStatus(cm.get(), secure_url, "A=B; SameSite=None");
+    EXPECT_EQ(
+        CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE,
+        result);
+
     // Cookie set from an insecure URL with SameSite=None (which can't ever be
     // secure because it's an insecure URL) is rejected.
     result =
@@ -3310,7 +3316,7 @@
         result);
 
     // Cookie set from an insecure URL which defaults into LAX_MODE is not
-    // forced to be secure.
+    // rejected.
     result = SetCookieReturnStatus(cm.get(), insecure_url, "A=B");
     EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
     cookies = GetAllCookiesForURL(cm.get(), insecure_url);
@@ -3329,8 +3335,7 @@
         {features::
              kCookiesWithoutSameSiteMustBeSecure} /* disabled_features */);
 
-    // Cookie set from a secure URL with SameSite enabled is not forced to be
-    // secure.
+    // Cookie set from a secure URL with SameSite enabled is not rejected.
     result = SetCookieReturnStatus(cm.get(), secure_url, "A=B; SameSite=Lax");
     EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
     CookieList cookies = GetAllCookiesForURL(cm.get(), secure_url);
@@ -3338,8 +3343,8 @@
     EXPECT_EQ(CookieSameSite::LAX_MODE, cookies[0].SameSite());
     EXPECT_FALSE(cookies[0].IsSecure());
 
-    // Cookie set from a secure URL which defaults into LAX_MODE is not forced
-    // to be secure.
+    // Cookie set from a secure URL which defaults into LAX_MODE is not
+    // rejected.
     result = SetCookieReturnStatus(cm.get(), secure_url, "A=B");
     EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
     cookies = GetAllCookiesForURL(cm.get(), secure_url);
@@ -3348,8 +3353,17 @@
     EXPECT_EQ(CookieSameSite::LAX_MODE, cookies[0].GetEffectiveSameSite());
     EXPECT_FALSE(cookies[0].IsSecure());
 
+    // Cookie set from a secure URL with SameSite=None and Secure is set.
+    result = SetCookieReturnStatus(cm.get(), secure_url,
+                                   "A=B; SameSite=None; Secure");
+    EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
+    cookies = GetAllCookiesForURL(cm.get(), secure_url);
+    ASSERT_EQ(1u, cookies.size());
+    EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookies[0].SameSite());
+    EXPECT_TRUE(cookies[0].IsSecure());
+
     // Cookie set from a secure URL with SameSite=None but not specifying Secure
-    // is NOT converted to a secure cookie.
+    // is NOT rejected.
     result = SetCookieReturnStatus(cm.get(), secure_url, "A=B; SameSite=None");
     EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
     cookies = GetAllCookiesForURL(cm.get(), secure_url);
@@ -3368,7 +3382,7 @@
     EXPECT_FALSE(cookies[0].IsSecure());
 
     // Cookie set from an insecure URL which defaults into LAX_MODE is not
-    // forced to be secure.
+    // rejected.
     result = SetCookieReturnStatus(cm.get(), insecure_url, "A=B");
     EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, result);
     cookies = GetAllCookiesForURL(cm.get(), insecure_url);
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index 853d1c6..4d3ce6c 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -202,11 +202,17 @@
 MDnsClientImpl::Core::Core(base::Clock* clock, base::OneShotTimer* timer)
     : clock_(clock),
       cleanup_timer_(timer),
-      connection_(new MDnsConnection(this)) {}
+      connection_(new MDnsConnection(this)) {
+  DCHECK(cleanup_timer_);
+  DCHECK(!cleanup_timer_->IsRunning());
+}
 
-MDnsClientImpl::Core::~Core() = default;
+MDnsClientImpl::Core::~Core() {
+  cleanup_timer_->Stop();
+}
 
 int MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) {
+  CHECK(!cleanup_timer_->IsRunning());
   return connection_->Init(socket_factory);
 }
 
@@ -425,7 +431,9 @@
                                std::unique_ptr<base::OneShotTimer> timer)
     : clock_(clock), cleanup_timer_(std::move(timer)) {}
 
-MDnsClientImpl::~MDnsClientImpl() = default;
+MDnsClientImpl::~MDnsClientImpl() {
+  StopListening();
+}
 
 int MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) {
   DCHECK(!core_.get());
diff --git a/net/dns/mdns_client_impl.h b/net/dns/mdns_client_impl.h
index 2a4b895..fd911dc 100644
--- a/net/dns/mdns_client_impl.h
+++ b/net/dns/mdns_client_impl.h
@@ -218,10 +218,11 @@
   Core* core() { return core_.get(); }
 
  private:
-  std::unique_ptr<Core> core_;
   base::Clock* clock_;
   std::unique_ptr<base::OneShotTimer> cleanup_timer_;
 
+  std::unique_ptr<Core> core_;
+
   DISALLOW_COPY_AND_ASSIGN(MDnsClientImpl);
 };
 
diff --git a/net/dns/mdns_client_unittest.cc b/net/dns/mdns_client_unittest.cc
index 88b7fe5..b15a762 100644
--- a/net/dns/mdns_client_unittest.cc
+++ b/net/dns/mdns_client_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -12,10 +13,12 @@
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/simple_test_clock.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/timer/mock_timer.h"
+#include "base/timer/timer.h"
 #include "net/base/address_family.h"
 #include "net/base/completion_repeating_callback.h"
 #include "net/base/ip_address.h"
@@ -618,6 +621,36 @@
   timer->Fire();
 }
 
+TEST_F(MDnsTest, StopListening) {
+  ASSERT_TRUE(test_client_->IsListening());
+
+  test_client_->StopListening();
+  EXPECT_FALSE(test_client_->IsListening());
+}
+
+TEST_F(MDnsTest, StopListening_CacheCleanupScheduled) {
+  base::SimpleTestClock clock;
+  // Use a nonzero starting time as a base.
+  clock.SetNow(base::Time() + base::TimeDelta::FromSeconds(1));
+  auto cleanup_timer = std::make_unique<base::MockOneShotTimer>();
+  base::OneShotTimer* cleanup_timer_ptr = cleanup_timer.get();
+
+  test_client_ =
+      std::make_unique<MDnsClientImpl>(&clock, std::move(cleanup_timer));
+  ASSERT_THAT(test_client_->StartListening(&socket_factory_), test::IsOk());
+  ASSERT_TRUE(test_client_->IsListening());
+
+  // Receive one record (privet) with TTL=1s to schedule cleanup.
+  SimulatePacketReceive(kSamplePacket3, sizeof(kSamplePacket3));
+  ASSERT_TRUE(cleanup_timer_ptr->IsRunning());
+
+  test_client_->StopListening();
+  EXPECT_FALSE(test_client_->IsListening());
+
+  // Expect cleanup unscheduled.
+  EXPECT_FALSE(cleanup_timer_ptr->IsRunning());
+}
+
 TEST_F(MDnsTest, MalformedPacket) {
   StrictMock<MockListenerDelegate> delegate_printer;
 
diff --git a/net/docs/proxy.md b/net/docs/proxy.md
index 79449e1..55ae06ac 100644
--- a/net/docs/proxy.md
+++ b/net/docs/proxy.md
@@ -56,3 +56,103 @@
 rules when using a PAC script. Proxy bypass lists only apply to manual
 settings, so the technique above cannot be used to let PAC scripts decide the
 proxy for localhost URLs.
+
+## Evaluating proxy lists (proxy fallback)
+
+Proxy resolution results in a _list_ of proxy servers to use for a given
+request, not just a single proxy server.
+
+For instance, consider this PAC script:
+
+```
+function FindProxyForURL(url, host) {
+    if (host == "www.example.com") {
+        return "PROXY proxy1; HTTPS proxy2; SOCKS5 proxy3";
+    }
+    return "DIRECT";
+}
+
+```
+
+What proxy will Chrome use for connections to `www.example.com`, given that
+we have a choice of 3 separate proxies, each of different type?
+
+Initially, Chrome will try the proxies in order. This means first attempting the
+request through the HTTP WebProxy `proxy1`. If that "fails", the request is
+next attempted through the HTTPS proxy `proxy2`. Lastly if that fails, the request is
+attempted through the SOCKSv5 proxy `proxy3`.
+
+This process is referred to as _proxy fallback_. What constitutes a
+"failure" is described later.
+
+Proxy fallback is stateful. The actual order of proxy attempts made be Chrome
+is influenced by the past responsiveness of proxy servers.
+
+Let's say we request `http://www.example.com/`. Per the PAC script this resolves to:
+
+```
+"PROXY proxy1; HTTPS proxy2; SOCKS5 proxy3"
+```
+
+Chrome will first attempt to issue the request through these proxies in the
+left-to-right order (`proxy1`, `proxy2`, `proxy3`).
+
+Let's say that the attempt through `proxy1` fails, but then the attempt through
+`proxy2` succeeds. Chrome will mark `proxy1` as _bad_ for the next 5 minutes.
+Being marked as _bad_ means that `proxy1` is de-prioritized with respect to other
+proxies options (including DIRECT) that are not marked as bad.
+
+That means the next time `http://www.example.com/` is requested, the effective
+order for proxies to attempt will be:
+
+```
+HTTPS proxy2; SOCKS5 proxy3; "PROXY proxy1"
+```
+
+Conceptually, _bad_ proxies are moved to the end of the list, rather than being
+removed from consideration all together.
+
+What constitutes a "failure" when it comes to triggering proxy fallback depends
+on the proxy type. Generally speaking, only connection level failures
+are deemed eligible for proxy fallback. This includes:
+
+* Failure resolving the proxy server's DNS
+* Failure connecting a TCP socket to the proxy server
+
+(There are some caveats for how HTTPS and QUIC proxies count failures for
+fallback)
+
+Prior to M67, Chrome would consider failures establishing a
+CONNECT tunnel as an error eligible for proxy fallback. This policy [resulted
+in problems](https://bugs.chromium.org/p/chromium/issues/detail?id=680837) for
+deployments whose HTTP proxies intentionally failed certain https:// requests,
+since that necessitates inducing a failure during the CONNECT tunnel
+establishment. The problem would occur when a working proxy fallback option
+like DIRECT was given, since the failing proxy would then be marked as bad.
+
+Currently there are no options to configure proxy fallback (including disabling
+the caching of bad proxies). Future versions of Chrome may [remove caching
+of bad proxies](https://bugs.chromium.org/p/chromium/issues/detail?id=936130)
+to make fallback predictable.
+
+To investigate issues relating to proxy fallback, one can [collect a NetLog
+dump using
+chrome://net-export/](https://dev.chromium.org/for-testers/providing-network-details).
+These logs can then be loaded with the [NetLog
+viewer](https://netlog-viewer.appspot.com/).
+
+There are a few things of interest in the logs:
+
+* The "Proxy" tab will show which proxies (if any) were marked as bad at the
+  time the capture ended.
+* The "Events" tab notes what the resolved proxy list was, and what the
+  re-ordered proxy list was after taking into account bad proxies.
+* The "Events" tab notes when a proxy is marked as bad and why (provided the
+  event occurred while capturing was enabled).
+
+When debugging issues with bad proxies, it is also useful to reset Chrome's
+cache of bad proxies. This can be done by clicking the "Clear bad proxies"
+button on
+[chrome://net-internals/#proxy](chrome://net-internals/#proxy). Note the UI
+will not give feedback that the bad proxies were cleared, however capturing a
+new NetLog dump can confirm it was cleared.
diff --git a/net/http/http_server_properties_impl.h b/net/http/http_server_properties_impl.h
index 78c8cf0b..5ae2d6b 100644
--- a/net/http/http_server_properties_impl.h
+++ b/net/http/http_server_properties_impl.h
@@ -21,7 +21,6 @@
 #include "base/values.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_address.h"
-#include "net/base/linked_hash_map.h"
 #include "net/base/net_export.h"
 #include "net/http/broken_alternative_services.h"
 #include "net/http/http_server_properties.h"
diff --git a/net/quic/platform/impl/quic_containers_impl.h b/net/quic/platform/impl/quic_containers_impl.h
index c7d4de9c..1b619a7 100644
--- a/net/quic/platform/impl/quic_containers_impl.h
+++ b/net/quic/platform/impl/quic_containers_impl.h
@@ -13,7 +13,7 @@
 #include "base/containers/queue.h"
 #include "base/containers/small_map.h"
 #include "net/base/interval_set.h"
-#include "net/base/linked_hash_map.h"
+#include "net/third_party/quiche/src/common/simple_linked_hash_map.h"
 
 namespace quic {
 
@@ -43,7 +43,7 @@
 
 // A map which offers insertion-ordered iteration.
 template <typename Key, typename Value, typename Hash>
-using QuicLinkedHashMapImpl = net::linked_hash_map<Key, Value, Hash>;
+using QuicLinkedHashMapImpl = quiche::SimpleLinkedHashMap<Key, Value, Hash>;
 
 // A map which is faster than (for example) hash_map for a certain number of
 // unique key-value-pair elements, and upgrades itself to unordered_map when
diff --git a/net/quiche/common/platform/impl/quiche_logging_impl.h b/net/quiche/common/platform/impl/quiche_logging_impl.h
new file mode 100644
index 0000000..5362e69
--- /dev/null
+++ b/net/quiche/common/platform/impl/quiche_logging_impl.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_LOGGING_IMPL_H_
+#define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_LOGGING_IMPL_H_
+
+#include "base/logging.h"
+
+#endif  // NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_LOGGING_IMPL_H_
diff --git a/net/quiche/common/platform/impl/quiche_ptr_util_impl.h b/net/quiche/common/platform/impl/quiche_ptr_util_impl.h
new file mode 100644
index 0000000..8f7dd21e
--- /dev/null
+++ b/net/quiche/common/platform/impl/quiche_ptr_util_impl.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_PTR_UTIL_IMPL_H_
+#define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_PTR_UTIL_IMPL_H_
+
+#include <memory>
+
+namespace quiche {
+
+template <typename T, typename... Args>
+std::unique_ptr<T> QuicheMakeUniqueImpl(Args&&... args) {
+  return std::make_unique<T>(std::forward<Args>(args)...);
+}
+
+}  // namespace quiche
+
+#endif  // NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_PTR_UTIL_IMPL_H_
diff --git a/net/quiche/common/platform/impl/quiche_test_impl.h b/net/quiche/common/platform/impl/quiche_test_impl.h
new file mode 100644
index 0000000..11ae28c
--- /dev/null
+++ b/net/quiche/common/platform/impl/quiche_test_impl.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TEST_IMPL_H_
+#define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TEST_IMPL_H_
+
+#include "testing/gmock/include/gmock/gmock.h"  // IWYU pragma: export
+#include "testing/gtest/include/gtest/gtest.h"  // IWYU pragma: export
+
+#endif  // NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TEST_IMPL_H_
diff --git a/net/quiche/common/platform/impl/quiche_unordered_containers_impl.h b/net/quiche/common/platform/impl/quiche_unordered_containers_impl.h
new file mode 100644
index 0000000..fe48f20c
--- /dev/null
+++ b/net/quiche/common/platform/impl/quiche_unordered_containers_impl.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_UNORDERED_CONTAINERS_IMPL_H_
+#define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_UNORDERED_CONTAINERS_IMPL_H_
+
+#include <unordered_map>
+
+namespace quiche {
+
+// The default hasher used by hash tables.
+template <typename Key>
+using QuicheDefaultHasherImpl = std::hash<Key>;
+
+template <typename Key,
+          typename Value,
+          typename Hash,
+          typename Eq =
+              typename std::unordered_map<Key, Value, Hash>::key_equal,
+          typename Alloc =
+              typename std::unordered_map<Key, Value, Hash>::allocator_type>
+using QuicheUnorderedMapImpl = std::unordered_map<Key, Value, Hash, Eq, Alloc>;
+
+}  // namespace quiche
+
+#endif  // NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_UNORDERED_CONTAINERS_IMPL_H_
diff --git a/net/spdy/platform/impl/spdy_containers_impl.h b/net/spdy/platform/impl/spdy_containers_impl.h
index b0dc3803..5792eb7 100644
--- a/net/spdy/platform/impl/spdy_containers_impl.h
+++ b/net/spdy/platform/impl/spdy_containers_impl.h
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/strings/string_piece.h"
-#include "net/base/linked_hash_map.h"
+#include "net/third_party/quiche/src/common/simple_linked_hash_map.h"
 
 namespace spdy {
 
@@ -23,7 +23,7 @@
 using SpdyHashSetImpl = std::unordered_set<ElementType, Hasher, Eq>;
 
 template <typename Key, typename Value, typename Hash>
-using SpdyLinkedHashMapImpl = net::linked_hash_map<Key, Value, Hash>;
+using SpdyLinkedHashMapImpl = quiche::SimpleLinkedHashMap<Key, Value, Hash>;
 
 template <typename T, size_t N, typename A = std::allocator<T>>
 using SpdyInlinedVectorImpl = std::vector<T, A>;
diff --git a/net/test/spawned_test_server/local_test_server_posix.cc b/net/test/spawned_test_server/local_test_server_posix.cc
index 06c2fe28..8c0b2a81 100644
--- a/net/test/spawned_test_server/local_test_server_posix.cc
+++ b/net/test/spawned_test_server/local_test_server_posix.cc
@@ -139,8 +139,8 @@
 
   // Log is useful in the event you want to run a nearby script (e.g. a test) in
   // the same environment as the TestServer.
-  VLOG(1) << "LaunchPython called with PYTHONPATH = "
-          << options.environment["PYTHONPATH"];
+  LOG(ERROR) << "LaunchPython called with PYTHONPATH = "
+             << options.environment["PYTHONPATH"];
 
   // Set CWD to source root.
   if (!base::PathService::Get(base::DIR_SOURCE_ROOT,
@@ -150,6 +150,7 @@
   }
 
   options.fds_to_remap.push_back(std::make_pair(pipefd[1], pipefd[1]));
+  LOG(ERROR) << "Running: " << python_command.GetCommandLineString();
   process_ = base::LaunchProcess(python_command, options);
   if (!process_.IsValid()) {
     LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString();
diff --git a/sandbox/win/tests/validation_tests/unit_tests.cc b/sandbox/win/tests/validation_tests/unit_tests.cc
index 592b6c0..9e99e00e 100644
--- a/sandbox/win/tests/validation_tests/unit_tests.cc
+++ b/sandbox/win/tests/validation_tests/unit_tests.cc
@@ -14,6 +14,10 @@
       return sandbox::DispatchCall(argc, argv);
   }
 
+  // Force binary unduplication for crbug.com/959223.
+  // If you're reading this, it should be safe to remove.
+  DCHECK(argc >= 0);
+
   base::TestSuite test_suite(argc, argv);
   return base::LaunchUnitTests(
       argc,
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index c356e48..1557c633 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -1026,49 +1026,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -3622,50 +3579,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84Z",
-              "device_type": "flo",
-              "os": "Android"
-            }
-          ],
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -6235,50 +6148,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "LMY48I",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -9036,50 +8905,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "LMY49B",
-              "device_type": "flo",
-              "os": "Android"
-            }
-          ],
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -11686,49 +11511,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -14434,50 +14216,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MRA58Z",
-              "device_type": "flo",
-              "os": "Android"
-            }
-          ],
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -19092,49 +18830,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -21776,49 +21471,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
diff --git a/testing/buildbot/chromium.chrome.json b/testing/buildbot/chromium.chrome.json
index 253f7e6..4a269ef 100644
--- a/testing/buildbot/chromium.chrome.json
+++ b/testing/buildbot/chromium.chrome.json
@@ -271,6 +271,23 @@
               "os": "Ubuntu-14.04",
               "pool": "chrome.tests"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "experiment_percentage": 100,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04",
+              "pool": "chrome.tests"
+            }
           ],
           "shards": 10
         },
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 8c0f7b2..d475427 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -818,6 +818,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 21
         },
@@ -2407,6 +2422,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index c33fe87..95671653 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -195,6 +195,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -4817,49 +4832,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -7480,49 +7452,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -9876,6 +9805,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -11275,6 +11219,24 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -12829,6 +12791,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -14166,6 +14143,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -15511,6 +15503,21 @@
         "test": "boringssl_ssl_tests"
       },
       {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
         "args": [
           "--disable-blink-features=HTMLImports,ShadowDOMV0,CustomElementsV0",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_html_imports_polyfill_browser_tests.filter"
@@ -16859,6 +16866,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -18214,6 +18236,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -35288,6 +35325,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 20375d7..bab4392 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -8941,6 +8941,22 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 21
         },
@@ -10524,6 +10540,22 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 21
         },
@@ -12071,6 +12103,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -13670,6 +13717,22 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -17791,6 +17854,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 229944d..29ed2d0 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -2267,6 +2267,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -3867,6 +3882,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -5426,6 +5456,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -6916,6 +6961,22 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -8679,6 +8740,21 @@
             {
               "os": "Ubuntu-16.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
           ],
           "shards": 10
         },
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index f13bd1e..a7f9770 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -402,49 +402,6 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
             "cacheinvalidation_unittests"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -2880,6 +2837,24 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 30
         },
@@ -4513,6 +4488,21 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -5948,6 +5938,24 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 31
         },
@@ -7704,6 +7712,25 @@
               "cpu": "x86-64",
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 25
         },
@@ -9483,6 +9510,25 @@
               "cpu": "x86-64",
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
@@ -11110,6 +11156,24 @@
       },
       {
         "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "args": [
           "--disable-blink-features=HTMLImports,ShadowDOMV0,CustomElementsV0",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_html_imports_polyfill_browser_tests.filter",
           "--test-launcher-print-test-stdio=always"
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index e77cf7d..9969d4ee 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -89,7 +89,6 @@
 
     'android_specific_chromium_gtests': {
       'android_webview_unittests': {},
-      'breakpad_unittests': {},
       'content_shell_test_apk': {
         'swarming': {
           'shards': 3,
@@ -2232,6 +2231,7 @@
     },
 
     'chromium_gtests_for_linux_and_chromeos_only': {
+      'breakpad_unittests': {},
       'dbus_unittests': {},
       'mojo_core_unittests': {},
       'nacl_helper_nonsfi_unittests': {},
diff --git a/testing/buildbot/tryserver.chromium.linux.json b/testing/buildbot/tryserver.chromium.linux.json
index 354605b..a700123 100644
--- a/testing/buildbot/tryserver.chromium.linux.json
+++ b/testing/buildbot/tryserver.chromium.linux.json
@@ -208,6 +208,22 @@
             {
               "os": "Ubuntu-14.04"
             }
+          ]
+        },
+        "test": "breakpad_unittests"
+      },
+      {
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
           ],
           "shards": 10
         },
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index 3af55b8..06b9de6 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -18,9 +18,10 @@
 
 2. Copy the content of the Abseil git repo to //third_party/abseil-cpp.
 
-3. From //third_party/abseil-cpp/ launch ./rename_dynamic_annotations.sh.
-   This script will rewrite dynamic_annotations macros and function inside
-   Abseil in order to avoid ODR violations and macro clashing with Chromium
+3. From //third_party/abseil-cpp/ launch ./rename_annotations.sh.
+   This script will rewrite dynamic_annotations and thread_annotations
+   macros and function inside Abseil in order to avoid ODR violations
+   and macro clashing with Chromium
    (see: https://github.com/abseil/abseil-cpp/issues/122).
 
 Local Modifications:
@@ -30,5 +31,6 @@
 
 * All the BUILD.bazel files has been translated to BUILD.gn files.
 
-* Functions and macros in absl/base/dynamic_annotations.{h,cc} have been renamed
-  to avoid ODR violations (see step 3).
+* Functions and macros in absl/base/dynamic_annotations.{h,cc} and
+  absl/base/thread_annotations.h have been renamed to avoid ODR
+  violations and macro clashes with Chromium (see step 3).
diff --git a/third_party/abseil-cpp/absl/base/call_once_test.cc b/third_party/abseil-cpp/absl/base/call_once_test.cc
index 9c2a0c4..9a5a5c1 100644
--- a/third_party/abseil-cpp/absl/base/call_once_test.cc
+++ b/third_party/abseil-cpp/absl/base/call_once_test.cc
@@ -30,11 +30,11 @@
 
 ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit);
 
-int running_thread_count GUARDED_BY(counters_mu) = 0;
-int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
-int call_once_finished_count GUARDED_BY(counters_mu) = 0;
-int call_once_return_count GUARDED_BY(counters_mu) = 0;
-bool done_blocking GUARDED_BY(counters_mu) = false;
+int running_thread_count ABSL_GUARDED_BY(counters_mu) = 0;
+int call_once_invoke_count ABSL_GUARDED_BY(counters_mu) = 0;
+int call_once_finished_count ABSL_GUARDED_BY(counters_mu) = 0;
+int call_once_return_count ABSL_GUARDED_BY(counters_mu) = 0;
+bool done_blocking ABSL_GUARDED_BY(counters_mu) = false;
 
 // Function to be called from absl::call_once.  Waits for a notification.
 void WaitAndIncrement() {
@@ -60,7 +60,7 @@
 }
 
 // Returns true if all threads are set up for the test.
-bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
+bool ThreadsAreSetup(void*) ABSL_EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
   // All ten threads must be running, and WaitAndIncrement should be blocked.
   return running_thread_count == 10 && call_once_invoke_count == 1;
 }
diff --git a/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc b/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc
index e4030ed..1356167 100644
--- a/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc
+++ b/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc
@@ -203,9 +203,9 @@
 
   base_internal::SpinLock mu;
   // Head of free list, sorted by address
-  AllocList freelist GUARDED_BY(mu);
+  AllocList freelist ABSL_GUARDED_BY(mu);
   // Count of allocated blocks
-  int32_t allocation_count GUARDED_BY(mu);
+  int32_t allocation_count ABSL_GUARDED_BY(mu);
   // flags passed to NewArena
   const uint32_t flags;
   // Result of sysconf(_SC_PAGESIZE)
@@ -215,7 +215,7 @@
   // Smallest allocation block size
   const size_t min_size;
   // PRNG state
-  uint32_t random GUARDED_BY(mu);
+  uint32_t random ABSL_GUARDED_BY(mu);
 };
 
 namespace {
@@ -275,10 +275,10 @@
 static const uintptr_t kMagicUnallocated = ~kMagicAllocated;
 
 namespace {
-class SCOPED_LOCKABLE ArenaLock {
+class ABSL_SCOPED_LOCKABLE ArenaLock {
  public:
   explicit ArenaLock(LowLevelAlloc::Arena *arena)
-      EXCLUSIVE_LOCK_FUNCTION(arena->mu)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(arena->mu)
       : arena_(arena) {
 #ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
     if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
@@ -290,7 +290,7 @@
     arena_->mu.Lock();
   }
   ~ArenaLock() { ABSL_RAW_CHECK(left_, "haven't left Arena region"); }
-  void Leave() UNLOCK_FUNCTION() {
+  void Leave() ABSL_UNLOCK_FUNCTION() {
     arena_->mu.Unlock();
 #ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
     if (mask_valid_) {
diff --git a/third_party/abseil-cpp/absl/base/internal/spinlock.h b/third_party/abseil-cpp/absl/base/internal/spinlock.h
index 4a31639..f05ad83 100644
--- a/third_party/abseil-cpp/absl/base/internal/spinlock.h
+++ b/third_party/abseil-cpp/absl/base/internal/spinlock.h
@@ -47,7 +47,7 @@
 namespace absl {
 namespace base_internal {
 
-class LOCKABLE SpinLock {
+class ABSL_LOCKABLE SpinLock {
  public:
   SpinLock() : lockword_(kSpinLockCooperative) {
     ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
@@ -76,7 +76,7 @@
   ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
 
   // Acquire this SpinLock.
-  inline void Lock() EXCLUSIVE_LOCK_FUNCTION() {
+  inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
     ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
     if (!TryLockImpl()) {
       SlowLock();
@@ -88,7 +88,7 @@
   // acquisition was successful.  If the lock was not acquired, false is
   // returned.  If this SpinLock is free at the time of the call, TryLock
   // will return true with high probability.
-  inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+  inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
     ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
     bool res = TryLockImpl();
     ABSL_TSAN_MUTEX_POST_LOCK(
@@ -98,7 +98,7 @@
   }
 
   // Release this SpinLock, which must be held by the calling thread.
-  inline void Unlock() UNLOCK_FUNCTION() {
+  inline void Unlock() ABSL_UNLOCK_FUNCTION() {
     ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
     uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
     lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
@@ -176,13 +176,13 @@
 
 // Corresponding locker object that arranges to acquire a spinlock for
 // the duration of a C++ scope.
-class SCOPED_LOCKABLE SpinLockHolder {
+class ABSL_SCOPED_LOCKABLE SpinLockHolder {
  public:
-  inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l)
+  inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
       : lock_(l) {
     l->Lock();
   }
-  inline ~SpinLockHolder() UNLOCK_FUNCTION() { lock_->Unlock(); }
+  inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_->Unlock(); }
 
   SpinLockHolder(const SpinLockHolder&) = delete;
   SpinLockHolder& operator=(const SpinLockHolder&) = delete;
diff --git a/third_party/abseil-cpp/absl/base/internal/sysinfo.cc b/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
index 4dd3add..e5e131f 100644
--- a/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
+++ b/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
@@ -333,7 +333,7 @@
 // We set a bit per thread in this array to indicate that an ID is in
 // use. ID 0 is unused because it is the default value returned by
 // pthread_getspecific().
-static std::vector<uint32_t>* tid_array GUARDED_BY(tid_lock) = nullptr;
+static std::vector<uint32_t>* tid_array ABSL_GUARDED_BY(tid_lock) = nullptr;
 static constexpr int kBitsPerWord = 32;  // tid_array is uint32_t.
 
 // Returns the TID to tid_array.
diff --git a/third_party/abseil-cpp/absl/base/thread_annotations.h b/third_party/abseil-cpp/absl/base/thread_annotations.h
index 0b2c306..341f7c28 100644
--- a/third_party/abseil-cpp/absl/base/thread_annotations.h
+++ b/third_party/abseil-cpp/absl/base/thread_annotations.h
@@ -35,18 +35,18 @@
 #define ABSL_BASE_THREAD_ANNOTATIONS_H_
 
 #if defined(__clang__)
-#define THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
+#define ABSL_THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
 #else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op
+#define ABSL_THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op
 #endif
 
-// GUARDED_BY()
+// ABSL_GUARDED_BY()
 //
 // Documents if a shared field or global variable needs to be protected by a
-// mutex. GUARDED_BY() allows the user to specify a particular mutex that
+// mutex. ABSL_GUARDED_BY() allows the user to specify a particular mutex that
 // should be held when accessing the annotated variable.
 //
-// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
+// Although this annotation (and ABSL_PT_GUARDED_BY, below) cannot be applied to
 // local variables, a local variable and its associated mutex can often be
 // combined into a small class or struct, thereby allowing the annotation.
 //
@@ -54,12 +54,12 @@
 //
 //   class Foo {
 //     Mutex mu_;
-//     int p1_ GUARDED_BY(mu_);
+//     int p1_ ABSL_GUARDED_BY(mu_);
 //     ...
 //   };
-#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+#define ABSL_GUARDED_BY(x) ABSL_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
 
-// PT_GUARDED_BY()
+// ABSL_PT_GUARDED_BY()
 //
 // Documents if the memory location pointed to by a pointer should be guarded
 // by a mutex when dereferencing the pointer.
@@ -67,7 +67,7 @@
 // Example:
 //   class Foo {
 //     Mutex mu_;
-//     int *p1_ PT_GUARDED_BY(mu_);
+//     int *p1_ ABSL_PT_GUARDED_BY(mu_);
 //     ...
 //   };
 //
@@ -78,31 +78,31 @@
 //
 //   // `q_`, guarded by `mu1_`, points to a shared memory location that is
 //   // guarded by `mu2_`:
-//   int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
-#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+//   int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
+#define ABSL_PT_GUARDED_BY(x) ABSL_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
 
-// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
+// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
 //
 // Documents the acquisition order between locks that can be held
 // simultaneously by a thread. For any two locks that need to be annotated
 // to establish an acquisition order, only one of them needs the annotation.
-// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
-// and ACQUIRED_BEFORE.)
+// (i.e. You don't have to annotate both locks with both ABSL_ACQUIRED_AFTER
+// and ABSL_ACQUIRED_BEFORE.)
 //
-// As with GUARDED_BY, this is only applicable to mutexes that are shared
+// As with ABSL_GUARDED_BY, this is only applicable to mutexes that are shared
 // fields or global variables.
 //
 // Example:
 //
 //   Mutex m1_;
-//   Mutex m2_ ACQUIRED_AFTER(m1_);
-#define ACQUIRED_AFTER(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+//   Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
+#define ABSL_ACQUIRED_AFTER(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
 
-#define ACQUIRED_BEFORE(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+#define ABSL_ACQUIRED_BEFORE(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
 
-// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
+// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
 //
 // Documents a function that expects a mutex to be held prior to entry.
 // The mutex is expected to be held both on entry to, and exit from, the
@@ -114,77 +114,77 @@
 // concurrently.
 //
 // Generally, non-const methods should be annotated with
-// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
-// SHARED_LOCKS_REQUIRED.
+// ABSL_EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
+// ABSL_SHARED_LOCKS_REQUIRED.
 //
 // Example:
 //
 //   Mutex mu1, mu2;
-//   int a GUARDED_BY(mu1);
-//   int b GUARDED_BY(mu2);
+//   int a ABSL_GUARDED_BY(mu1);
+//   int b ABSL_GUARDED_BY(mu2);
 //
-//   void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
-//   void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
-#define EXCLUSIVE_LOCKS_REQUIRED(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+//   void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
+//   void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
 
-#define SHARED_LOCKS_REQUIRED(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+#define ABSL_SHARED_LOCKS_REQUIRED(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
 
-// LOCKS_EXCLUDED()
+// ABSL_LOCKS_EXCLUDED()
 //
 // Documents the locks acquired in the body of the function. These locks
 // cannot be held when calling this function (as Abseil's `Mutex` locks are
 // non-reentrant).
-#define LOCKS_EXCLUDED(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+#define ABSL_LOCKS_EXCLUDED(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
 
-// LOCK_RETURNED()
+// ABSL_LOCK_RETURNED()
 //
 // Documents a function that returns a mutex without acquiring it.  For example,
 // a public getter method that returns a pointer to a private mutex should
-// be annotated with LOCK_RETURNED.
-#define LOCK_RETURNED(x) \
-  THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+// be annotated with ABSL_LOCK_RETURNED.
+#define ABSL_LOCK_RETURNED(x) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
 
-// LOCKABLE
+// ABSL_LOCKABLE
 //
 // Documents if a class/type is a lockable type (such as the `Mutex` class).
-#define LOCKABLE \
-  THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+#define ABSL_LOCKABLE \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(lockable)
 
-// SCOPED_LOCKABLE
+// ABSL_SCOPED_LOCKABLE
 //
 // Documents if a class does RAII locking (such as the `MutexLock` class).
 // The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
-// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
+// acquired, and the destructor should use `ABSL_UNLOCK_FUNCTION()` with no
 // arguments; the analysis will assume that the destructor unlocks whatever the
 // constructor locked.
-#define SCOPED_LOCKABLE \
-  THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+#define ABSL_SCOPED_LOCKABLE \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
 
-// EXCLUSIVE_LOCK_FUNCTION()
+// ABSL_EXCLUSIVE_LOCK_FUNCTION()
 //
 // Documents functions that acquire a lock in the body of a function, and do
 // not release it.
-#define EXCLUSIVE_LOCK_FUNCTION(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
 
-// SHARED_LOCK_FUNCTION()
+// ABSL_SHARED_LOCK_FUNCTION()
 //
 // Documents functions that acquire a shared (reader) lock in the body of a
 // function, and do not release it.
-#define SHARED_LOCK_FUNCTION(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+#define ABSL_SHARED_LOCK_FUNCTION(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
 
-// UNLOCK_FUNCTION()
+// ABSL_UNLOCK_FUNCTION()
 //
 // Documents functions that expect a lock to be held on entry to the function,
 // and release it in the body of the function.
-#define UNLOCK_FUNCTION(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+#define ABSL_UNLOCK_FUNCTION(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
 
-// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
+// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
 //
 // Documents functions that try to acquire a lock, and return success or failure
 // (or a non-boolean value that can be interpreted as a boolean).
@@ -192,60 +192,60 @@
 // success, or `false` for functions that return `false` on success. The second
 // argument specifies the mutex that is locked on success. If unspecified, this
 // mutex is assumed to be `this`.
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
 
-#define SHARED_TRYLOCK_FUNCTION(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
 
-// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
+// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
 //
 // Documents functions that dynamically check to see if a lock is held, and fail
 // if it is not held.
-#define ASSERT_EXCLUSIVE_LOCK(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
 
-#define ASSERT_SHARED_LOCK(...) \
-  THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+#define ABSL_ASSERT_SHARED_LOCK(...) \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
 
-// NO_THREAD_SAFETY_ANALYSIS
+// ABSL_NO_THREAD_SAFETY_ANALYSIS
 //
 // Turns off thread safety checking within the body of a particular function.
 // This annotation is used to mark functions that are known to be correct, but
 // the locking behavior is more complicated than the analyzer can handle.
-#define NO_THREAD_SAFETY_ANALYSIS \
-  THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
+  ABSL_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
 
 //------------------------------------------------------------------------------
 // Tool-Supplied Annotations
 //------------------------------------------------------------------------------
 
-// TS_UNCHECKED should be placed around lock expressions that are not valid
+// ABSL_TS_UNCHECKED should be placed around lock expressions that are not valid
 // C++ syntax, but which are present for documentation purposes.  These
 // annotations will be ignored by the analysis.
-#define TS_UNCHECKED(x) ""
+#define ABSL_TS_UNCHECKED(x) ""
 
-// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
+// ABSL_TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
 // It is used by automated tools to mark and disable invalid expressions.
-// The annotation should either be fixed, or changed to TS_UNCHECKED.
-#define TS_FIXME(x) ""
+// The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED.
+#define ABSL_TS_FIXME(x) ""
 
-// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
+// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
 // a particular function.  However, this attribute is used to mark functions
 // that are incorrect and need to be fixed.  It is used by automated tools to
 // avoid breaking the build when the analysis is updated.
 // Code owners are expected to eventually fix the routine.
-#define NO_THREAD_SAFETY_ANALYSIS_FIXME  NO_THREAD_SAFETY_ANALYSIS
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME  ABSL_NO_THREAD_SAFETY_ANALYSIS
 
-// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
+// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a ABSL_GUARDED_BY
 // annotation that needs to be fixed, because it is producing thread safety
-// warning.  It disables the GUARDED_BY.
-#define GUARDED_BY_FIXME(x)
+// warning.  It disables the ABSL_GUARDED_BY.
+#define ABSL_GUARDED_BY_FIXME(x)
 
 // Disables warnings for a single read operation.  This can be used to avoid
 // warnings when it is known that the read is not actually involved in a race,
 // but the compiler cannot confirm that.
-#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
+#define ABSL_TS_UNCHECKED_READ(x) thread_safety_analysis::absl_ts_unchecked_read(x)
 
 
 namespace thread_safety_analysis {
@@ -253,12 +253,12 @@
 // Takes a reference to a guarded data member, and returns an unguarded
 // reference.
 template <typename T>
-inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
+inline const T& absl_ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   return v;
 }
 
 template <typename T>
-inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
+inline T& absl_ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   return v;
 }
 
diff --git a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
index a308e78..41121754 100644
--- a/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
+++ b/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
@@ -65,7 +65,7 @@
 
   // Puts the object into a clean state, fills in the logically `const` members,
   // blocking for any readers that are currently sampling the object.
-  void PrepareForSampling() EXCLUSIVE_LOCKS_REQUIRED(init_mu);
+  void PrepareForSampling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
 
   // These fields are mutated by the various Record* APIs and need to be
   // thread-safe.
@@ -83,7 +83,7 @@
   // prevents races with sampling and resurrecting an object.
   absl::Mutex init_mu;
   HashtablezInfo* next;
-  HashtablezInfo* dead GUARDED_BY(init_mu);
+  HashtablezInfo* dead ABSL_GUARDED_BY(init_mu);
 
   // All of the fields below are set by `PrepareForSampling`, they must not be
   // mutated in `Record*` functions.  They are logically `const` in that sense.
diff --git a/third_party/abseil-cpp/absl/synchronization/barrier.h b/third_party/abseil-cpp/absl/synchronization/barrier.h
index 23bb2f5..cb5d821 100644
--- a/third_party/abseil-cpp/absl/synchronization/barrier.h
+++ b/third_party/abseil-cpp/absl/synchronization/barrier.h
@@ -69,8 +69,8 @@
 
  private:
   Mutex lock_;
-  int num_to_block_ GUARDED_BY(lock_);
-  int num_to_exit_ GUARDED_BY(lock_);
+  int num_to_block_ ABSL_GUARDED_BY(lock_);
+  int num_to_exit_ ABSL_GUARDED_BY(lock_);
 };
 
 }  // namespace absl
diff --git a/third_party/abseil-cpp/absl/synchronization/blocking_counter.h b/third_party/abseil-cpp/absl/synchronization/blocking_counter.h
index 4c66e0a..77560fc0 100644
--- a/third_party/abseil-cpp/absl/synchronization/blocking_counter.h
+++ b/third_party/abseil-cpp/absl/synchronization/blocking_counter.h
@@ -88,8 +88,8 @@
 
  private:
   Mutex lock_;
-  int count_ GUARDED_BY(lock_);
-  int num_waiting_ GUARDED_BY(lock_);
+  int count_ ABSL_GUARDED_BY(lock_);
+  int num_waiting_ ABSL_GUARDED_BY(lock_);
 };
 
 }  // namespace absl
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/thread_pool.h b/third_party/abseil-cpp/absl/synchronization/internal/thread_pool.h
index 7f458f5..a00f2be 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/thread_pool.h
+++ b/third_party/abseil-cpp/absl/synchronization/internal/thread_pool.h
@@ -60,7 +60,7 @@
   }
 
  private:
-  bool WorkAvailable() const EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+  bool WorkAvailable() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
     return !queue_.empty();
   }
 
@@ -81,7 +81,7 @@
   }
 
   absl::Mutex mu_;
-  std::queue<std::function<void()>> queue_ GUARDED_BY(mu_);
+  std::queue<std::function<void()>> queue_ ABSL_GUARDED_BY(mu_);
   std::vector<std::thread> threads_;
 };
 
diff --git a/third_party/abseil-cpp/absl/synchronization/lifetime_test.cc b/third_party/abseil-cpp/absl/synchronization/lifetime_test.cc
index 0279c8f8..34b8875 100644
--- a/third_party/abseil-cpp/absl/synchronization/lifetime_test.cc
+++ b/third_party/abseil-cpp/absl/synchronization/lifetime_test.cc
@@ -143,11 +143,11 @@
 // constructors of globals "happen at link time"; memory is pre-initialized,
 // before the constructors of either grab_lock or check_still_locked are run.)
 extern absl::Mutex const_init_sanity_mutex;
-OnConstruction grab_lock([]() NO_THREAD_SAFETY_ANALYSIS {
+OnConstruction grab_lock([]() ABSL_NO_THREAD_SAFETY_ANALYSIS {
   const_init_sanity_mutex.Lock();
 });
 ABSL_CONST_INIT absl::Mutex const_init_sanity_mutex(absl::kConstInit);
-OnConstruction check_still_locked([]() NO_THREAD_SAFETY_ANALYSIS {
+OnConstruction check_still_locked([]() ABSL_NO_THREAD_SAFETY_ANALYSIS {
   const_init_sanity_mutex.AssertHeld();
   const_init_sanity_mutex.Unlock();
 });
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.cc b/third_party/abseil-cpp/absl/synchronization/mutex.cc
index 97c59198..ac2e2b9 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.cc
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.cc
@@ -207,8 +207,8 @@
     absl::base_internal::kLinkerInitialized);
 
 // graph used to detect deadlocks.
-static GraphCycles *deadlock_graph GUARDED_BY(deadlock_graph_mu)
-    PT_GUARDED_BY(deadlock_graph_mu);
+static GraphCycles *deadlock_graph ABSL_GUARDED_BY(deadlock_graph_mu)
+    ABSL_PT_GUARDED_BY(deadlock_graph_mu);
 
 //------------------------------------------------------------------
 // An event mechanism for debugging mutex use.
@@ -279,10 +279,10 @@
 
 static struct SynchEvent {     // this is a trivial hash table for the events
   // struct is freed when refcount reaches 0
-  int refcount GUARDED_BY(synch_event_mu);
+  int refcount ABSL_GUARDED_BY(synch_event_mu);
 
   // buckets have linear, 0-terminated  chains
-  SynchEvent *next GUARDED_BY(synch_event_mu);
+  SynchEvent *next ABSL_GUARDED_BY(synch_event_mu);
 
   // Constant after initialization
   uintptr_t masked_addr;  // object at this address is called "name"
@@ -296,7 +296,7 @@
 
   // Constant after initialization
   char name[1];         // actually longer---null-terminated std::string
-} *synch_event[kNSynchEvent] GUARDED_BY(synch_event_mu);
+} *synch_event[kNSynchEvent] ABSL_GUARDED_BY(synch_event_mu);
 
 // Ensure that the object at "addr" has a SynchEvent struct associated with it,
 // set "bits" in the word there (waiting until lockbit is clear before doing
@@ -1139,7 +1139,7 @@
 }
 
 static GraphId GetGraphIdLocked(Mutex *mu)
-    EXCLUSIVE_LOCKS_REQUIRED(deadlock_graph_mu) {
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(deadlock_graph_mu) {
   if (!deadlock_graph) {  // (re)create the deadlock graph.
     deadlock_graph =
         new (base_internal::LowLevelAlloc::Alloc(sizeof(*deadlock_graph)))
@@ -1148,7 +1148,7 @@
   return deadlock_graph->GetId(mu);
 }
 
-static GraphId GetGraphId(Mutex *mu) LOCKS_EXCLUDED(deadlock_graph_mu) {
+static GraphId GetGraphId(Mutex *mu) ABSL_LOCKS_EXCLUDED(deadlock_graph_mu) {
   deadlock_graph_mu.Lock();
   GraphId id = GetGraphIdLocked(mu);
   deadlock_graph_mu.Unlock();
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.h b/third_party/abseil-cpp/absl/synchronization/mutex.h
index c38e356..af770e85 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.h
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.h
@@ -135,7 +135,7 @@
 //
 // See also `MutexLock`, below, for scoped `Mutex` acquisition.
 
-class LOCKABLE Mutex {
+class ABSL_LOCKABLE Mutex {
  public:
   // Creates a `Mutex` that is not held by anyone. This constructor is
   // typically used for Mutexes allocated on the heap or the stack.
@@ -164,27 +164,27 @@
   //
   // Blocks the calling thread, if necessary, until this `Mutex` is free, and
   // then acquires it exclusively. (This lock is also known as a "write lock.")
-  void Lock() EXCLUSIVE_LOCK_FUNCTION();
+  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION();
 
   // Mutex::Unlock()
   //
   // Releases this `Mutex` and returns it from the exclusive/write state to the
   // free state. Caller must hold the `Mutex` exclusively.
-  void Unlock() UNLOCK_FUNCTION();
+  void Unlock() ABSL_UNLOCK_FUNCTION();
 
   // Mutex::TryLock()
   //
   // If the mutex can be acquired without blocking, does so exclusively and
   // returns `true`. Otherwise, returns `false`. Returns `true` with high
   // probability if the `Mutex` was free.
-  bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
+  bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
 
   // Mutex::AssertHeld()
   //
   // Return immediately if this thread holds the `Mutex` exclusively (in write
   // mode). Otherwise, may report an error (typically by crashing with a
   // diagnostic), or may return immediately.
-  void AssertHeld() const ASSERT_EXCLUSIVE_LOCK();
+  void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK();
 
   // ---------------------------------------------------------------------------
   // Reader-Writer Locking
@@ -225,28 +225,28 @@
   // `ReaderLock()` will block if some other thread has an exclusive/writer lock
   // on the mutex.
 
-  void ReaderLock() SHARED_LOCK_FUNCTION();
+  void ReaderLock() ABSL_SHARED_LOCK_FUNCTION();
 
   // Mutex::ReaderUnlock()
   //
   // Releases a read share of this `Mutex`. `ReaderUnlock` may return a mutex to
   // the free state if this thread holds the last reader lock on the mutex. Note
   // that you cannot call `ReaderUnlock()` on a mutex held in write mode.
-  void ReaderUnlock() UNLOCK_FUNCTION();
+  void ReaderUnlock() ABSL_UNLOCK_FUNCTION();
 
   // Mutex::ReaderTryLock()
   //
   // If the mutex can be acquired without blocking, acquires this mutex for
   // shared access and returns `true`. Otherwise, returns `false`. Returns
   // `true` with high probability if the `Mutex` was free or shared.
-  bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true);
+  bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true);
 
   // Mutex::AssertReaderHeld()
   //
   // Returns immediately if this thread holds the `Mutex` in at least shared
   // mode (read mode). Otherwise, may report an error (typically by
   // crashing with a diagnostic), or may return immediately.
-  void AssertReaderHeld() const ASSERT_SHARED_LOCK();
+  void AssertReaderHeld() const ABSL_ASSERT_SHARED_LOCK();
 
   // Mutex::WriterLock()
   // Mutex::WriterUnlock()
@@ -257,11 +257,11 @@
   // These methods may be used (along with the complementary `Reader*()`
   // methods) to distingish simple exclusive `Mutex` usage (`Lock()`,
   // etc.) from reader/writer lock usage.
-  void WriterLock() EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
+  void WriterLock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
 
-  void WriterUnlock() UNLOCK_FUNCTION() { this->Unlock(); }
+  void WriterUnlock() ABSL_UNLOCK_FUNCTION() { this->Unlock(); }
 
-  bool WriterTryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+  bool WriterTryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
     return this->TryLock();
   }
 
@@ -315,11 +315,11 @@
   // be acquired, then atomically acquires this `Mutex`. `LockWhen()` is
   // logically equivalent to `*Lock(); Await();` though they may have different
   // performance characteristics.
-  void LockWhen(const Condition &cond) EXCLUSIVE_LOCK_FUNCTION();
+  void LockWhen(const Condition &cond) ABSL_EXCLUSIVE_LOCK_FUNCTION();
 
-  void ReaderLockWhen(const Condition &cond) SHARED_LOCK_FUNCTION();
+  void ReaderLockWhen(const Condition &cond) ABSL_SHARED_LOCK_FUNCTION();
 
-  void WriterLockWhen(const Condition &cond) EXCLUSIVE_LOCK_FUNCTION() {
+  void WriterLockWhen(const Condition &cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() {
     this->LockWhen(cond);
   }
 
@@ -361,11 +361,11 @@
   //
   // Negative timeouts are equivalent to a zero timeout.
   bool LockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
-      EXCLUSIVE_LOCK_FUNCTION();
+      ABSL_EXCLUSIVE_LOCK_FUNCTION();
   bool ReaderLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
-      SHARED_LOCK_FUNCTION();
+      ABSL_SHARED_LOCK_FUNCTION();
   bool WriterLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
-      EXCLUSIVE_LOCK_FUNCTION() {
+      ABSL_EXCLUSIVE_LOCK_FUNCTION() {
     return this->LockWhenWithTimeout(cond, timeout);
   }
 
@@ -381,11 +381,11 @@
   //
   // Deadlines in the past are equivalent to an immediate deadline.
   bool LockWhenWithDeadline(const Condition &cond, absl::Time deadline)
-      EXCLUSIVE_LOCK_FUNCTION();
+      ABSL_EXCLUSIVE_LOCK_FUNCTION();
   bool ReaderLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
-      SHARED_LOCK_FUNCTION();
+      ABSL_SHARED_LOCK_FUNCTION();
   bool WriterLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
-      EXCLUSIVE_LOCK_FUNCTION() {
+      ABSL_EXCLUSIVE_LOCK_FUNCTION() {
     return this->LockWhenWithDeadline(cond, deadline);
   }
 
@@ -535,9 +535,9 @@
 // private:
 //   Mutex lock_;
 // };
-class SCOPED_LOCKABLE MutexLock {
+class ABSL_SCOPED_LOCKABLE MutexLock {
  public:
-  explicit MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
+  explicit MutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
     this->mu_->Lock();
   }
 
@@ -546,7 +546,7 @@
   MutexLock& operator=(const MutexLock&) = delete;
   MutexLock& operator=(MutexLock&&) = delete;
 
-  ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); }
+  ~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); }
 
  private:
   Mutex *const mu_;
@@ -556,9 +556,9 @@
 //
 // The `ReaderMutexLock` is a helper class, like `MutexLock`, which acquires and
 // releases a shared lock on a `Mutex` via RAII.
-class SCOPED_LOCKABLE ReaderMutexLock {
+class ABSL_SCOPED_LOCKABLE ReaderMutexLock {
  public:
-  explicit ReaderMutexLock(Mutex *mu) SHARED_LOCK_FUNCTION(mu)
+  explicit ReaderMutexLock(Mutex *mu) ABSL_SHARED_LOCK_FUNCTION(mu)
       :  mu_(mu) {
     mu->ReaderLock();
   }
@@ -568,7 +568,7 @@
   ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
   ReaderMutexLock& operator=(ReaderMutexLock&&) = delete;
 
-  ~ReaderMutexLock() UNLOCK_FUNCTION() {
+  ~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() {
     this->mu_->ReaderUnlock();
   }
 
@@ -580,9 +580,9 @@
 //
 // The `WriterMutexLock` is a helper class, like `MutexLock`, which acquires and
 // releases a write (exclusive) lock on a `Mutex` via RAII.
-class SCOPED_LOCKABLE WriterMutexLock {
+class ABSL_SCOPED_LOCKABLE WriterMutexLock {
  public:
-  explicit WriterMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+  explicit WriterMutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
       : mu_(mu) {
     mu->WriterLock();
   }
@@ -592,7 +592,7 @@
   WriterMutexLock& operator=(const WriterMutexLock&) = delete;
   WriterMutexLock& operator=(WriterMutexLock&&) = delete;
 
-  ~WriterMutexLock() UNLOCK_FUNCTION() {
+  ~WriterMutexLock() ABSL_UNLOCK_FUNCTION() {
     this->mu_->WriterUnlock();
   }
 
@@ -633,7 +633,7 @@
 // Example:
 //
 //   // assume count_ is not internal reference count
-//   int count_ GUARDED_BY(mu_);
+//   int count_ ABSL_GUARDED_BY(mu_);
 //
 //   mu_.LockWhen(Condition(+[](int* count) { return *count == 0; },
 //         &count_));
@@ -860,11 +860,11 @@
 // MutexLockMaybe
 //
 // MutexLockMaybe is like MutexLock, but is a no-op when mu is null.
-class SCOPED_LOCKABLE MutexLockMaybe {
+class ABSL_SCOPED_LOCKABLE MutexLockMaybe {
  public:
-  explicit MutexLockMaybe(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+  explicit MutexLockMaybe(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
       : mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } }
-  ~MutexLockMaybe() UNLOCK_FUNCTION() {
+  ~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() {
     if (this->mu_ != nullptr) { this->mu_->Unlock(); }
   }
  private:
@@ -879,17 +879,17 @@
 //
 // ReleasableMutexLock is like MutexLock, but permits `Release()` of its
 // mutex before destruction. `Release()` may be called at most once.
-class SCOPED_LOCKABLE ReleasableMutexLock {
+class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
  public:
-  explicit ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+  explicit ReleasableMutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
       : mu_(mu) {
     this->mu_->Lock();
   }
-  ~ReleasableMutexLock() UNLOCK_FUNCTION() {
+  ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
     if (this->mu_ != nullptr) { this->mu_->Unlock(); }
   }
 
-  void Release() UNLOCK_FUNCTION();
+  void Release() ABSL_UNLOCK_FUNCTION();
 
  private:
   Mutex *mu_;
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex_test.cc b/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
index 10211229..6df0a45c 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
+++ b/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
@@ -425,10 +425,10 @@
   // Use a struct so the lock annotations apply.
   struct {
     absl::Mutex barrier_mu;
-    bool barrier GUARDED_BY(barrier_mu) = false;
+    bool barrier ABSL_GUARDED_BY(barrier_mu) = false;
 
     absl::Mutex release_mu;
-    bool release GUARDED_BY(release_mu) = false;
+    bool release ABSL_GUARDED_BY(release_mu) = false;
     absl::CondVar released_cv;
   } state;
 
@@ -466,10 +466,10 @@
   // Use a struct so the lock annotations apply.
   struct {
     absl::Mutex barrier_mu;
-    bool barrier GUARDED_BY(barrier_mu) = false;
+    bool barrier ABSL_GUARDED_BY(barrier_mu) = false;
 
     absl::Mutex release_mu;
-    bool release GUARDED_BY(release_mu) = false;
+    bool release ABSL_GUARDED_BY(release_mu) = false;
     absl::CondVar released_cv;
   } state;
 
@@ -770,7 +770,7 @@
 
 // Test for reader counter being decremented incorrectly by waiter
 // with false condition.
-TEST(Mutex, MutexReaderDecrementBug) NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, MutexReaderDecrementBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   ReaderDecrementBugStruct x;
   x.cond = false;
   x.waiting_on_cond = false;
@@ -815,7 +815,7 @@
 
 // Test that we correctly handle the situation when a lock is
 // held and then destroyed (w/o unlocking).
-TEST(Mutex, LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   for (int i = 0; i != 10; i++) {
     // Create, lock and destroy 10 locks.
     const int kNumLocks = 10;
@@ -1087,11 +1087,11 @@
   absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
 }
 
-// This test is tagged with NO_THREAD_SAFETY_ANALYSIS because the
+// This test is tagged with ABSL_NO_THREAD_SAFETY_ANALYSIS because the
 // annotation-based static thread-safety analysis is not currently
 // predicate-aware and cannot tell if the two for-loops that acquire and
 // release the locks have the same predicates.
-TEST(Mutex, DeadlockDetectorStessTest) NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, DeadlockDetectorStessTest) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   // Stress test: Here we create a large number of locks and use all of them.
   // If a deadlock detector keeps a full graph of lock acquisition order,
   // it will likely be too slow for this test to pass.
@@ -1109,7 +1109,7 @@
   }
 }
 
-TEST(Mutex, DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, DeadlockIdBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   // Test a scenario where a cached deadlock graph node id in the
   // list of held locks is not invalidated when the corresponding
   // mutex is deleted.
diff --git a/third_party/abseil-cpp/absl/time/clock.cc b/third_party/abseil-cpp/absl/time/clock.cc
index fa0ed34..396c55f 100644
--- a/third_party/abseil-cpp/absl/time/clock.cc
+++ b/third_party/abseil-cpp/absl/time/clock.cc
@@ -385,7 +385,7 @@
 // TODO(absl-team): Remove this attribute when our compiler is smart enough
 // to do the right thing.
 ABSL_ATTRIBUTE_NOINLINE
-static int64_t GetCurrentTimeNanosSlowPath() LOCKS_EXCLUDED(lock) {
+static int64_t GetCurrentTimeNanosSlowPath() ABSL_LOCKS_EXCLUDED(lock) {
   // Serialize access to slow-path.  Fast-path readers are not blocked yet, and
   // code below must not modify last_sample until the seqlock is acquired.
   lock.Lock();
@@ -430,7 +430,7 @@
 static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
                                  uint64_t delta_cycles,
                                  const struct TimeSample *sample)
-    EXCLUSIVE_LOCKS_REQUIRED(lock) {
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock) {
   uint64_t estimated_base_ns = now_ns;
   uint64_t lock_value = SeqAcquire(&seq);  // acquire seqlock to block readers
 
diff --git a/third_party/abseil-cpp/rename_dynamic_annotations.sh b/third_party/abseil-cpp/rename_annotations.sh
similarity index 75%
rename from third_party/abseil-cpp/rename_dynamic_annotations.sh
rename to third_party/abseil-cpp/rename_annotations.sh
index b39017f9..fa2de4d 100755
--- a/third_party/abseil-cpp/rename_dynamic_annotations.sh
+++ b/third_party/abseil-cpp/rename_annotations.sh
@@ -1,14 +1,15 @@
 #!/bin/bash
 
 # This script renames all the functions and the macros defined in
-# absl/base/dynamic_annotations.{h,cc}.
+# absl/base/dynamic_annotations.{h,cc} and absl/base/thread_annotations.h.
 #
 # Chromium's dynamic_annotations live in //base/third_party/dynamic_annotations
-# and the are in conflict with Abseil's dynamic_annotations (ODR violations and
-# macro clashing).
+# and its //base contains a copy of thread_annotations.h which conflict with
+# Abseil's versions (ODR violations and macro clashing).
 # In order to avoid problems in Chromium, this copy of Abseil has its own
-# dynamic_annotations renamed.
+# dynamic_annotations and thread_annotations renamed.
 
+# -------------------------- dynamic_annotations -------------------------
 for w in \
   AnnotateBarrierDestroy \
   AnnotateBarrierInit \
@@ -125,3 +126,40 @@
 ; do
   find absl/ -type f -exec sed -i "s/\b$w\b/ABSL_$w/g" {} \;
 done
+
+# -------------------------- thread_annotations -------------------------
+
+for w in \
+  ts_unchecked_read \
+; do
+  find absl/ -type f -exec sed -i "s/\b$w\b/absl_$w/g" {} \;
+done
+
+for w in \
+  THREAD_ANNOTATION_ATTRIBUTE__ \
+  GUARDED_BY \
+  PT_GUARDED_BY \
+  ACQUIRED_AFTER \
+  ACQUIRED_BEFORE \
+  EXCLUSIVE_LOCKS_REQUIRED \
+  SHARED_LOCKS_REQUIRED \
+  LOCKS_EXCLUDED \
+  LOCK_RETURNED \
+  LOCKABLE \
+  SCOPED_LOCKABLE \
+  EXCLUSIVE_LOCK_FUNCTION \
+  SHARED_LOCK_FUNCTION \
+  UNLOCK_FUNCTION \
+  EXCLUSIVE_TRYLOCK_FUNCTION \
+  SHARED_TRYLOCK_FUNCTION \
+  ASSERT_EXCLUSIVE_LOCK \
+  ASSERT_SHARED_LOCK \
+  NO_THREAD_SAFETY_ANALYSIS \
+  TS_UNCHECKED \
+  TS_FIXME \
+  NO_THREAD_SAFETY_ANALYSIS_FIXME \
+  GUARDED_BY_FIXME \
+  TS_UNCHECKED_READ \
+; do
+  find absl/ -type f -exec sed -i "s/\b$w\b/ABSL_$w/g" {} \;
+done
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 29e1e96..18608c8 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -1761,7 +1761,6 @@
   kInputTypeFileSecureOriginOpenChooser = 2324,
   kInputTypeFileInsecureOriginOpenChooser = 2325,
   kBasicShapeEllipseNoRadius = 2326,
-  kBasicShapeEllipseOneRadius = 2327,
   kBasicShapeEllipseTwoRadius = 2328,
   kTemporalInputTypeChooserByTrustedClick = 2329,
   kTemporalInputTypeChooserByUntrustedClick = 2330,
diff --git a/third_party/blink/public/platform/web_input_event.h b/third_party/blink/public/platform/web_input_event.h
index 1c09a6b..2bff74e 100644
--- a/third_party/blink/public/platform/web_input_event.h
+++ b/third_party/blink/public/platform/web_input_event.h
@@ -190,7 +190,7 @@
     kPointerTypeFirst = kPointerDown,
     kPointerUp,
     kPointerMove,
-    kPointerRawMove,  // To be only used within blink.
+    kPointerRawUpdate,  // To be only used within blink.
     kPointerCancel,
     kPointerCausedUaAction,
     kPointerTypeLast = kPointerCausedUaAction,
@@ -412,7 +412,7 @@
       CASE_TYPE(PointerDown);
       CASE_TYPE(PointerUp);
       CASE_TYPE(PointerMove);
-      CASE_TYPE(PointerRawMove);
+      CASE_TYPE(PointerRawUpdate);
       CASE_TYPE(PointerCancel);
       CASE_TYPE(PointerCausedUaAction);
     }
diff --git a/third_party/blink/public/web/web_settings.h b/third_party/blink/public/web/web_settings.h
index 6076ae1d..88ac9e36 100644
--- a/third_party/blink/public/web/web_settings.h
+++ b/third_party/blink/public/web/web_settings.h
@@ -264,7 +264,6 @@
   virtual void SetValidationMessageTimerMagnification(int) = 0;
   virtual void SetViewportEnabled(bool) = 0;
   virtual void SetViewportMetaEnabled(bool) = 0;
-  virtual void SetViewportMetaLayoutSizeQuirk(bool) = 0;
   virtual void SetViewportMetaMergeContentQuirk(bool) = 0;
   virtual void SetViewportMetaNonUserScalableQuirk(bool) = 0;
   virtual void SetViewportMetaZeroValuesQuirk(bool) = 0;
diff --git a/third_party/blink/public/web/web_widget_client.h b/third_party/blink/public/web/web_widget_client.h
index 4491ab7..6b92ded 100644
--- a/third_party/blink/public/web/web_widget_client.h
+++ b/third_party/blink/public/web/web_widget_client.h
@@ -170,8 +170,8 @@
   // or navigate.
   virtual void SetOverscrollBehavior(const cc::OverscrollBehavior&) {}
 
-  // Called to update if pointerrawmove events should be sent.
-  virtual void HasPointerRawMoveEventHandlers(bool) {}
+  // Called to update if pointerrawupdate events should be sent.
+  virtual void HasPointerRawUpdateEventHandlers(bool) {}
 
   // Called to update if touch events should be sent.
   virtual void HasTouchEventHandlers(bool) {}
diff --git a/third_party/blink/renderer/bindings/modules/v8/generated.gni b/third_party/blink/renderer/bindings/modules/v8/generated.gni
index 7c37c6d2..ff6dc7e 100644
--- a/third_party/blink/renderer/bindings/modules/v8/generated.gni
+++ b/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -24,8 +24,6 @@
   "$bindings_modules_v8_output_dir/array_buffer_view_or_blob_or_string_or_form_data.h",
   "$bindings_modules_v8_output_dir/audio_context_latency_category_or_double.cc",
   "$bindings_modules_v8_output_dir/audio_context_latency_category_or_double.h",
-  "$bindings_modules_v8_output_dir/blob_or_readable_stream.cc",
-  "$bindings_modules_v8_output_dir/blob_or_readable_stream.h",
   "$bindings_modules_v8_output_dir/boolean_or_constrain_boolean_parameters.cc",
   "$bindings_modules_v8_output_dir/boolean_or_constrain_boolean_parameters.h",
   "$bindings_modules_v8_output_dir/boolean_or_media_track_constraints.cc",
diff --git a/third_party/blink/renderer/core/css/css_basic_shape_values.cc b/third_party/blink/renderer/core/css/css_basic_shape_values.cc
index 4c5f6f3..2639c9e 100644
--- a/third_party/blink/renderer/core/css/css_basic_shape_values.cc
+++ b/third_party/blink/renderer/core/css/css_basic_shape_values.cc
@@ -191,25 +191,24 @@
   String radius_x;
   String radius_y;
   if (radius_x_) {
+    DCHECK(radius_y_);
+
     auto* radius_x_identifier_value =
         DynamicTo<CSSIdentifierValue>(radius_x_.Get());
-    bool should_serialize_radius_x_value =
-        !(radius_x_identifier_value &&
-          radius_x_identifier_value->GetValueID() == CSSValueID::kClosestSide);
-    bool should_serialize_radius_y_value = false;
+    bool radius_x_closest_side =
+        (radius_x_identifier_value &&
+         radius_x_identifier_value->GetValueID() == CSSValueID::kClosestSide);
 
-    if (radius_y_) {
-      auto* radius_y_identifier_value =
-          DynamicTo<CSSIdentifierValue>(radius_y_.Get());
-      should_serialize_radius_y_value = !(
-          radius_y_identifier_value &&
-          radius_y_identifier_value->GetValueID() == CSSValueID::kClosestSide);
-      if (should_serialize_radius_y_value)
-        radius_y = radius_y_->CssText();
-    }
-    if (should_serialize_radius_x_value ||
-        (!should_serialize_radius_x_value && should_serialize_radius_y_value))
+    auto* radius_y_identifier_value =
+        DynamicTo<CSSIdentifierValue>(radius_y_.Get());
+    bool radius_y_closest_side =
+        (radius_y_identifier_value &&
+         radius_y_identifier_value->GetValueID() == CSSValueID::kClosestSide);
+
+    if (!radius_x_closest_side || !radius_y_closest_side) {
       radius_x = radius_x_->CssText();
+      radius_y = radius_y_->CssText();
+    }
   }
 
   return BuildEllipseString(
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
index a6ceeb1..d25892af 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
@@ -317,13 +317,6 @@
       UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseTwoRadius));
 
   EXPECT_FALSE(
-      UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseOneRadius));
-  CSSParser::ParseSingleValue(CSSPropertyID::kClipPath, "ellipse(1px)",
-                              context);
-  EXPECT_TRUE(
-      UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseOneRadius));
-
-  EXPECT_FALSE(
       UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseNoRadius));
   CSSParser::ParseSingleValue(CSSPropertyID::kClipPath, "ellipse()", context);
   EXPECT_TRUE(
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index 7d033e8..63e64d0 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -253,12 +253,13 @@
   auto* shape = MakeGarbageCollected<CSSBasicShapeEllipseValue>();
   WebFeature feature = WebFeature::kBasicShapeEllipseNoRadius;
   if (CSSValue* radius_x = ConsumeShapeRadius(args, context.Mode())) {
-    shape->SetRadiusX(radius_x);
-    feature = WebFeature::kBasicShapeEllipseOneRadius;
-    if (CSSValue* radius_y = ConsumeShapeRadius(args, context.Mode())) {
-      shape->SetRadiusY(radius_y);
-      feature = WebFeature::kBasicShapeEllipseTwoRadius;
+    CSSValue* radius_y = ConsumeShapeRadius(args, context.Mode());
+    if (!radius_y) {
+      return nullptr;
     }
+    shape->SetRadiusX(radius_x);
+    shape->SetRadiusY(radius_y);
+    feature = WebFeature::kBasicShapeEllipseTwoRadius;
   }
   if (css_property_parser_helpers::ConsumeIdent<CSSValueID::kAt>(args)) {
     CSSValue* center_x = nullptr;
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl
index 378f053..58daf6f 100644
--- a/third_party/blink/renderer/core/dom/document.idl
+++ b/third_party/blink/renderer/core/dom/document.idl
@@ -204,7 +204,7 @@
     attribute EventHandler onfreeze;
     attribute EventHandler onresume;
     attribute EventHandler onsearch;
-    [RuntimeEnabled=ExperimentalContentSecurityPolicyFeatures] attribute EventHandler onsecuritypolicyviolation;
+    attribute EventHandler onsecuritypolicyviolation;
     attribute EventHandler onvisibilitychange;
 };
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 0714ac0..70d44ec 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2567,9 +2567,9 @@
 
   if (LayoutObject* layout_object = GetLayoutObject()) {
     DCHECK(new_style);
-    if (IsPseudoElement() && new_style->Display() == EDisplay::kContents) {
-      new_style =
-          ToPseudoElement(this)->LayoutStyleForDisplayContents(*new_style);
+    auto* this_element = DynamicTo<PseudoElement>(this);
+    if (this_element && new_style->Display() == EDisplay::kContents) {
+      new_style = this_element->LayoutStyleForDisplayContents(*new_style);
     }
     // kEqual means that the computed style didn't change, but there are
     // additional flags in ComputedStyle which may have changed. For instance,
diff --git a/third_party/blink/renderer/core/dom/global_event_handlers.h b/third_party/blink/renderer/core/dom/global_event_handlers.h
index 92cf31a..dff91f0 100644
--- a/third_party/blink/renderer/core/dom/global_event_handlers.h
+++ b/third_party/blink/renderer/core/dom/global_event_handlers.h
@@ -97,7 +97,7 @@
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(pointermove, kPointermove)
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(pointerout, kPointerout)
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(pointerover, kPointerover)
-  DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(pointerrawmove, kPointerrawmove)
+  DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(pointerrawupdate, kPointerrawupdate)
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(pointerup, kPointerup)
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(progress, kProgress)
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(ratechange, kRatechange)
diff --git a/third_party/blink/renderer/core/dom/global_event_handlers.idl b/third_party/blink/renderer/core/dom/global_event_handlers.idl
index db74edf..a060458 100644
--- a/third_party/blink/renderer/core/dom/global_event_handlers.idl
+++ b/third_party/blink/renderer/core/dom/global_event_handlers.idl
@@ -110,7 +110,7 @@
     attribute EventHandler onlostpointercapture;
     attribute EventHandler onpointerdown;
     attribute EventHandler onpointermove;
-    [RuntimeEnabled=PointerRawMove] attribute EventHandler onpointerrawmove;
+    [RuntimeEnabled=PointerRawUpdate] attribute EventHandler onpointerrawupdate;
     attribute EventHandler onpointerup;
     attribute EventHandler onpointercancel;
     attribute EventHandler onpointerover;
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc b/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
index 878f2efe..4008787f 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
@@ -62,8 +62,8 @@
   // LayoutTreeBuilderTraversal::parent() is used only for a node which is
   // connected.
   // DCHECK(node.isConnected());
-  if (node.IsPseudoElement()) {
-    AssertPseudoElementParent(ToPseudoElement(node));
+  if (auto* element = DynamicTo<PseudoElement>(node)) {
+    AssertPseudoElementParent(*element);
     return node.parentNode();
   }
   return FlatTreeTraversal::Parent(node, details);
@@ -87,7 +87,7 @@
 
 Node* LayoutTreeBuilderTraversal::NextSibling(const Node& node) {
   if (node.IsBeforePseudoElement()) {
-    AssertPseudoElementParent(ToPseudoElement(node));
+    AssertPseudoElementParent(To<PseudoElement>(node));
     if (Node* next = FlatTreeTraversal::FirstChild(*node.parentNode()))
       return next;
   } else {
@@ -106,7 +106,7 @@
 
 Node* LayoutTreeBuilderTraversal::PreviousSibling(const Node& node) {
   if (node.IsAfterPseudoElement()) {
-    AssertPseudoElementParent(ToPseudoElement(node));
+    AssertPseudoElementParent(To<PseudoElement>(node));
     if (Node* previous = FlatTreeTraversal::LastChild(*node.parentNode()))
       return previous;
   } else {
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.h b/third_party/blink/renderer/core/dom/pseudo_element.h
index 6bf86f5..15c111c7 100644
--- a/third_party/blink/renderer/core/dom/pseudo_element.h
+++ b/third_party/blink/renderer/core/dom/pseudo_element.h
@@ -29,6 +29,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
@@ -78,7 +79,15 @@
 
 bool PseudoElementLayoutObjectIsNeeded(const ComputedStyle*);
 
-DEFINE_ELEMENT_TYPE_CASTS(PseudoElement, IsPseudoElement());
+template <>
+inline bool IsElementOfType<const PseudoElement>(const Node& node) {
+  return node.IsPseudoElement();
+}
+
+template <>
+struct DowncastTraits<PseudoElement> {
+  static bool AllowFrom(const Node& node) { return node.IsPseudoElement(); }
+};
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/events/event_type_names.json5 b/third_party/blink/renderer/core/events/event_type_names.json5
index ae35470..63f7c81 100644
--- a/third_party/blink/renderer/core/events/event_type_names.json5
+++ b/third_party/blink/renderer/core/events/event_type_names.json5
@@ -215,7 +215,7 @@
     "pointermove",
     "pointerout",
     "pointerover",
-    "pointerrawmove",
+    "pointerrawupdate",
     "pointerup",
     "popstate",
     "portalactivate",
diff --git a/third_party/blink/renderer/core/events/pointer_event_factory.cc b/third_party/blink/renderer/core/events/pointer_event_factory.cc
index 3234509b..8b8dba7 100644
--- a/third_party/blink/renderer/core/events/pointer_event_factory.cc
+++ b/third_party/blink/renderer/core/events/pointer_event_factory.cc
@@ -63,8 +63,8 @@
       return event_type_names::kPointerup;
     case WebInputEvent::kPointerMove:
       return event_type_names::kPointermove;
-    case WebInputEvent::kPointerRawMove:
-      return event_type_names::kPointerrawmove;
+    case WebInputEvent::kPointerRawUpdate:
+      return event_type_names::kPointerrawupdate;
     case WebInputEvent::kPointerCancel:
       return event_type_names::kPointercancel;
     default:
@@ -96,7 +96,7 @@
       web_pointer_event_in_root_frame, dom_window, pointer_event_init);
   if (RuntimeEnabledFeatures::MovementXYInBlinkEnabled() &&
       web_pointer_event.GetType() == WebInputEvent::kPointerMove) {
-    // TODO(eirage): pointerrawmove event's movements are not calculated.
+    // TODO(eirage): pointerrawupdate event's movements are not calculated.
     pointer_event_init->setMovementX(web_pointer_event.PositionInScreen().x -
                                      last_global_position.X());
     pointer_event_init->setMovementY(web_pointer_event.PositionInScreen().y -
@@ -243,7 +243,7 @@
       type != event_type_names::kPointerenter &&
       type != event_type_names::kPointerleave &&
       type != event_type_names::kPointercancel &&
-      type != event_type_names::kPointerrawmove &&
+      type != event_type_names::kPointerrawupdate &&
       type != event_type_names::kGotpointercapture &&
       type != event_type_names::kLostpointercapture);
 
@@ -260,7 +260,7 @@
   DCHECK(event_type == WebInputEvent::kPointerDown ||
          event_type == WebInputEvent::kPointerUp ||
          event_type == WebInputEvent::kPointerMove ||
-         event_type == WebInputEvent::kPointerRawMove ||
+         event_type == WebInputEvent::kPointerRawUpdate ||
          event_type == WebInputEvent::kPointerCancel);
 
   PointerEventInit* pointer_event_init =
@@ -305,7 +305,7 @@
   HeapVector<Member<PointerEvent>> coalesced_pointer_events,
       predicted_pointer_events;
   if (type == event_type_names::kPointermove ||
-      type == event_type_names::kPointerrawmove) {
+      type == event_type_names::kPointerrawupdate) {
     coalesced_pointer_events = CreateEventSequence(
         web_pointer_event, pointer_event_init, coalesced_events, view);
   }
@@ -402,9 +402,9 @@
                               pointer_event->PlatformTimeStamp());
 }
 
-PointerEvent* PointerEventFactory::CreatePointerRawMoveEvent(
+PointerEvent* PointerEventFactory::CreatePointerRawUpdateEvent(
     PointerEvent* pointer_event) {
-  // This function is for creating pointerrawmove event from a pointerdown/up
+  // This function is for creating pointerrawupdate event from a pointerdown/up
   // event that caused by chorded buttons and hence its type is changed to
   // pointermove.
   DCHECK(pointer_event->type() == event_type_names::kPointermove &&
@@ -414,7 +414,7 @@
          pointer_event->button() != 0);
 
   return CreatePointerEventFrom(pointer_event,
-                                event_type_names::kPointerrawmove,
+                                event_type_names::kPointerrawupdate,
                                 pointer_event->relatedTarget());
 }
 
diff --git a/third_party/blink/renderer/core/events/pointer_event_factory.h b/third_party/blink/renderer/core/events/pointer_event_factory.h
index bf363c6..9ee7532 100644
--- a/third_party/blink/renderer/core/events/pointer_event_factory.h
+++ b/third_party/blink/renderer/core/events/pointer_event_factory.h
@@ -40,8 +40,8 @@
   PointerEvent* CreatePointerCancelEvent(const PointerId pointer_id,
                                          TimeTicks platfrom_time_stamp);
 
-  // For creating raw move events in chorded button case.
-  PointerEvent* CreatePointerRawMoveEvent(PointerEvent*);
+  // For creating raw update events in chorded button case.
+  PointerEvent* CreatePointerRawUpdateEvent(PointerEvent*);
 
   // For creating capture events (i.e got/lostpointercapture).
   PointerEvent* CreatePointerCaptureEvent(PointerEvent*, const AtomicString&);
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 405bb3e..30c2cf2 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -2303,38 +2303,6 @@
                    .Height());
 }
 
-TEST_F(WebFrameTest, WideViewportAndWideContentWithInitialScale) {
-  RegisterMockedHttpURLLoad("wide_document_width_viewport.html");
-  RegisterMockedHttpURLLoad("white-1x1.png");
-
-  FixedLayoutTestWebViewClient client;
-  client.screen_info_.device_scale_factor = 1;
-  int viewport_width = 600;
-  int viewport_height = 800;
-
-  frame_test_helpers::WebViewHelper web_view_helper;
-  web_view_helper.InitializeAndLoad("about:blank", nullptr, &client, nullptr,
-                                    ConfigureAndroid);
-  web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
-      true);
-  web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
-  web_view_helper.GetWebView()->GetSettings()->SetViewportMetaLayoutSizeQuirk(
-      true);
-  web_view_helper.Resize(WebSize(viewport_width, viewport_height));
-
-  frame_test_helpers::LoadFrame(
-      web_view_helper.GetWebView()->MainFrameImpl(),
-      base_url_ + "wide_document_width_viewport.html");
-  web_view_helper.Resize(WebSize(viewport_width, viewport_height));
-
-  int wide_document_width = 800;
-  float minimum_page_scale_factor = viewport_width / (float)wide_document_width;
-  EXPECT_EQ(minimum_page_scale_factor,
-            web_view_helper.GetWebView()->PageScaleFactor());
-  EXPECT_EQ(minimum_page_scale_factor,
-            web_view_helper.GetWebView()->MinimumPageScaleFactor());
-}
-
 TEST_F(WebFrameTest, WideViewportQuirkClobbersHeight) {
   RegisterMockedHttpURLLoad("viewport-height-1000.html");
 
@@ -2349,8 +2317,6 @@
   web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
       true);
   web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(false);
-  web_view_helper.GetWebView()->GetSettings()->SetViewportMetaLayoutSizeQuirk(
-      true);
   web_view_helper.Resize(WebSize(viewport_width, viewport_height));
 
   frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
@@ -2365,124 +2331,6 @@
   EXPECT_EQ(1, web_view_helper.GetWebView()->PageScaleFactor());
 }
 
-TEST_F(WebFrameTest, LayoutSize320Quirk) {
-  RegisterMockedHttpURLLoad("viewport/viewport-30.html");
-
-  FixedLayoutTestWebViewClient client;
-  client.screen_info_.device_scale_factor = 1;
-  int viewport_width = 600;
-  int viewport_height = 800;
-
-  frame_test_helpers::WebViewHelper web_view_helper;
-  web_view_helper.InitializeAndLoad("about:blank", nullptr, &client, nullptr,
-                                    ConfigureAndroid);
-  web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
-      true);
-  web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
-  web_view_helper.GetWebView()->GetSettings()->SetViewportMetaLayoutSizeQuirk(
-      true);
-  web_view_helper.Resize(WebSize(viewport_width, viewport_height));
-
-  frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
-                                base_url_ + "viewport/viewport-30.html");
-  web_view_helper.Resize(WebSize(viewport_width, viewport_height));
-
-  EXPECT_EQ(600, web_view_helper.GetWebView()
-                     ->MainFrameImpl()
-                     ->GetFrameView()
-                     ->GetLayoutSize()
-                     .Width());
-  EXPECT_EQ(800, web_view_helper.GetWebView()
-                     ->MainFrameImpl()
-                     ->GetFrameView()
-                     ->GetLayoutSize()
-                     .Height());
-  EXPECT_EQ(1, web_view_helper.GetWebView()->PageScaleFactor());
-
-  // The magic number to snap to device-width is 320, so test that 321 is
-  // respected.
-  ViewportData& viewport =
-      To<LocalFrame>(web_view_helper.GetWebView()->GetPage()->MainFrame())
-          ->GetDocument()
-          ->GetViewportData();
-  ViewportDescription description = viewport.GetViewportDescription();
-  description.min_width = Length::Fixed(321);
-  description.max_width = Length::Fixed(321);
-  viewport.SetViewportDescription(description);
-  UpdateAllLifecyclePhases(web_view_helper.GetWebView());
-  EXPECT_EQ(321, web_view_helper.GetWebView()
-                     ->MainFrameImpl()
-                     ->GetFrameView()
-                     ->GetLayoutSize()
-                     .Width());
-
-  description.min_width = Length::Fixed(320);
-  description.max_width = Length::Fixed(320);
-  viewport.SetViewportDescription(description);
-  UpdateAllLifecyclePhases(web_view_helper.GetWebView());
-  EXPECT_EQ(600, web_view_helper.GetWebView()
-                     ->MainFrameImpl()
-                     ->GetFrameView()
-                     ->GetLayoutSize()
-                     .Width());
-
-  description = viewport.GetViewportDescription();
-  description.max_height = Length::Fixed(1000);
-  viewport.SetViewportDescription(description);
-  UpdateAllLifecyclePhases(web_view_helper.GetWebView());
-  EXPECT_EQ(1000, web_view_helper.GetWebView()
-                      ->MainFrameImpl()
-                      ->GetFrameView()
-                      ->GetLayoutSize()
-                      .Height());
-
-  description.max_height = Length::Fixed(320);
-  viewport.SetViewportDescription(description);
-  UpdateAllLifecyclePhases(web_view_helper.GetWebView());
-  EXPECT_EQ(800, web_view_helper.GetWebView()
-                     ->MainFrameImpl()
-                     ->GetFrameView()
-                     ->GetLayoutSize()
-                     .Height());
-}
-
-TEST_F(WebFrameTest, ZeroValuesQuirk) {
-  RegisterMockedHttpURLLoad("viewport-zero-values.html");
-
-  FixedLayoutTestWebViewClient client;
-  client.screen_info_.device_scale_factor = 1;
-  int viewport_width = 640;
-  int viewport_height = 480;
-
-  frame_test_helpers::WebViewHelper web_view_helper;
-  web_view_helper.Initialize(nullptr, &client, nullptr, ConfigureAndroid);
-  web_view_helper.GetWebView()->GetSettings()->SetViewportMetaZeroValuesQuirk(
-      true);
-  web_view_helper.GetWebView()->GetSettings()->SetWideViewportQuirkEnabled(
-      true);
-  web_view_helper.GetWebView()->GetSettings()->SetViewportMetaLayoutSizeQuirk(
-      true);
-  frame_test_helpers::LoadFrame(web_view_helper.GetWebView()->MainFrameImpl(),
-                                base_url_ + "viewport-zero-values.html");
-  web_view_helper.Resize(WebSize(viewport_width, viewport_height));
-
-  EXPECT_EQ(viewport_width, web_view_helper.GetWebView()
-                                ->MainFrameImpl()
-                                ->GetFrameView()
-                                ->GetLayoutSize()
-                                .Width());
-  EXPECT_EQ(1.0f, web_view_helper.GetWebView()->PageScaleFactor());
-
-  web_view_helper.GetWebView()->GetSettings()->SetUseWideViewport(true);
-  UpdateAllLifecyclePhases(web_view_helper.GetWebView());
-  EXPECT_EQ(viewport_width, web_view_helper.GetWebView()
-                                ->MainFrameImpl()
-                                ->GetFrameView()
-                                ->GetLayoutSize()
-                                .Width());
-  EXPECT_EQ(1.0f, web_view_helper.GetWebView()->PageScaleFactor());
-}
-
 TEST_F(WebFrameTest, OverflowHiddenDisablesScrolling) {
   RegisterMockedHttpURLLoad("body-overflow-hidden.html");
 
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.cc b/third_party/blink/renderer/core/exported/web_settings_impl.cc
index 818f377..8312aab 100644
--- a/third_party/blink/renderer/core/exported/web_settings_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -45,7 +45,6 @@
       render_v_sync_notification_enabled_(false),
       auto_zoom_focused_node_to_legible_scale_(false),
       support_deprecated_target_density_dpi_(false),
-      viewport_meta_layout_size_quirk_(false),
       viewport_meta_non_user_scalable_quirk_(false),
       clobber_user_agent_initial_scale_quirk_(false) {
   DCHECK(settings);
@@ -183,11 +182,6 @@
       support_deprecated_target_density_dpi;
 }
 
-void WebSettingsImpl::SetViewportMetaLayoutSizeQuirk(
-    bool viewport_meta_layout_size_quirk) {
-  viewport_meta_layout_size_quirk_ = viewport_meta_layout_size_quirk;
-}
-
 void WebSettingsImpl::SetViewportMetaMergeContentQuirk(
     bool viewport_meta_merge_content_quirk) {
   settings_->SetViewportMetaMergeContentQuirk(
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.h b/third_party/blink/renderer/core/exported/web_settings_impl.h
index f2f38f1f..6131c110 100644
--- a/third_party/blink/renderer/core/exported/web_settings_impl.h
+++ b/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -186,7 +186,6 @@
   void SetValidationMessageTimerMagnification(int) override;
   void SetViewportEnabled(bool) override;
   void SetViewportMetaEnabled(bool) override;
-  void SetViewportMetaLayoutSizeQuirk(bool) override;
   void SetViewportMetaMergeContentQuirk(bool) override;
   void SetViewportMetaNonUserScalableQuirk(bool) override;
   void SetViewportMetaZeroValuesQuirk(bool) override;
@@ -229,9 +228,6 @@
     return support_deprecated_target_density_dpi_;
   }
   bool ViewportMetaEnabled() const;
-  bool ViewportMetaLayoutSizeQuirk() const {
-    return viewport_meta_layout_size_quirk_;
-  }
   bool ViewportMetaNonUserScalableQuirk() const {
     return viewport_meta_non_user_scalable_quirk_;
   }
@@ -250,10 +246,6 @@
   bool support_deprecated_target_density_dpi_;
   // This quirk is to maintain compatibility with Android apps built on
   // the Android SDK prior to and including version 18. Presumably, this
-  // can be removed any time after 2015. See http://crbug.com/277369.
-  bool viewport_meta_layout_size_quirk_;
-  // This quirk is to maintain compatibility with Android apps built on
-  // the Android SDK prior to and including version 18. Presumably, this
   // can be removed any time after 2015. See http://crbug.com/312691.
   bool viewport_meta_non_user_scalable_quirk_;
   // This quirk is to maintain compatibility with Android apps built on
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 5e14a42..6f4443d 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1780,9 +1780,9 @@
     }
   }
 
-  // Skip the pointerrawmove for mouse capture case.
+  // Skip the pointerrawupdate for mouse capture case.
   if (mouse_capture_element_ &&
-      input_event.GetType() == WebInputEvent::kPointerRawMove)
+      input_event.GetType() == WebInputEvent::kPointerRawUpdate)
     return WebInputEventResult::kHandledSystem;
 
   if (mouse_capture_element_ &&
@@ -1816,9 +1816,9 @@
     case WebInputEvent::kMouseMove:
       event_type = event_type_names::kMousemove;
       break;
-    case WebInputEvent::kPointerRawMove:
-      // There will be no mouse event for raw move events.
-      event_type = event_type_names::kPointerrawmove;
+    case WebInputEvent::kPointerRawUpdate:
+      // There will be no mouse event for rawupdate events.
+      event_type = event_type_names::kPointerrawupdate;
       break;
     case WebInputEvent::kMouseLeave:
       event_type = event_type_names::kMouseout;
@@ -2625,25 +2625,10 @@
   if (default_min_width.IsAuto())
     default_min_width = Length::ExtendToZoom();
 
-  ViewportDescription adjusted_description = description;
-  if (SettingsImpl()->ViewportMetaLayoutSizeQuirk() &&
-      adjusted_description.type == ViewportDescription::kViewportMeta) {
-    const int kLegacyWidthSnappingMagicNumber = 320;
-    if (adjusted_description.max_width.IsFixed() &&
-        adjusted_description.max_width.Value() <=
-            kLegacyWidthSnappingMagicNumber)
-      adjusted_description.max_width = Length::DeviceWidth();
-    if (adjusted_description.max_height.IsFixed() &&
-        adjusted_description.max_height.Value() <= size_.height)
-      adjusted_description.max_height = Length::DeviceHeight();
-    adjusted_description.min_width = adjusted_description.max_width;
-    adjusted_description.min_height = adjusted_description.max_height;
-  }
-
   float old_initial_scale =
       GetPageScaleConstraintsSet().PageDefinedConstraints().initial_scale;
-  GetPageScaleConstraintsSet().UpdatePageDefinedConstraints(
-      adjusted_description, default_min_width);
+  GetPageScaleConstraintsSet().UpdatePageDefinedConstraints(description,
+                                                            default_min_width);
 
   if (SettingsImpl()->ClobberUserAgentInitialScaleQuirk() &&
       GetPageScaleConstraintsSet().UserAgentConstraints().initial_scale != -1 &&
@@ -2659,7 +2644,7 @@
 
   Settings& page_settings = GetPage()->GetSettings();
   GetPageScaleConstraintsSet().AdjustForAndroidWebViewQuirks(
-      adjusted_description, default_min_width.IntValue(), DeviceScaleFactor(),
+      description, default_min_width.IntValue(), DeviceScaleFactor(),
       SettingsImpl()->SupportDeprecatedTargetDensityDPI(),
       page_settings.GetWideViewportQuirkEnabled(),
       page_settings.GetUseWideViewport(),
diff --git a/third_party/blink/renderer/core/frame/event_handler_registry.cc b/third_party/blink/renderer/core/frame/event_handler_registry.cc
index d255ba9..a2ff7ebc 100644
--- a/third_party/blink/renderer/core/frame/event_handler_registry.cc
+++ b/third_party/blink/renderer/core/frame/event_handler_registry.cc
@@ -69,11 +69,11 @@
              event_type == event_type_names::kTouchmove) {
     *result = options->passive() ? kTouchStartOrMoveEventPassive
                                  : kTouchStartOrMoveEventBlocking;
-  } else if (event_type == event_type_names::kPointerrawmove) {
+  } else if (event_type == event_type_names::kPointerrawupdate) {
     // This will be used to avoid waking up the main thread to
-    // process pointerrawmove events and hit-test them when
+    // process pointerrawupdate events and hit-test them when
     // there is no listener on the page.
-    *result = kPointerRawMoveEvent;
+    *result = kPointerRawUpdateEvent;
   } else if (event_util::IsPointerEventType(event_type)) {
     // The pointer events never block scrolling and the compositor
     // only needs to know about the touch listeners.
@@ -276,11 +276,11 @@
               HasEventHandlers(kTouchStartOrMoveEventPassive) ||
                   HasEventHandlers(kPointerEvent)));
       break;
-    case kPointerRawMoveEvent:
+    case kPointerRawUpdateEvent:
       GetPage()->GetChromeClient().SetEventListenerProperties(
-          frame, cc::EventListenerClass::kPointerRawMove,
+          frame, cc::EventListenerClass::kPointerRawUpdate,
           GetEventListenerProperties(false,
-                                     HasEventHandlers(kPointerRawMoveEvent)));
+                                     HasEventHandlers(kPointerRawUpdateEvent)));
       break;
     case kTouchEndOrCancelEventBlocking:
     case kTouchEndOrCancelEventPassive:
diff --git a/third_party/blink/renderer/core/frame/event_handler_registry.h b/third_party/blink/renderer/core/frame/event_handler_registry.h
index 1ea48478..91890f0 100644
--- a/third_party/blink/renderer/core/frame/event_handler_registry.h
+++ b/third_party/blink/renderer/core/frame/event_handler_registry.h
@@ -41,8 +41,9 @@
     kTouchStartOrMoveEventPassive,
     kTouchEndOrCancelEventBlocking,
     kTouchEndOrCancelEventPassive,
-    kPointerEvent,  // This includes all pointerevents excluding pointerrawmove.
-    kPointerRawMoveEvent,
+    kPointerEvent,  // This includes all pointerevents excluding
+                    // pointerrawupdate.
+    kPointerRawUpdateEvent,
 #if DCHECK_IS_ON()
     // Additional event categories for verifying handler tracking logic.
     kEventsForTesting,
diff --git a/third_party/blink/renderer/core/frame/settings.cc b/third_party/blink/renderer/core/frame/settings.cc
index ac117465..875f17e 100644
--- a/third_party/blink/renderer/core/frame/settings.cc
+++ b/third_party/blink/renderer/core/frame/settings.cc
@@ -109,7 +109,7 @@
   force_dark_mode_ = enabled;
 
   if (force_dark_mode_) {
-    SetDarkMode(DarkMode::kInvertLightness);
+    SetDarkMode(DarkMode::kInvertLightnessLAB);
     SetDarkModeImagePolicy(DarkModeImagePolicy::kFilterSmart);
   } else {
     SetDarkMode(DarkMode::kOff);
diff --git a/third_party/blink/renderer/core/html/html_attribute_names.json5 b/third_party/blink/renderer/core/html/html_attribute_names.json5
index 3ff9569..70c006940 100644
--- a/third_party/blink/renderer/core/html/html_attribute_names.json5
+++ b/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -224,7 +224,7 @@
     "onpointermove",
     "onpointerout",
     "onpointerover",
-    "onpointerrawmove",
+    "onpointerrawupdate",
     "onpointerup",
     "onpopstate",
     "onportalactivate",
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index deed25cb..461c8d2 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -446,8 +446,8 @@
        nullptr},
       {kOnpointeroverAttr, kNoWebFeature, event_type_names::kPointerover,
        nullptr},
-      {kOnpointerrawmoveAttr, kNoWebFeature, event_type_names::kPointerrawmove,
-       nullptr},
+      {kOnpointerrawupdateAttr, kNoWebFeature,
+       event_type_names::kPointerrawupdate, nullptr},
       {kOnpointerupAttr, kNoWebFeature, event_type_names::kPointerup, nullptr},
       {kOnprogressAttr, kNoWebFeature, event_type_names::kProgress, nullptr},
       {kOnratechangeAttr, kNoWebFeature, event_type_names::kRatechange,
diff --git a/third_party/blink/renderer/core/html/media/autoplay_policy.cc b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
index d4545d6..e861506 100644
--- a/third_party/blink/renderer/core/html/media/autoplay_policy.cc
+++ b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
@@ -196,7 +196,7 @@
     return false;
   }
 
-  return element_->muted() &&
+  return !element_->EffectiveMediaVolume() &&
          DocumentShouldAutoplayMutedVideos(element_->GetDocument());
 }
 
@@ -223,7 +223,7 @@
 }
 
 bool AutoplayPolicy::RequestAutoplayUnmute() {
-  DCHECK(!element_->muted());
+  DCHECK_NE(0, element_->EffectiveMediaVolume());
   bool was_autoplaying_muted = IsAutoplayingMutedInternal(true);
 
   TryUnlockingUserGesture();
@@ -289,7 +289,7 @@
 }
 
 bool AutoplayPolicy::IsOrWillBeAutoplayingMuted() const {
-  return IsOrWillBeAutoplayingMutedInternal(element_->muted());
+  return IsOrWillBeAutoplayingMutedInternal(!element_->EffectiveMediaVolume());
 }
 
 bool AutoplayPolicy::IsOrWillBeAutoplayingMutedInternal(bool muted) const {
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index af1e07c..aa97892 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -2597,9 +2597,22 @@
 
   volume_ = vol;
 
+  ScheduleEvent(event_type_names::kVolumechange);
+
+  // If it setting volume to audible and AutoplayPolicy doesn't want the
+  // playback to continue, pause the playback.
+  if (EffectiveMediaVolume() && !autoplay_policy_->RequestAutoplayUnmute())
+    pause();
+
+  // If playback was not paused by the autoplay policy and got audible, the
+  // element is marked as being allowed to play unmuted.
+  if (EffectiveMediaVolume() && PotentiallyPlaying())
+    was_always_muted_ = false;
+
   if (GetWebMediaPlayer())
     GetWebMediaPlayer()->SetVolume(EffectiveMediaVolume());
-  ScheduleEvent(event_type_names::kVolumechange);
+
+  autoplay_policy_->StopAutoplayMutedWhenVisible();
 }
 
 bool HTMLMediaElement::muted() const {
@@ -2618,12 +2631,12 @@
 
   // If it is unmute and AutoplayPolicy doesn't want the playback to continue,
   // pause the playback.
-  if (!muted_ && !autoplay_policy_->RequestAutoplayUnmute())
+  if (EffectiveMediaVolume() && !autoplay_policy_->RequestAutoplayUnmute())
     pause();
 
   // If playback was not paused by the autoplay policy and got unmuted, the
   // element is marked as being allowed to play unmuted.
-  if (!muted_ && PotentiallyPlaying())
+  if (EffectiveMediaVolume() && PotentiallyPlaying())
     was_always_muted_ = false;
 
   // This is called at the end to make sure the WebMediaPlayer has the right
diff --git a/third_party/blink/renderer/core/html/portal/html_portal_element.cc b/third_party/blink/renderer/core/html/portal/html_portal_element.cc
index 2fd6bb0ee..b7213b19 100644
--- a/third_party/blink/renderer/core/html/portal/html_portal_element.cc
+++ b/third_party/blink/renderer/core/html/portal/html_portal_element.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 #include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_event_listener.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h"
@@ -13,6 +14,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/event_type_names.h"
 #include "third_party/blink/renderer/core/events/message_event.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -327,8 +329,26 @@
     const AttributeModificationParams& params) {
   HTMLFrameOwnerElement::ParseAttribute(params);
 
-  if (params.name == html_names::kSrcAttr)
+  if (params.name == html_names::kSrcAttr) {
     Navigate();
+    return;
+  }
+
+  struct {
+    const QualifiedName& name;
+    const AtomicString& event_name;
+  } event_handler_attributes[] = {
+      {html_names::kOnmessageAttr, event_type_names::kMessage},
+      {html_names::kOnmessageerrorAttr, event_type_names::kMessageerror},
+  };
+  for (const auto& attribute : event_handler_attributes) {
+    if (params.name == attribute.name) {
+      SetAttributeEventListener(
+          attribute.event_name,
+          CreateAttributeEventListener(this, attribute.name, params.new_value));
+      return;
+    }
+  }
 }
 
 LayoutObject* HTMLPortalElement::CreateLayoutObject(const ComputedStyle& style,
diff --git a/third_party/blink/renderer/core/input/keyboard_event_manager.cc b/third_party/blink/renderer/core/input/keyboard_event_manager.cc
index bca30e47..1942097a 100644
--- a/third_party/blink/renderer/core/input/keyboard_event_manager.cc
+++ b/third_party/blink/renderer/core/input/keyboard_event_manager.cc
@@ -185,8 +185,9 @@
       static_cast<ui::DomKey>(initial_key_event.dom_key));
 
   std::unique_ptr<UserGestureIndicator> gesture_indicator;
-  if (!is_modifier)
+  if (!is_modifier && initial_key_event.dom_key != ui::DomKey::ESCAPE) {
     gesture_indicator = LocalFrame::NotifyUserActivation(frame_);
+  }
 
   // In IE, access keys are special, they are handled after default keydown
   // processing, but cannot be canceled - this is hard to match.  On Mac OS X,
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.cc b/third_party/blink/renderer/core/input/pointer_event_manager.cc
index 6a7744b5..4f41a64 100644
--- a/third_party/blink/renderer/core/input/pointer_event_manager.cc
+++ b/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -43,7 +43,8 @@
 }
 bool HasPointerEventListener(const EventHandlerRegistry& registry) {
   return registry.HasEventHandlers(EventHandlerRegistry::kPointerEvent) ||
-         registry.HasEventHandlers(EventHandlerRegistry::kPointerRawMoveEvent);
+         registry.HasEventHandlers(
+             EventHandlerRegistry::kPointerRawUpdateEvent);
 }
 
 const AtomicString& MouseEventNameForPointerEventInputType(
@@ -532,10 +533,10 @@
     const WebPointerEvent& event,
     const Vector<WebPointerEvent>& coalesced_events,
     const Vector<WebPointerEvent>& predicted_events) {
-  if (event.GetType() == WebInputEvent::Type::kPointerRawMove) {
-    if (!RuntimeEnabledFeatures::PointerRawMoveEnabled() ||
+  if (event.GetType() == WebInputEvent::Type::kPointerRawUpdate) {
+    if (!RuntimeEnabledFeatures::PointerRawUpdateEnabled() ||
         !frame_->GetEventHandlerRegistry().HasEventHandlers(
-            EventHandlerRegistry::kPointerRawMoveEvent))
+            EventHandlerRegistry::kPointerRawUpdateEvent))
       return WebInputEventResult::kHandledSystem;
 
     // If the page has pointer lock active and the event was from
@@ -733,14 +734,14 @@
   if ((event_type == WebInputEvent::kPointerDown ||
        event_type == WebInputEvent::kPointerUp) &&
       pointer_event->type() == event_type_names::kPointermove &&
-      RuntimeEnabledFeatures::PointerRawMoveEnabled() &&
+      RuntimeEnabledFeatures::PointerRawUpdateEnabled() &&
       frame_->GetEventHandlerRegistry().HasEventHandlers(
-          EventHandlerRegistry::kPointerRawMoveEvent)) {
+          EventHandlerRegistry::kPointerRawUpdateEvent)) {
     // This is a chorded button move event. We need to also send a
-    // pointerrawmove for it.
+    // pointerrawupdate for it.
     DispatchPointerEvent(
         effective_target,
-        pointer_event_factory_.CreatePointerRawMoveEvent(pointer_event));
+        pointer_event_factory_.CreatePointerRawUpdateEvent(pointer_event));
   }
   WebInputEventResult result =
       DispatchPointerEvent(effective_target, pointer_event);
diff --git a/third_party/blink/renderer/core/inspector/inspector_highlight.cc b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
index d59e4f71..55205840 100644
--- a/third_party/blink/renderer/core/inspector/inspector_highlight.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
@@ -253,9 +253,8 @@
   std::unique_ptr<protocol::DictionaryValue> element_info =
       protocol::DictionaryValue::create();
   Element* real_element = element;
-  PseudoElement* pseudo_element = nullptr;
-  if (element->IsPseudoElement()) {
-    pseudo_element = ToPseudoElement(element);
+  auto* pseudo_element = DynamicTo<PseudoElement>(element);
+  if (pseudo_element) {
     real_element = element->ParentOrShadowHostElement();
   }
   bool is_xhtml = real_element->GetDocument().IsXHTMLDocument();
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.cc b/third_party/blink/renderer/core/layout/hit_test_result.cc
index f657558..af1e7a5 100644
--- a/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -202,8 +202,8 @@
     return;
   }
   inner_possibly_pseudo_node_ = n;
-  if (n->IsPseudoElement())
-    n = ToPseudoElement(n)->InnerNodeForHitTesting();
+  if (auto* pseudo_element = DynamicTo<PseudoElement>(n))
+    n = pseudo_element->InnerNodeForHitTesting();
   inner_node_ = n;
   if (HTMLAreaElement* area = ImageAreaForImage()) {
     inner_node_ = area;
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index c199ca1..4d250792 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -515,8 +515,10 @@
     LayoutUnit child_intrinsic_logical_height =
         child_intrinsic_content_logical_height +
         child.ScrollbarLogicalHeight() + child.BorderAndPaddingLogicalHeight();
-    return child.ConstrainLogicalHeightByMinMax(
-        child_intrinsic_logical_height, child_intrinsic_content_logical_height);
+    LogicalExtentComputedValues values;
+    child.ComputeLogicalHeight(child_intrinsic_logical_height, LayoutUnit(),
+                               values);
+    return values.extent_;
   }
   return child.LogicalHeight();
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index b96f1eb..de0754f1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -29,6 +29,11 @@
                   sizeof(SameSizeAsNGPhysicalBoxFragment),
               "NGPhysicalBoxFragment should stay small");
 
+bool HasControlClip(const NGPhysicalBoxFragment& self) {
+  const LayoutBox* box = ToLayoutBoxOrNull(self.GetLayoutObject());
+  return box && box->HasControlClip();
+}
+
 }  // namespace
 
 scoped_refptr<const NGPhysicalBoxFragment> NGPhysicalBoxFragment::Create(
@@ -74,13 +79,9 @@
 }
 
 bool NGPhysicalBoxFragment::HasSelfPaintingLayer() const {
-  return GetLayoutBoxModelObject().HasSelfPaintingLayer();
-}
-
-bool NGPhysicalBoxFragment::HasControlClip() const {
-  const LayoutObject* layout_object = GetLayoutObject();
-  DCHECK(layout_object);
-  return layout_object->IsBox() && ToLayoutBox(layout_object)->HasControlClip();
+  SECURITY_DCHECK(GetLayoutObject() && GetLayoutObject()->IsBoxModelObject());
+  return (static_cast<LayoutBoxModelObject*>(GetLayoutObject()))
+      ->HasSelfPaintingLayer();
 }
 
 LayoutRect NGPhysicalBoxFragment::OverflowClipRect(
@@ -195,7 +196,7 @@
   }
 
   if (outline_type == NGOutlineType::kIncludeBlockVisualOverflow &&
-      !HasOverflowClip() && !HasControlClip()) {
+      !HasOverflowClip() && !HasControlClip(*this)) {
     AddOutlineRectsForNormalChildren(outline_rects, additional_offset,
                                      outline_type);
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index 2cb4731..e02fedda6 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -44,8 +44,6 @@
   bool HasSelfPaintingLayer() const;
   bool ChildrenInline() const { return children_inline_; }
 
-  bool HasControlClip() const;
-
   PhysicalRect ScrollableOverflow() const;
 
   // TODO(layout-dev): These three methods delegate to legacy layout for now,
@@ -68,13 +66,6 @@
 
   UBiDiLevel BidiLevel() const;
 
-  scoped_refptr<const NGPhysicalFragment> CloneWithoutOffset() const;
-
-  LayoutBoxModelObject& GetLayoutBoxModelObject() const {
-    SECURITY_DCHECK(GetLayoutObject() && GetLayoutObject()->IsBoxModelObject());
-    return *static_cast<LayoutBoxModelObject*>(GetLayoutObject());
-  }
-
  private:
   NGPhysicalBoxFragment(NGBoxFragmentBuilder* builder,
                         WritingMode block_or_line_writing_mode);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
index f6fdac45..6ba3893 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
@@ -45,14 +45,6 @@
     return ChildLinkList(num_children_, buffer_);
   }
 
-  void AddOutlineRectsForNormalChildren(Vector<LayoutRect>* outline_rects,
-                                        const LayoutPoint& additional_offset,
-                                        NGOutlineType outline_type) const;
-  void AddOutlineRectsForDescendant(const NGLink& descendant,
-                                    Vector<LayoutRect>* rects,
-                                    const LayoutPoint& additional_offset,
-                                    NGOutlineType outline_type) const;
-
   bool HasFloatingDescendants() const { return has_floating_descendants_; }
 
  protected:
@@ -63,6 +55,14 @@
                               NGFragmentType,
                               unsigned sub_type);
 
+  void AddOutlineRectsForNormalChildren(Vector<LayoutRect>* outline_rects,
+                                        const LayoutPoint& additional_offset,
+                                        NGOutlineType outline_type) const;
+  void AddOutlineRectsForDescendant(const NGLink& descendant,
+                                    Vector<LayoutRect>* rects,
+                                    const LayoutPoint& additional_offset,
+                                    NGOutlineType outline_type) const;
+
   // Because flexible arrays need to be the last member in a class, the actual
   // storage is in the subclass and we just keep a pointer to it here.
   const NGLinkStorage* buffer_;
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index 4c326ba6..5ee51054 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -977,8 +977,8 @@
           tree_view->EventListenerProperties(
               cc::EventListenerClass::kTouchStartOrMove) !=
               cc::EventListenerProperties::kNone);
-    } else if (event_class == cc::EventListenerClass::kPointerRawMove) {
-      client->HasPointerRawMoveEventHandlers(
+    } else if (event_class == cc::EventListenerClass::kPointerRawUpdate) {
+      client->HasPointerRawUpdateEventHandlers(
           properties != cc::EventListenerProperties::kNone);
     }
   } else {
diff --git a/third_party/blink/renderer/core/page/page_widget_delegate.cc b/third_party/blink/renderer/core/page/page_widget_delegate.cc
index f9b0acef..ddcad03 100644
--- a/third_party/blink/renderer/core/page/page_widget_delegate.cc
+++ b/third_party/blink/renderer/core/page/page_widget_delegate.cc
@@ -177,7 +177,7 @@
     case WebInputEvent::kPointerDown:
     case WebInputEvent::kPointerUp:
     case WebInputEvent::kPointerMove:
-    case WebInputEvent::kPointerRawMove:
+    case WebInputEvent::kPointerRawUpdate:
     case WebInputEvent::kPointerCancel:
     case WebInputEvent::kPointerCausedUaAction:
       if (!root || !root->View())
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
index 10c3a1f..b7462ec3 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
@@ -127,6 +127,10 @@
 
     LayoutRect bounding_box = LayoutRect(ComputeTextRect(range));
 
+    // Set the bounding box height to zero because we want to center the top of
+    // the text range.
+    bounding_box.SetHeight(LayoutUnit());
+
     DCHECK(range.Nodes().begin() != range.Nodes().end());
 
     Node& node = *range.Nodes().begin();
@@ -136,7 +140,7 @@
     node.GetLayoutObject()->ScrollRectToVisible(
         bounding_box,
         WebScrollIntoViewParams(ScrollAlignment::kAlignCenterIfNeeded,
-                                ScrollAlignment::kAlignToEdgeIfNeeded,
+                                ScrollAlignment::kAlignCenterIfNeeded,
                                 kProgrammaticScroll));
   }
   EphemeralRange dom_range =
@@ -145,7 +149,7 @@
   // TODO(nburris): Determine what we should do with overlapping text matches.
   // Currently, AddTextMatchMarker will crash when adding an overlapping marker.
   frame_->GetDocument()->Markers().AddTextMatchMarker(
-      dom_range, TextMatchMarker::MatchStatus::kActive);
+      dom_range, TextMatchMarker::MatchStatus::kInactive);
   frame_->GetEditor().SetMarkedTextMatchesAreHighlighted(true);
 }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index c7008b0..29d032e 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -143,9 +143,10 @@
 
 // ::before, ::after and ::first-letter can be hit test targets.
 bool CanBeHitTestTargetPseudoNode(const Node& node) {
-  if (!node.IsPseudoElement())
+  auto* pseudo_element = DynamicTo<PseudoElement>(node);
+  if (!pseudo_element)
     return false;
-  switch (ToPseudoElement(node).GetPseudoId()) {
+  switch (pseudo_element->GetPseudoId()) {
     case kPseudoIdBefore:
     case kPseudoIdAfter:
     case kPseudoIdFirstLetter:
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.cc b/third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.cc
index a459495..1d939bc 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.cc
@@ -81,15 +81,23 @@
 }
 
 gfx::Rect ScrollbarLayerDelegate::TrackRect() const {
-  return theme_.TrackRect(*scrollbar_);
+  IntRect track_rect = theme_.TrackRect(*scrollbar_);
+  track_rect.MoveBy(-scrollbar_->Location());
+  return track_rect;
 }
 
 gfx::Rect ScrollbarLayerDelegate::BackButtonRect() const {
-  return theme_.BackButtonRect(*scrollbar_, blink::kBackButtonStartPart);
+  IntRect back_button_rect =
+      theme_.BackButtonRect(*scrollbar_, blink::kBackButtonStartPart);
+  back_button_rect.MoveBy(-scrollbar_->Location());
+  return back_button_rect;
 }
 
 gfx::Rect ScrollbarLayerDelegate::ForwardButtonRect() const {
-  return theme_.ForwardButtonRect(*scrollbar_, blink::kForwardButtonEndPart);
+  IntRect forward_button_rect =
+      theme_.ForwardButtonRect(*scrollbar_, blink::kForwardButtonEndPart);
+  forward_button_rect.MoveBy(-scrollbar_->Location());
+  return forward_button_rect;
 }
 
 float ScrollbarLayerDelegate::ThumbOpacity() const {
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.h b/third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.h
index 2192d20c..1f80dc65 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.h
@@ -38,9 +38,16 @@
   gfx::Point Location() const override;
   int ThumbThickness() const override;
   int ThumbLength() const override;
+
+  // Returns the track rect relative to the scrollbar's origin.
   gfx::Rect TrackRect() const override;
+
+  // Returns the back button rect relative to the scrollbar's origin.
   gfx::Rect BackButtonRect() const override;
+
+  // Returns the forward button rect relative to the scrollbar's origin.
   gfx::Rect ForwardButtonRect() const override;
+
   float ThumbOpacity() const override;
   bool NeedsPaintPart(cc::ScrollbarPart part) const override;
   bool HasTickmarks() const override;
diff --git a/third_party/blink/renderer/core/timing/window_performance.cc b/third_party/blink/renderer/core/timing/window_performance.cc
index b81f61b9..2267206 100644
--- a/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/third_party/blink/renderer/core/timing/window_performance.cc
@@ -62,7 +62,7 @@
 // Events taking longer than this threshold to finish being processed are
 // regarded as long-latency events by event-timing. Shorter-latency events are
 // ignored to reduce performance impact.
-constexpr int kEventTimingDurationThresholdInMs = 50;
+constexpr int kEventTimingDurationThresholdInMs = 104;
 
 String GetFrameAttribute(HTMLFrameOwnerElement* frame_owner,
                          const QualifiedName& attr_name,
@@ -379,7 +379,7 @@
             PerformanceEventTiming::CreateFirstInputTiming(entry));
       }
     }
-    if (duration_in_ms <= kEventTimingDurationThresholdInMs)
+    if (duration_in_ms < kEventTimingDurationThresholdInMs)
       continue;
 
     if (HasObserverFor(PerformanceEntry::kEvent)) {
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_writer.cc b/third_party/blink/renderer/modules/filesystem/file_system_writer.cc
index 91dfebd..56d3c0a 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_writer.cc
+++ b/third_party/blink/renderer/modules/filesystem/file_system_writer.cc
@@ -4,16 +4,17 @@
 
 #include "third_party/blink/renderer/modules/filesystem/file_system_writer.h"
 
+#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_blob.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
-#include "third_party/blink/renderer/bindings/modules/v8/blob_or_readable_stream.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/fetch/fetch_data_loader.h"
 #include "third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h"
 #include "third_party/blink/renderer/core/fileapi/blob.h"
 #include "third_party/blink/renderer/core/fileapi/file_error.h"
 #include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/platform/blob/blob_data.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
@@ -23,15 +24,36 @@
   DCHECK(writer_);
 }
 
-ScriptPromise FileSystemWriter::write(ScriptState* script_state,
-                                      uint64_t position,
-                                      const BlobOrReadableStream& data,
-                                      ExceptionState& exception_state) {
+ScriptPromise FileSystemWriter::write(
+    ScriptState* script_state,
+    uint64_t position,
+    const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
+    ExceptionState& exception_state) {
   DCHECK(!data.IsNull());
-  if (data.IsBlob())
-    return WriteBlob(script_state, position, data.GetAsBlob());
-  return WriteStream(script_state, position, data.GetAsReadableStream(),
-                     exception_state);
+
+  auto blob_data = std::make_unique<BlobData>();
+  Blob* blob = nullptr;
+  if (data.IsArrayBuffer()) {
+    DOMArrayBuffer* array_buffer = data.GetAsArrayBuffer();
+    blob_data->AppendBytes(array_buffer->Data(), array_buffer->ByteLength());
+  } else if (data.IsArrayBufferView()) {
+    DOMArrayBufferView* array_buffer_view = data.GetAsArrayBufferView().View();
+    blob_data->AppendBytes(array_buffer_view->BaseAddress(),
+                           array_buffer_view->byteLength());
+  } else if (data.IsBlob()) {
+    blob = data.GetAsBlob();
+  } else if (data.IsUSVString()) {
+    // Let the developer be explicit about line endings.
+    blob_data->AppendText(data.GetAsUSVString(),
+                          /*normalize_line_endings_to_native=*/false);
+  }
+
+  if (!blob) {
+    uint64_t size = blob_data->length();
+    blob = Blob::Create(BlobDataHandle::Create(std::move(blob_data), size));
+  }
+
+  return WriteBlob(script_state, position, blob);
 }
 
 ScriptPromise FileSystemWriter::WriteBlob(ScriptState* script_state,
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_writer.h b/third_party/blink/renderer/modules/filesystem/file_system_writer.h
index 43306aa..d6a5874 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_writer.h
+++ b/third_party/blink/renderer/modules/filesystem/file_system_writer.h
@@ -6,12 +6,12 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_WRITER_H_
 
 #include "third_party/blink/public/mojom/filesystem/file_writer.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
 namespace blink {
 
 class Blob;
-class BlobOrReadableStream;
 class ExceptionState;
 class FetchDataLoader;
 class ReadableStream;
@@ -27,7 +27,7 @@
 
   ScriptPromise write(ScriptState*,
                       uint64_t position,
-                      const BlobOrReadableStream& data,
+                      const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data,
                       ExceptionState&);
   ScriptPromise truncate(ScriptState*, uint64_t size);
   ScriptPromise close(ScriptState*);
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_writer.idl b/third_party/blink/renderer/modules/filesystem/file_system_writer.idl
index ac4ff2f..57d46f5 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_writer.idl
+++ b/third_party/blink/renderer/modules/filesystem/file_system_writer.idl
@@ -7,7 +7,7 @@
     NoInterfaceObject,
     RuntimeEnabled=NativeFileSystem
 ] interface FileSystemWriter {
-    [CallWith=ScriptState, RaisesException] Promise<void> write(unsigned long long position, (Blob or ReadableStream) data);
+    [CallWith=ScriptState, RaisesException] Promise<void> write(unsigned long long position, (BufferSource or Blob or USVString) data);
     [CallWith=ScriptState] Promise<void> truncate(unsigned long long size);
 
     [CallWith=ScriptState] Promise<void> close();
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_cursor.h b/third_party/blink/renderer/modules/indexeddb/idb_cursor.h
index 6df0b0a9..c329255 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_cursor.h
+++ b/third_party/blink/renderer/modules/indexeddb/idb_cursor.h
@@ -72,6 +72,7 @@
   ScriptValue key(ScriptState*);
   ScriptValue primaryKey(ScriptState*);
   ScriptValue value(ScriptState*);
+  IDBRequest* request() { return request_.Get(); }
   void source(Source&) const;
 
   IDBRequest* update(ScriptState*, const ScriptValue&, ExceptionState&);
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl b/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl
index aa1ce76..eab40294 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl
+++ b/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl
@@ -41,6 +41,7 @@
     readonly attribute IDBCursorDirection direction;
     [CallWith=ScriptState, CachedAttribute=isKeyDirty] readonly attribute any key;
     [CallWith=ScriptState, CachedAttribute=isPrimaryKeyDirty] readonly attribute any primaryKey;
+    [SameObject] readonly attribute IDBRequest request;
 
     [RaisesException] void advance([EnforceRange] unsigned long count);
     [CallWith=ScriptState, ImplementedAs=Continue, RaisesException] void continue([DefaultValue=Undefined] optional any key);
diff --git a/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc b/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc
index 42ba74ec..f151df43 100644
--- a/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc
+++ b/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc
@@ -25,6 +25,9 @@
 #include "media/base/video_util.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/web/modules/mediastream/video_track_adapter_settings.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
 
 namespace blink {
@@ -116,6 +119,16 @@
 
 }  // anonymous namespace
 
+// Template specialization of [1], needed to be able to pass WTF callbacks
+// that have VideoTrackAdapterSettings parameters across threads.
+//
+// [1] third_party/blink/renderer/platform/cross_thread_copier.h.
+template <>
+struct CrossThreadCopier<VideoTrackAdapterSettings>
+    : public CrossThreadCopierPassThrough<VideoTrackAdapterSettings> {
+  STATIC_ONLY(CrossThreadCopier);
+};
+
 // VideoFrameResolutionAdapter is created on and lives on the IO-thread. It does
 // the resolution adaptation and delivers frames to all registered tracks on the
 // IO-thread. All method calls must be on the IO-thread.
@@ -331,8 +344,8 @@
               kResolutionAdapterWrappingFrameForCroppingFailed);
       return;
     }
-    video_frame->AddDestructionObserver(
-        base::BindOnce(&TrackReleaseOriginalFrame, frame));
+    video_frame->AddDestructionObserver(ConvertToBaseCallback(
+        CrossThreadBind(&TrackReleaseOriginalFrame, frame)));
 
     DVLOG(3) << "desired size  " << desired_size.ToString()
              << " output natural size "
@@ -469,8 +482,8 @@
 void VideoTrackAdapter::VideoFrameResolutionAdapter::
     PostFrameDroppedToMainTaskRunner(
         media::VideoCaptureFrameDropReason reason) {
-  renderer_task_runner_->PostTask(FROM_HERE,
-                                  base::BindOnce(frame_dropped_cb_, reason));
+  PostCrossThreadTask(*renderer_task_runner_, FROM_HERE,
+                      CrossThreadBind(frame_dropped_cb_, reason));
 }
 
 VideoTrackAdapter::VideoTrackAdapter(
@@ -532,9 +545,10 @@
 
 void VideoTrackAdapter::RemoveTrack(const MediaStreamVideoTrack* track) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  io_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&VideoTrackAdapter::RemoveTrackOnIO, this, track));
+  PostCrossThreadTask(
+      *io_task_runner_, FROM_HERE,
+      CrossThreadBind(&VideoTrackAdapter::RemoveTrackOnIO, WrapRefCounted(this),
+                      CrossThreadUnretained(track)));
 }
 
 void VideoTrackAdapter::ReconfigureTrack(
@@ -542,9 +556,10 @@
     const VideoTrackAdapterSettings& settings) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  io_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&VideoTrackAdapter::ReconfigureTrackOnIO, this,
-                                track, settings));
+  PostCrossThreadTask(*io_task_runner_, FROM_HERE,
+                      CrossThreadBind(&VideoTrackAdapter::ReconfigureTrackOnIO,
+                                      WrapRefCounted(this),
+                                      CrossThreadUnretained(track), settings));
 }
 
 void VideoTrackAdapter::StartFrameMonitoring(
@@ -563,16 +578,18 @@
 
 void VideoTrackAdapter::StopFrameMonitoring() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  io_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&VideoTrackAdapter::StopFrameMonitoringOnIO, this));
+  PostCrossThreadTask(
+      *io_task_runner_, FROM_HERE,
+      CrossThreadBind(&VideoTrackAdapter::StopFrameMonitoringOnIO,
+                      WrapRefCounted(this)));
 }
 
 void VideoTrackAdapter::SetSourceFrameSize(const IntSize& source_frame_size) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  io_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&VideoTrackAdapter::SetSourceFrameSizeOnIO,
-                                this, source_frame_size));
+  PostCrossThreadTask(
+      *io_task_runner_, FROM_HERE,
+      CrossThreadBind(&VideoTrackAdapter::SetSourceFrameSizeOnIO,
+                      WrapRefCounted(this), source_frame_size));
 }
 
 bool VideoTrackAdapter::CalculateDesiredSize(
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 b2a9658..7fd4971b 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
@@ -194,10 +194,15 @@
   return consumer_;
 }
 
+bool RTCIceTransport::IsFromPeerConnection() const {
+  return peer_connection_;
+}
+
 IceTransportProxy* RTCIceTransport::ConnectConsumer(
     RTCQuicTransport* consumer) {
   DCHECK(consumer);
   DCHECK(proxy_);
+  DCHECK(!peer_connection_);
   if (!consumer_) {
     consumer_ = consumer;
   } else {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
index 687578da..c4d027f 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
@@ -102,6 +102,21 @@
   // a QuicTransportProxy. It may be called repeatedly with the same
   // RTCQuicTransport.
   bool HasConsumer() const;
+  // If |this| was created from an RTCPeerConnection.
+  //
+  // Background: This is because we don't reuse an RTCIceTransport that has been
+  // created from an RTCPeerConnection for an RTCQuicTransport (see
+  // bugs.webrtc.org/10591). The core issue here is that the source of truth for
+  // connecting a consumer to ICE is at the P2PTransportChannel. In the case of
+  // RTCPeerConnection, the P2PTransportChannel is already connected and given
+  // to the RTCIceTransport. In the case of the RTCQuicTransport it uses the
+  // RTCIceTransport as the source of truth for enforcing just one connected
+  // consumer. Possible fixes to this issue could include: -Use the
+  // P2PTransportChannel as the source of truth directly (calling this
+  // synchronously from the main thread)
+  // -Asynchronously connect to the P2PTransport - if the count of connected
+  // transports to the P2PTransportChannel is > 1, then throw an exception.
+  bool IsFromPeerConnection() const;
   IceTransportProxy* ConnectConsumer(RTCQuicTransport* consumer);
   void DisconnectConsumer(RTCQuicTransport* consumer);
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
index d2b436cf..5b944b10 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
@@ -115,6 +115,14 @@
                                       "has a connected RTCQuicTransport.");
     return nullptr;
   }
+  if (transport->IsFromPeerConnection()) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "Cannot construct an RTCQuicTransport "
+        "with an RTCIceTransport that came from an "
+        "RTCPeerConnection.");
+    return nullptr;
+  }
   for (const auto& certificate : certificates) {
     if (certificate->expires() < ConvertSecondsToDOMTimeStamp(CurrentTime())) {
       exception_state.ThrowTypeError(
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 2bbf4f6a..0bc2a989 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1026,6 +1026,7 @@
     "graphics/intercepting_canvas.h",
     "graphics/interpolation_space.cc",
     "graphics/interpolation_space.h",
+    "graphics/lab_color_space.h",
     "graphics/link_highlight.h",
     "graphics/logging_canvas.cc",
     "graphics/logging_canvas.h",
@@ -1743,6 +1744,7 @@
     "graphics/gpu/webgl_image_conversion_test.cc",
     "graphics/gpu/webgpu_swap_buffer_provider_test.cc",
     "graphics/graphics_context_test.cc",
+    "graphics/lab_color_space_test.cc",
     "graphics/paint/cull_rect_test.cc",
     "graphics/paint/display_item_client_test.cc",
     "graphics/paint/display_item_raster_invalidator_test.cc",
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index d217c0b..cef9e09 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -2584,12 +2584,46 @@
       .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
   Update(artifact.Build());
 
+  if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
+    // Expectation in effect stack diagram:
+    //           l1
+    // l0
+    // [ mask_isolation_0 ]
+    // [        e0        ]
+    // One content layer.
+    ASSERT_EQ(1u, RootLayer()->children().size());
+    ASSERT_EQ(1u, ContentLayerCount());
+    // There is still a "synthesized layer" but it's null.
+    ASSERT_EQ(1u, SynthesizedClipLayerCount());
+    EXPECT_FALSE(SynthesizedClipLayerAt(0));
+
+    const cc::Layer* content0 = RootLayer()->children()[0].get();
+
+    constexpr int c0_id = 1;
+    constexpr int e0_id = 1;
+
+    EXPECT_EQ(ContentLayerAt(0), content0);
+    int c1_id = content0->clip_tree_index();
+    const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id);
+    EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip);
+    ASSERT_EQ(c0_id, cc_c1.parent_id);
+    int mask_isolation_0_id = content0->effect_tree_index();
+    const cc::EffectNode& mask_isolation_0 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id);
+    ASSERT_EQ(e0_id, mask_isolation_0.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
+    EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_0.rounded_corner_bounds);
+    return;
+  }
+
   // Expectation in effect stack diagram:
   //           l1
   // l0 [ mask_effect_0 ]
   // [ mask_isolation_0 ]
   // [        e0        ]
-  // One content layer, one clip mask.
+  // One content layer.
   ASSERT_EQ(2u, RootLayer()->children().size());
   ASSERT_EQ(1u, ContentLayerCount());
   ASSERT_EQ(1u, SynthesizedClipLayerCount());
@@ -2725,6 +2759,44 @@
       .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
   Update(artifact.Build());
 
+  if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
+    // Expectation in effect stack diagram:
+    //   l0         l1
+    // [ e1 ]
+    // [  mask_isolation_0   ]
+    // [         e0          ]
+    // One content layer, one clip mask.
+    ASSERT_EQ(1u, RootLayer()->children().size());
+    ASSERT_EQ(1u, ContentLayerCount());
+    // There is still a "synthesized layer" but it's null.
+    ASSERT_EQ(1u, SynthesizedClipLayerCount());
+    EXPECT_FALSE(SynthesizedClipLayerAt(0));
+
+    const cc::Layer* content0 = RootLayer()->children()[0].get();
+
+    constexpr int c0_id = 1;
+    constexpr int e0_id = 1;
+
+    EXPECT_EQ(ContentLayerAt(0), content0);
+    int c1_id = content0->clip_tree_index();
+    const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id);
+    EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip);
+    ASSERT_EQ(c0_id, cc_c1.parent_id);
+    int e1_id = content0->effect_tree_index();
+    const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id);
+    EXPECT_EQ(c1_id, cc_e1.clip_id);
+    int mask_isolation_0_id = cc_e1.parent_id;
+    const cc::EffectNode& mask_isolation_0 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id);
+    ASSERT_EQ(e0_id, mask_isolation_0.parent_id);
+    EXPECT_EQ(c1_id, mask_isolation_0.clip_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
+    EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 0),
+              mask_isolation_0.rounded_corner_bounds);
+    return;
+  }
+
   // Expectation in effect stack diagram:
   //   l0         l1
   // [ e1 ][ mask_effect_0 ]
@@ -2785,6 +2857,52 @@
       .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
   Update(artifact.Build());
 
+  if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
+    // Expectation in effect stack diagram:
+    //              l2
+    // l0 l1
+    // [  mask_isolation_0   ]
+    // [         e0          ]
+    // Two content layers, one clip mask.
+    ASSERT_EQ(2u, RootLayer()->children().size());
+    ASSERT_EQ(2u, ContentLayerCount());
+    // There is still a "synthesized layer" but it's null.
+    ASSERT_EQ(1u, SynthesizedClipLayerCount());
+    EXPECT_FALSE(SynthesizedClipLayerAt(0));
+
+    const cc::Layer* content0 = RootLayer()->children()[0].get();
+    const cc::Layer* content1 = RootLayer()->children()[1].get();
+
+    constexpr int t0_id = 1;
+    constexpr int c0_id = 1;
+    constexpr int e0_id = 1;
+
+    EXPECT_EQ(ContentLayerAt(0), content0);
+    EXPECT_EQ(t0_id, content0->transform_tree_index());
+    int c1_id = content0->clip_tree_index();
+    const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id);
+    EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip);
+    ASSERT_EQ(c0_id, cc_c1.parent_id);
+    int mask_isolation_0_id = content0->effect_tree_index();
+    const cc::EffectNode& mask_isolation_0 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id);
+    ASSERT_EQ(e0_id, mask_isolation_0.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
+
+    EXPECT_EQ(ContentLayerAt(1), content1);
+    int t1_id = content1->transform_tree_index();
+    const cc::TransformNode& cc_t1 =
+        *GetPropertyTrees().transform_tree.Node(t1_id);
+    ASSERT_EQ(t0_id, cc_t1.parent_id);
+    EXPECT_EQ(c1_id, content1->clip_tree_index());
+    EXPECT_EQ(mask_isolation_0_id, content1->effect_tree_index());
+
+    EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_0.rounded_corner_bounds);
+    return;
+  }
+
   // Expectation in effect stack diagram:
   //              l2
   // l0 l1 [ mask_effect_0 ]
@@ -2855,6 +2973,66 @@
       .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
   Update(artifact.Build());
 
+  if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
+    // Expectation in effect stack diagram:
+    //           l1                      l4
+    // l0                   l3
+    // [ mask_isolation_0 ] l2 [ mask_isolation_1 ]
+    // [                    e0                    ]
+    // Three content layers.
+    ASSERT_EQ(3u, RootLayer()->children().size());
+    ASSERT_EQ(3u, ContentLayerCount());
+    // There are still "synthesized layers" but they're null.
+    ASSERT_EQ(2u, SynthesizedClipLayerCount());
+    EXPECT_FALSE(SynthesizedClipLayerAt(0));
+    EXPECT_FALSE(SynthesizedClipLayerAt(1));
+
+    const cc::Layer* content0 = RootLayer()->children()[0].get();
+    const cc::Layer* content1 = RootLayer()->children()[1].get();
+    const cc::Layer* content2 = RootLayer()->children()[2].get();
+
+    constexpr int t0_id = 1;
+    constexpr int c0_id = 1;
+    constexpr int e0_id = 1;
+
+    EXPECT_EQ(ContentLayerAt(0), content0);
+    EXPECT_EQ(t0_id, content0->transform_tree_index());
+    int c1_id = content0->clip_tree_index();
+    const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id);
+    EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip);
+    ASSERT_EQ(c0_id, cc_c1.parent_id);
+    int mask_isolation_0_id = content0->effect_tree_index();
+    const cc::EffectNode& mask_isolation_0 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id);
+    ASSERT_EQ(e0_id, mask_isolation_0.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
+    EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_0.rounded_corner_bounds);
+
+    EXPECT_EQ(ContentLayerAt(1), content1);
+    int t1_id = content1->transform_tree_index();
+    const cc::TransformNode& cc_t1 =
+        *GetPropertyTrees().transform_tree.Node(t1_id);
+    ASSERT_EQ(t0_id, cc_t1.parent_id);
+    EXPECT_EQ(c0_id, content1->clip_tree_index());
+    EXPECT_EQ(e0_id, content1->effect_tree_index());
+
+    EXPECT_EQ(ContentLayerAt(2), content2);
+    EXPECT_EQ(t0_id, content2->transform_tree_index());
+    EXPECT_EQ(c1_id, content2->clip_tree_index());
+    int mask_isolation_1_id = content2->effect_tree_index();
+    const cc::EffectNode& mask_isolation_1 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_1_id);
+    EXPECT_NE(mask_isolation_0_id, mask_isolation_1_id);
+    ASSERT_EQ(e0_id, mask_isolation_1.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_1.blend_mode);
+    EXPECT_TRUE(mask_isolation_1.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_1.rounded_corner_bounds);
+    return;
+  }
+
   // Expectation in effect stack diagram:
   //           l1                      l4
   // l0 [ mask_effect_0 ]    l3 [ mask_effect_1 ]
@@ -2945,6 +3123,56 @@
       .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
   Update(artifact.Build());
 
+  if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
+    // Expectation in effect stack diagram:
+    //      l1             l3
+    // l0 [ e1 ] l2
+    // [      mask_isolation_0      ]
+    // [             e0             ]
+    // Three content layers.
+    ASSERT_EQ(3u, RootLayer()->children().size());
+    ASSERT_EQ(3u, ContentLayerCount());
+    // There is still a "synthesized layer" but it's null.
+    ASSERT_EQ(1u, SynthesizedClipLayerCount());
+    EXPECT_FALSE(SynthesizedClipLayerAt(0));
+
+    const cc::Layer* content0 = RootLayer()->children()[0].get();
+    const cc::Layer* content1 = RootLayer()->children()[1].get();
+    const cc::Layer* content2 = RootLayer()->children()[2].get();
+
+    constexpr int c0_id = 1;
+    constexpr int e0_id = 1;
+
+    EXPECT_EQ(ContentLayerAt(0), content0);
+    int c1_id = content0->clip_tree_index();
+    const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id);
+    EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip);
+    ASSERT_EQ(c0_id, cc_c1.parent_id);
+    int mask_isolation_0_id = content0->effect_tree_index();
+    const cc::EffectNode& mask_isolation_0 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id);
+    ASSERT_EQ(e0_id, mask_isolation_0.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
+
+    EXPECT_EQ(ContentLayerAt(1), content1);
+    EXPECT_EQ(c1_id, content1->clip_tree_index());
+    int e1_id = content1->effect_tree_index();
+    const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id);
+    ASSERT_EQ(mask_isolation_0_id, cc_e1.parent_id);
+
+    EXPECT_EQ(ContentLayerAt(2), content2);
+    EXPECT_EQ(c1_id, content2->clip_tree_index());
+    EXPECT_EQ(mask_isolation_0_id, content2->effect_tree_index());
+
+    int e2_id = content2->effect_tree_index();
+    const cc::EffectNode& cc_e2 = *GetPropertyTrees().effect_tree.Node(e2_id);
+    EXPECT_TRUE(cc_e2.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_0.rounded_corner_bounds);
+
+    return;
+  }
+
   // Expectation in effect stack diagram:
   //      l1             l3
   // l0 [ e1 ] l2 [ mask_effect_0 ]
@@ -3017,6 +3245,72 @@
       .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
   Update(artifact.Build());
 
+  if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
+    // Expectation in effect stack diagram:
+    //                               l3
+    //           l1        l2                         l5
+    // l0                   [ mask_isolation_1 ] l4
+    // [ mask_isolation_0 ][        e1        ][ mask_isolation_2  ]
+    // [                            e0                             ]
+    // Three content layers.
+    ASSERT_EQ(3u, RootLayer()->children().size());
+    ASSERT_EQ(3u, ContentLayerCount());
+    // There are still "synthesized layers" but they're null.
+    ASSERT_EQ(3u, SynthesizedClipLayerCount());
+    EXPECT_FALSE(SynthesizedClipLayerAt(0));
+    EXPECT_FALSE(SynthesizedClipLayerAt(1));
+    EXPECT_FALSE(SynthesizedClipLayerAt(2));
+
+    const cc::Layer* content0 = RootLayer()->children()[0].get();
+    const cc::Layer* content1 = RootLayer()->children()[1].get();
+    const cc::Layer* content2 = RootLayer()->children()[2].get();
+
+    constexpr int c0_id = 1;
+    constexpr int e0_id = 1;
+
+    EXPECT_EQ(ContentLayerAt(0), content0);
+    int c1_id = content0->clip_tree_index();
+    const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id);
+    EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip);
+    ASSERT_EQ(c0_id, cc_c1.parent_id);
+    int mask_isolation_0_id = content0->effect_tree_index();
+    const cc::EffectNode& mask_isolation_0 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id);
+    ASSERT_EQ(e0_id, mask_isolation_0.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
+    EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_0.rounded_corner_bounds);
+
+    EXPECT_EQ(ContentLayerAt(1), content1);
+    EXPECT_EQ(c1_id, content1->clip_tree_index());
+    int mask_isolation_1_id = content1->effect_tree_index();
+    const cc::EffectNode& mask_isolation_1 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_1_id);
+    EXPECT_NE(mask_isolation_0_id, mask_isolation_1_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_1.blend_mode);
+    int e1_id = mask_isolation_1.parent_id;
+    const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id);
+    ASSERT_EQ(e0_id, cc_e1.parent_id);
+    EXPECT_TRUE(mask_isolation_1.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_1.rounded_corner_bounds);
+
+    EXPECT_EQ(ContentLayerAt(2), content2);
+    EXPECT_EQ(c1_id, content2->clip_tree_index());
+    int mask_isolation_2_id = content2->effect_tree_index();
+    const cc::EffectNode& mask_isolation_2 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_2_id);
+    EXPECT_NE(mask_isolation_0_id, mask_isolation_2_id);
+    EXPECT_NE(mask_isolation_1_id, mask_isolation_2_id);
+    ASSERT_EQ(e0_id, mask_isolation_2.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_2.blend_mode);
+    EXPECT_TRUE(mask_isolation_2.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_2.rounded_corner_bounds);
+    return;
+  }
+
   // Expectation in effect stack diagram:
   //                               l3
   //           l1        l2 [ mask_effect_1 ]           l5
@@ -3123,6 +3417,73 @@
       .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
   Update(artifact.Build());
 
+  if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
+    // Expectation in effect stack diagram:
+    //           l1          l2         l3                   l5
+    // l0                  [ e1 ]               l4
+    // [ mask_isolation_0 ][  mask_isolation_1   ][ mask_isolation_2  ]
+    // [                              e0                              ]
+    // Three content layers.
+    ASSERT_EQ(3u, RootLayer()->children().size());
+    ASSERT_EQ(3u, ContentLayerCount());
+    // There are still "synthesized layers" but they're null.
+    ASSERT_EQ(3u, SynthesizedClipLayerCount());
+    EXPECT_FALSE(SynthesizedClipLayerAt(0));
+    EXPECT_FALSE(SynthesizedClipLayerAt(1));
+    EXPECT_FALSE(SynthesizedClipLayerAt(2));
+
+    const cc::Layer* content0 = RootLayer()->children()[0].get();
+    const cc::Layer* content1 = RootLayer()->children()[1].get();
+    const cc::Layer* content2 = RootLayer()->children()[2].get();
+
+    constexpr int c0_id = 1;
+    constexpr int e0_id = 1;
+
+    EXPECT_EQ(ContentLayerAt(0), content0);
+    int c1_id = content0->clip_tree_index();
+    const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id);
+    EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip);
+    ASSERT_EQ(c0_id, cc_c1.parent_id);
+    int mask_isolation_0_id = content0->effect_tree_index();
+    const cc::EffectNode& mask_isolation_0 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id);
+    ASSERT_EQ(e0_id, mask_isolation_0.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
+    EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_0.rounded_corner_bounds);
+
+    EXPECT_EQ(ContentLayerAt(1), content1);
+    EXPECT_EQ(c1_id, content1->clip_tree_index());
+    int e1_id = content1->effect_tree_index();
+    const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, cc_e1.blend_mode);
+    int mask_isolation_1_id = cc_e1.parent_id;
+    const cc::EffectNode& mask_isolation_1 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_1_id);
+    EXPECT_NE(mask_isolation_0_id, mask_isolation_1_id);
+    ASSERT_EQ(e0_id, mask_isolation_1.parent_id);
+    EXPECT_EQ(SkBlendMode::kMultiply, mask_isolation_1.blend_mode);
+    EXPECT_TRUE(mask_isolation_1.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_1.rounded_corner_bounds);
+
+    EXPECT_EQ(ContentLayerAt(2), content2);
+    EXPECT_EQ(c1_id, content2->clip_tree_index());
+    int mask_isolation_2_id = content2->effect_tree_index();
+    const cc::EffectNode& mask_isolation_2 =
+        *GetPropertyTrees().effect_tree.Node(mask_isolation_2_id);
+    EXPECT_NE(mask_isolation_0_id, mask_isolation_2_id);
+    EXPECT_NE(mask_isolation_1_id, mask_isolation_2_id);
+    ASSERT_EQ(e0_id, mask_isolation_2.parent_id);
+    EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode);
+    EXPECT_TRUE(mask_isolation_2.is_fast_rounded_corner);
+    EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 5),
+              mask_isolation_2.rounded_corner_bounds);
+
+    return;
+  }
+
   // Expectation in effect stack diagram:
   //           l1          l2         l3                   l5
   // l0 [ mask_effect_0 ][ e1 ][ mask_effect_1 ] l4 [ mask_effect_2 ]
@@ -3898,6 +4259,31 @@
   EXPECT_EQ(cc_effect->clip_id, cc_clip->parent_id);
 }
 
+TEST_P(PaintArtifactCompositorTest, Non2dAxisAlignedRoundedRectClip) {
+  auto rotate = CreateTransform(t0(), TransformationMatrix().Rotate(45));
+  FloatSize corner(5, 5);
+  FloatRoundedRect rounded_clip(FloatRect(50, 50, 50, 50), corner, corner,
+                                corner, corner);
+  auto clip = CreateClip(c0(), *rotate, rounded_clip);
+  auto opacity = CreateOpacityEffect(
+      e0(), 0.5f, CompositingReason::kActiveOpacityAnimation);
+
+  TestPaintArtifact artifact;
+  artifact.Chunk(t0(), *clip, *opacity)
+      .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite);
+  Update(artifact.Build());
+  ASSERT_EQ(1u, ContentLayerCount());
+
+  // We should create a synthetic effect node for the non-2d-axis-aligned clip.
+  int clip_id = ContentLayerAt(0)->clip_tree_index();
+  const auto* cc_clip = GetPropertyTrees().clip_tree.Node(clip_id);
+  int effect_id = ContentLayerAt(0)->effect_tree_index();
+  const auto* cc_effect = GetPropertyTrees().effect_tree.Node(effect_id);
+  EXPECT_OPACITY(effect_id, 1.f, kHasRenderSurface);
+  EXPECT_OPACITY(cc_effect->parent_id, 0.5f, kNoRenderSurface);
+  EXPECT_EQ(cc_effect->clip_id, cc_clip->id);
+}
+
 TEST_P(PaintArtifactCompositorTest,
        Non2dAxisAlignedClipUnderLaterRenderSurface) {
   auto rotate1 =
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 0ee35c24..0c2265d 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -761,20 +761,19 @@
   return false;
 }
 
-base::Optional<PropertyTreeManager::CcEffectType>
-PropertyTreeManager::NeedsSyntheticEffect(
+PropertyTreeManager::CcEffectType PropertyTreeManager::SyntheticEffectType(
     const ClipPaintPropertyNode& clip) const {
+  unsigned effect_type = CcEffectType::kEffect;
   if (clip.ClipRect().IsRounded() || clip.ClipPath())
-    return CcEffectType::kSyntheticForNonTrivialClip;
+    effect_type |= CcEffectType::kSyntheticForNonTrivialClip;
 
   // Cc requires that a rectangluar clip is 2d-axis-aligned with the render
   // surface to correctly apply the clip.
   if (current_.may_be_2d_axis_misaligned_to_render_surface |
       TransformsMayBe2dAxisMisaligned(clip.LocalTransformSpace(),
                                       current_.Transform()))
-    return CcEffectType::kSyntheticFor2dAxisAlignment;
-
-  return base::nullopt;
+    effect_type |= CcEffectType::kSyntheticFor2dAxisAlignment;
+  return static_cast<CcEffectType>(effect_type);
 }
 
 SkBlendMode PropertyTreeManager::SynthesizeCcEffectsForClipsIfNeeded(
@@ -821,8 +820,8 @@
   Vector<PendingClip> pending_clips;
   for (; target_clip && target_clip != current_.clip;
        target_clip = SafeUnalias(target_clip->Parent())) {
-    if (auto type = NeedsSyntheticEffect(*target_clip))
-      pending_clips.emplace_back(PendingClip{target_clip, *type});
+    if (auto type = SyntheticEffectType(*target_clip))
+      pending_clips.emplace_back(PendingClip{target_clip, type});
   }
 
   if (!target_clip) {
@@ -844,7 +843,7 @@
     // surface which is axis-aligned with the clip.
     cc::EffectNode& synthetic_effect = *GetEffectTree().Node(
         GetEffectTree().Insert(cc::EffectNode(), current_.effect_id));
-    if (pending_clip.type == CcEffectType::kSyntheticForNonTrivialClip) {
+    if (pending_clip.type & CcEffectType::kSyntheticForNonTrivialClip) {
       synthetic_effect.clip_id = EnsureCompositorClipNode(*pending_clip.clip);
       // For non-trivial clip, isolation_effect.stable_id will be assigned later
       // when the effect is closed. For now the default value INVALID_STABLE_ID
@@ -863,23 +862,23 @@
     synthetic_effect.transform_id = EnsureCompositorTransformNode(transform);
     synthetic_effect.double_sided = !transform.IsBackfaceHidden();
 
-    if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
-      synthetic_effect.rounded_corner_bounds =
-          gfx::RRectF(pending_clip.clip->ClipRect());
-      synthetic_effect.is_fast_rounded_corner = true;
-    } else {
-      if (pending_clip.type == CcEffectType::kSyntheticForNonTrivialClip) {
+    if (pending_clip.type & CcEffectType::kSyntheticForNonTrivialClip) {
+      if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) {
+        synthetic_effect.rounded_corner_bounds =
+            gfx::RRectF(pending_clip.clip->ClipRect());
+        synthetic_effect.is_fast_rounded_corner = true;
+      } else {
         synthetic_effect.render_surface_reason =
             pending_clip.clip->ClipRect().IsRounded()
                 ? cc::RenderSurfaceReason::kRoundedCorner
                 : cc::RenderSurfaceReason::kClipPath;
-      } else {
-        synthetic_effect.render_surface_reason =
-            cc::RenderSurfaceReason::kClipAxisAlignment;
       }
-
       pending_synthetic_mask_layers_.insert(synthetic_effect.id);
     }
+    if (pending_clip.type & CcEffectType::kSyntheticFor2dAxisAlignment) {
+      synthetic_effect.render_surface_reason =
+          cc::RenderSurfaceReason::kClipAxisAlignment;
+    }
 
     // Clip and kDstIn do not commute. This shall never be reached because
     // kDstIn is only used internally to implement CSS clip-path and mask,
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
index 807028b..0bf293e 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
@@ -173,31 +173,28 @@
       cc::TransformNode&,
       const TransformPaintPropertyNode&);
 
-  bool IsCurrentCcEffectSynthetic() const {
-    return current_.effect_type != CcEffectType::kEffect;
-  }
+  bool IsCurrentCcEffectSynthetic() const { return current_.effect_type; }
   bool IsCurrentCcEffectSyntheticForNonTrivialClip() const {
-    return current_.effect_type == CcEffectType::kSyntheticForNonTrivialClip;
+    return current_.effect_type & CcEffectType::kSyntheticForNonTrivialClip;
   }
 
   // The type of operation the current cc effect node applies.
-  enum class CcEffectType {
+  enum CcEffectType {
     // The cc effect corresponds to a Blink effect node.
-    kEffect,
+    kEffect = 0,
     // The cc effect is synthetic for a blink clip node that has to be
     // rasterized because the clip is non-trivial.
-    kSyntheticForNonTrivialClip,
+    kSyntheticForNonTrivialClip = 1 << 0,
     // The cc effect is synthetic to create a render surface that is
     // 2d-axis-aligned with a blink clip node that is non-2d-axis-aligned
     // in the the original render surface. Cc requires a rectangular clip to be
     // 2d-axis-aligned with the render surface to correctly apply the clip.
     // TODO(crbug.com/504464): This will be changed when we move render surface
     // decision logic into the cc compositor thread.
-    kSyntheticFor2dAxisAlignment,
+    kSyntheticFor2dAxisAlignment = 1 << 1
   };
 
-  base::Optional<CcEffectType> NeedsSyntheticEffect(
-      const ClipPaintPropertyNode&) const;
+  CcEffectType SyntheticEffectType(const ClipPaintPropertyNode&) const;
 
   void SetCurrentEffectState(const cc::EffectNode&,
                              CcEffectType,
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
index 5d0233c2..3dd0ea23 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -35,6 +35,7 @@
   settings_ = new_settings;
 
   SkHighContrastConfig config;
+  transformer_ = base::nullopt;
   switch (settings_.mode) {
     case DarkMode::kOff:
       default_filter_.reset(nullptr);
@@ -58,6 +59,10 @@
     case DarkMode::kInvertLightness:
       config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
       break;
+    case DarkMode::kInvertLightnessLAB:
+      transformer_ = LabColorSpace::RGBLABTransformer();
+      config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
+      break;
   }
 
   config.fGrayscale = settings_.grayscale;
@@ -75,7 +80,10 @@
 Color DarkModeFilter::ApplyIfNeeded(const Color& color) {
   if (!default_filter_)
     return color;
-  return Color(default_filter_->filterColor(color.Rgb()));
+  if (!transformer_)
+    return Color(default_filter_->filterColor(color.Rgb()));
+
+  return InvertColor(color);
 }
 
 // TODO(gilmanmh): Investigate making |image| a const reference. This code
@@ -102,10 +110,25 @@
   if (flags.HasShader()) {
     dark_mode_flags.setColorFilter(default_filter_);
   } else {
-    dark_mode_flags.setColor(default_filter_->filterColor(flags.getColor()));
+    auto invertedColor = ApplyIfNeeded(flags.getColor());
+    dark_mode_flags.setColor(
+        SkColorSetRGB(invertedColor.Red(), invertedColor.Green(), invertedColor.Blue()));
   }
 
   return base::make_optional<cc::PaintFlags>(std::move(dark_mode_flags));
 }
 
+Color DarkModeFilter::InvertColor(const Color& color) const {
+  blink::FloatPoint3D rgb = {color.Red() / 255.0f, color.Green() / 255.0f,
+                             color.Blue() / 255.0f};
+  blink::FloatPoint3D lab = transformer_->sRGBToLab(rgb);
+  float invertedL = std::min(110.0f - lab.X(), 100.0f);
+  lab.SetX(invertedL);
+  rgb = transformer_->LabToSRGB(lab);
+
+  return Color(static_cast<unsigned int>(rgb.X() * 255 + 0.5),
+               static_cast<unsigned int>(rgb.Y() * 255 + 0.5),
+               static_cast<unsigned int>(rgb.Z() * 255 + 0.5), color.Alpha());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
index 3f8a1fae..da1114d 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
@@ -6,6 +6,7 @@
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
+#include "third_party/blink/renderer/platform/graphics/lab_color_space.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
 class SkColorFilter;
@@ -30,11 +31,14 @@
   base::Optional<cc::PaintFlags> ApplyToFlagsIfNeeded(
       const cc::PaintFlags& flags);
 
+  Color InvertColor(const Color& color) const;
+
  private:
   DarkModeSettings settings_;
 
   sk_sp<SkColorFilter> default_filter_;
   sk_sp<SkColorFilter> image_filter_;
+  base::Optional<LabColorSpace::RGBLABTransformer> transformer_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
index 21d1d9e2..e67c87d 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
@@ -14,6 +14,7 @@
   kSimpleInvertForTesting,
   kInvertBrightness,
   kInvertLightness,
+  kInvertLightnessLAB,
 };
 
 enum class DarkModeImagePolicy {
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index e7ede40..fdd1c06 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -79,7 +79,6 @@
   }
 
   operator const PaintFlags&() const { return *flags_; }
-
  private:
   const PaintFlags* flags_;
   base::Optional<PaintFlags> dark_mode_flags_;
diff --git a/third_party/blink/renderer/platform/graphics/lab_color_space.h b/third_party/blink/renderer/platform/graphics/lab_color_space.h
new file mode 100644
index 0000000..c470604
--- /dev/null
+++ b/third_party/blink/renderer/platform/graphics/lab_color_space.h
@@ -0,0 +1,172 @@
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_LAB_COLOR_SPACE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_LAB_COLOR_SPACE_H_
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <initializer_list>
+#include <iterator>
+
+#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
+
+// Class to handle color transformation between RGB and CIE L*a*b* color spaces.
+namespace LabColorSpace {
+
+using blink::FloatPoint3D;
+using blink::TransformationMatrix;
+
+static constexpr FloatPoint3D kIlluminantD50 =
+    FloatPoint3D(0.964212f, 1.0f, 0.825188f);
+static constexpr FloatPoint3D kIlluminantD65 =
+    FloatPoint3D(0.95042855f, 1.0f, 1.0889004f);
+
+// All matrices here are 3x3 matrices.
+// They are stored in blink::TransformationMatrix which is 4x4 matrix in the
+// following form.
+// |a b c 0|
+// |d e f 0|
+// |g h i 0|
+// |0 0 0 1|
+
+inline TransformationMatrix mul3x3Diag(const FloatPoint3D& lhs,
+                                       const TransformationMatrix& rhs) {
+  return TransformationMatrix(
+      lhs.X() * rhs.M11(), lhs.Y() * rhs.M12(), lhs.Z() * rhs.M13(), 0.0f,
+      lhs.X() * rhs.M21(), lhs.Y() * rhs.M22(), lhs.Z() * rhs.M23(), 0.0f,
+      lhs.X() * rhs.M31(), lhs.Y() * rhs.M32(), lhs.Z() * rhs.M33(), 0.0f,
+      0.0f, 0.0f, 0.0f, 1.0f);
+}
+
+template <typename T>
+inline constexpr T clamp(T x, T min, T max) {
+  return x < min ? min : x > max ? max : x;
+}
+
+// See https://en.wikipedia.org/wiki/Chromatic_adaptation#Von_Kries_transform.
+inline TransformationMatrix chromaticAdaptation(
+    const TransformationMatrix& matrix,
+    const FloatPoint3D& srcWhitePoint,
+    const FloatPoint3D& dstWhitePoint) {
+  FloatPoint3D srcLMS = matrix.MapPoint(srcWhitePoint);
+  FloatPoint3D dstLMS = matrix.MapPoint(dstWhitePoint);
+  // LMS is a diagonal matrix stored as a float[3]
+  FloatPoint3D LMS = {dstLMS.X() / srcLMS.X(), dstLMS.Y() / srcLMS.Y(),
+                      dstLMS.Z() / srcLMS.Z()};
+  return matrix.Inverse() * mul3x3Diag(LMS, matrix);
+}
+
+class sRGBColorSpace {
+ public:
+  FloatPoint3D toLinear(const FloatPoint3D& v) const {
+    auto EOTF = [](float u) {
+      return u < 0.04045f
+                 ? clamp(u / 12.92f, .0f, 1.0f)
+                 : clamp(std::pow((u + 0.055f) / 1.055f, 2.4f), .0f, 1.0f);
+    };
+    return {EOTF(v.X()), EOTF(v.Y()), EOTF(v.Z())};
+  }
+
+  FloatPoint3D fromLinear(const FloatPoint3D& v) const {
+    auto OETF = [](float u) {
+      return (u < 0.0031308f
+                  ? clamp(12.92 * u, .0, 1.0)
+                  : clamp(1.055 * std::pow(u, 1.0 / 2.4) - 0.055, .0, 1.0));
+    };
+    return {OETF(v.X()), OETF(v.Y()), OETF(v.Z())};
+  }
+
+  // See https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation.
+  FloatPoint3D toXYZ(const FloatPoint3D& rgb) const {
+    return transform_.MapPoint(toLinear(rgb));
+  }
+
+  // See
+  // https://en.wikipedia.org/wiki/SRGB#The_forward_transformation_(CIE_XYZ_to_sRGB).
+  FloatPoint3D fromXYZ(const FloatPoint3D& xyz) const {
+    return fromLinear(inverseTransform_.MapPoint(xyz));
+  }
+
+ private:
+  TransformationMatrix kBradford = TransformationMatrix(
+       0.8951f, -0.7502f,  0.0389f, 0.0f,
+       0.2664f,  1.7135f, -0.0685f, 0.0f,
+      -0.1614f,  0.0367f,  1.0296f, 0.0f,
+       0.0f,     0.0f,     0.0f,    1.0f);
+
+  TransformationMatrix xyzTransform = TransformationMatrix(
+      0.41238642f, 0.21263677f, 0.019330615f, 0.0f,
+      0.3575915f,  0.715183f,   0.11919712f,  0.0f,
+      0.18045056f, 0.07218022f, 0.95037293f,  0.0f,
+      0.0f,        0.0f,        0.0f,         1.0f);
+
+  TransformationMatrix transform_ =
+      chromaticAdaptation(kBradford, kIlluminantD65, kIlluminantD50) *
+      xyzTransform;
+  TransformationMatrix inverseTransform_ = transform_.Inverse();
+};
+
+class LABColorSpace {
+ public:
+  // See
+  // https://en.wikipedia.org/wiki/CIELAB_color_space#Reverse_transformation.
+  FloatPoint3D fromXYZ(const FloatPoint3D& v) const {
+    auto f = [](float x) {
+      return x > kSigma3 ? pow(x, 1.0f / 3.0f)
+                         : x / (3 * kSigma2) + 4.0f / 29.0f;
+    };
+
+    float fx = f(v.X() / kIlluminantD50.X());
+    float fy = f(v.Y() / kIlluminantD50.Y());
+    float fz = f(v.Z() / kIlluminantD50.Z());
+
+    float L = 116.0f * fy - 16.0f;
+    float a = 500.0f * (fx - fy);
+    float b = 200.0f * (fy - fz);
+
+    return {clamp(L, 0.0f, 100.0f), clamp(a, -128.0f, 128.0f),
+            clamp(b, -128.0f, 128.0f)};
+  }
+
+  // See
+  // https://en.wikipedia.org/wiki/CIELAB_color_space#Forward_transformation.
+  FloatPoint3D toXYZ(const FloatPoint3D& lab) const {
+    auto invf = [](float x) {
+      return x > kSigma ? pow(x, 3) : 3 * kSigma2 * (x - 4.0f / 29.0f);
+    };
+
+    FloatPoint3D v = {clamp(lab.X(), 0.0f, 100.0f),
+                      clamp(lab.Y(), -128.0f, 128.0f),
+                      clamp(lab.Z(), -128.0f, 128.0f)};
+
+    return {
+        invf((v.X() + 16.0f) / 116.0f + (v.Y() * 0.002f)) * kIlluminantD50.X(),
+        invf((v.X() + 16.0f) / 116.0f) * kIlluminantD50.Y(),
+        invf((v.X() + 16.0f) / 116.0f - (v.Z() * 0.005f)) * kIlluminantD50.Z()};
+  }
+
+ private:
+  static constexpr float kSigma = 6.0f / 29.0f;
+  static constexpr float kSigma2 = 36.0f / 841.0f;
+  static constexpr float kSigma3 = 216.0f / 24389.0f;
+};
+
+class RGBLABTransformer {
+ public:
+  FloatPoint3D sRGBToLab(const FloatPoint3D& rgb) const {
+    FloatPoint3D xyz = rcs.toXYZ(rgb);
+    return lcs.fromXYZ(xyz);
+  }
+
+  FloatPoint3D LabToSRGB(const FloatPoint3D& lab) const {
+    FloatPoint3D xyz = lcs.toXYZ(lab);
+    return rcs.fromXYZ(xyz);
+  }
+
+ private:
+  sRGBColorSpace rcs = sRGBColorSpace();
+  LABColorSpace lcs = LABColorSpace();
+};
+
+}  // namespace LabColorSpace
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_LAB_COLOR_SPACE_H_
diff --git a/third_party/blink/renderer/platform/graphics/lab_color_space_test.cc b/third_party/blink/renderer/platform/graphics/lab_color_space_test.cc
new file mode 100644
index 0000000..cacdb7ee
--- /dev/null
+++ b/third_party/blink/renderer/platform/graphics/lab_color_space_test.cc
@@ -0,0 +1,70 @@
+#include "third_party/blink/renderer/platform/graphics/lab_color_space.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace LabColorSpace {
+
+using blink::FloatPoint3D;
+
+static constexpr FloatPoint3D rgbReferenceWhite =
+    FloatPoint3D(1.0f, 1.0f, 1.0f);
+static constexpr FloatPoint3D labReferenceWhite =
+    FloatPoint3D(100.0f, 0.0f, 0.0f);
+static constexpr float epsilon = 0.0001;
+
+class LabColorSpaceTest : public testing::Test {
+ public:
+  void AssertColorsEqual(const FloatPoint3D& color1,
+                         const FloatPoint3D& color2) {
+    EXPECT_NEAR(color1.X(), color2.X(), epsilon);
+    EXPECT_NEAR(color1.Y(), color2.Y(), epsilon);
+    EXPECT_NEAR(color1.Z(), color2.Z(), epsilon);
+  }
+};
+
+TEST_F(LabColorSpaceTest, XYZTranslation) {
+  sRGBColorSpace colorSpace = sRGBColorSpace();
+
+  // Check whether white transformation is correct
+  FloatPoint3D xyzWhite = colorSpace.toXYZ(rgbReferenceWhite);
+  AssertColorsEqual(xyzWhite, kIlluminantD50);
+
+  FloatPoint3D rgbWhite = colorSpace.fromXYZ(kIlluminantD50);
+  AssertColorsEqual(rgbWhite, rgbReferenceWhite);
+
+  // Check whether transforming sRGB to XYZ and back gives the same RGB values
+  // for some random colors with different r, g, b components.
+  for (unsigned r = 0; r <= 255; r += 40) {
+    for (unsigned g = 0; r <= 255; r += 50) {
+      for (unsigned b = 0; r <= 255; r += 60) {
+        FloatPoint3D rgb = FloatPoint3D(r / 255.0f, g / 255.0f, b / 255.0f);
+        FloatPoint3D xyz = colorSpace.toXYZ(rgb);
+        AssertColorsEqual(rgb, colorSpace.fromXYZ(xyz));
+      }
+    }
+  }
+}
+
+TEST_F(LabColorSpaceTest, LabTranslation) {
+  RGBLABTransformer transformer = RGBLABTransformer();
+
+  // Check whether white transformation is correct
+  FloatPoint3D labWhite = transformer.sRGBToLab(rgbReferenceWhite);
+  AssertColorsEqual(labWhite, labReferenceWhite);
+
+  FloatPoint3D rgbWhite = transformer.LabToSRGB(labReferenceWhite);
+  AssertColorsEqual(rgbWhite, rgbReferenceWhite);
+
+  // Check whether transforming sRGB to Lab and back gives the same RGB values
+  // for some random colors with different r, g, b components.
+  for (unsigned r = 0; r <= 255; r += 40) {
+    for (unsigned g = 0; r <= 255; r += 50) {
+      for (unsigned b = 0; r <= 255; r += 60) {
+        FloatPoint3D rgb = FloatPoint3D(r / 255.0f, g / 255.0f, b / 255.0f);
+        FloatPoint3D lab = transformer.sRGBToLab(rgb);
+        AssertColorsEqual(rgb, transformer.LabToSRGB(lab));
+      }
+    }
+  }
+}
+
+}  // namespace LabColorSpace
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
index 1d88a7e..4ee0a09 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
@@ -575,6 +575,40 @@
   ExpectStatic(decoder.get());
 }
 
+TEST(AnimatedPNGTests, EmptyFdatFails) {
+  const char* png_file =
+      "/images/resources/"
+      "png-animated-idat-part-of-animation.png";
+  scoped_refptr<SharedBuffer> data = ReadFile(png_file);
+  ASSERT_FALSE(data->IsEmpty());
+
+  // Modify the third fdAT to be empty.
+  constexpr size_t kOffsetThirdFdat = 352;
+  scoped_refptr<SharedBuffer> modified_data =
+      SharedBuffer::Create(data->Data(), kOffsetThirdFdat);
+  png_byte four_bytes[4u];
+  WriteUint32(0, four_bytes);
+  modified_data->Append(reinterpret_cast<char*>(four_bytes), 4u);
+
+  // fdAT tag
+  modified_data->Append(data->Data() + kOffsetThirdFdat + 4u, 4u);
+
+  // crc computed from modified fdAT chunk
+  WriteUint32(4122214294, four_bytes);
+  modified_data->Append(reinterpret_cast<char*>(four_bytes), 4u);
+
+  // IEND
+  constexpr size_t kIENDOffset = 422u;
+  modified_data->Append(data->Data() + kIENDOffset, 12u);
+
+  auto decoder = CreatePNGDecoder();
+  decoder->SetData(std::move(modified_data), true);
+  for (size_t i = 0; i < decoder->FrameCount(); i++) {
+    decoder->DecodeFrameBufferAtIndex(i);
+  }
+  ASSERT_TRUE(decoder->Failed());
+}
+
 // Originally, the third frame has an offset of (1,2) and a size of (3,2). By
 // changing the offset to (4,4), the frame rect is no longer within the image
 // size of 5x5. This results in a failure.
@@ -714,11 +748,11 @@
       SharedBuffer::Create(full_data->Data(), kPostIDAT);
   const size_t kFcTLSize = 38u;
   const size_t kFdATSize = 31u;
-  png_byte fd_at[kFdATSize];
-  memcpy(fd_at, full_data->Data() + kPostIDAT + kFcTLSize, kFdATSize);
+  png_byte fdat[kFdATSize];
+  memcpy(fdat, full_data->Data() + kPostIDAT + kFcTLSize, kFdATSize);
   // Modify the sequence number
-  WriteUint32(1u, fd_at + 8);
-  data->Append((const char*)fd_at, kFdATSize);
+  WriteUint32(1u, fdat + 8);
+  data->Append((const char*)fdat, kFdATSize);
   const size_t kIENDOffset = 422u;
   data->Append(full_data->Data() + kIENDOffset,
                full_data->size() - kIENDOffset);
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
index fe55f76..14cdea9 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
@@ -39,6 +39,7 @@
 #include "third_party/blink/renderer/platform/image-decoders/png/png_image_reader.h"
 
 #include <memory>
+#include "base/numerics/checked_math.h"
 #include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
 #include "third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.h"
 #include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
@@ -128,7 +129,7 @@
                                     size_t read_offset,
                                     size_t length,
                                     char* buffer) {
-  DCHECK(length <= kPngReadBufferSize);
+  DCHECK_LE(length, kPngReadBufferSize);
   return reinterpret_cast<const png_byte*>(
       reader.GetConsecutiveData(read_offset, length, buffer));
 }
@@ -244,17 +245,22 @@
     char read_buffer[8];
     // At the beginning of each loop, the offset is at the start of a chunk.
     const png_byte* chunk = ReadAsConstPngBytep(reader, offset, 8, read_buffer);
+
+    // A large length would have been rejected in Parse.
     const png_uint_32 length = png_get_uint_32(chunk);
-    DCHECK(length <= PNG_UINT_31_MAX);
+    DCHECK_LE(length, PNG_UINT_31_MAX);
 
     // When an fcTL or IEND chunk is encountered, the frame data has ended.
-    // Return true, since all frame data is decoded.
-    if (IsChunk(chunk, "fcTL") || IsChunk(chunk, "IEND"))
+    if (IsChunk(chunk, "fcTL") || IsChunk(chunk, "IEND")) {
       return true;
+    }
+
+    const size_t chunk_end_offset = offset + length + 12;
+    DCHECK_GT(chunk_end_offset, offset);
 
     // If this chunk was already decoded, move on to the next.
-    if (progressive_decode_offset_ >= offset + length + 12) {
-      offset += length + 12;
+    if (progressive_decode_offset_ >= chunk_end_offset) {
+      offset = chunk_end_offset;
       continue;
     }
 
@@ -263,8 +269,6 @@
     //    Continue from there.
     // 2) This is an fdAT chunk. Convert it to an IDAT chunk to decode.
     // 3) This is any other chunk. Pass it to libpng for processing.
-    size_t end_offset_chunk = offset + length + 12;
-
     if (progressive_decode_offset_ >= offset + 8) {
       offset = progressive_decode_offset_;
     } else if (IsChunk(chunk, "fdAT")) {
@@ -276,7 +280,7 @@
       offset += 8;
     }
 
-    size_t bytes_left_in_chunk = end_offset_chunk - offset;
+    size_t bytes_left_in_chunk = chunk_end_offset - offset;
     size_t bytes_decoded = ProcessData(reader, offset, bytes_left_in_chunk);
     progressive_decode_offset_ = offset + bytes_decoded;
     if (bytes_decoded < bytes_left_in_chunk)
@@ -288,7 +292,7 @@
 }
 
 void PNGImageReader::ProcessFdatChunkAsIdat(png_uint_32 fdat_length) {
-  // An fdAT chunk is build up as follows:
+  // An fdAT chunk is built as follows:
   // - |length| (4B)
   // - fdAT tag (4B)
   // - sequence number (4B)
@@ -300,7 +304,8 @@
   // - change the tag to IDAT.
   // - omit the sequence number from the data part of the chunk.
   png_byte chunk_idat[] = {0, 0, 0, 0, 'I', 'D', 'A', 'T'};
-  png_save_uint_32(chunk_idat, fdat_length - 4);
+  DCHECK_GE(fdat_length, 4u);
+  png_save_uint_32(chunk_idat, fdat_length - 4u);
   // The CRC is incorrect when applied to the modified fdAT.
   png_set_crc_action(png_, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
   png_process_data(png_, info_, chunk_idat, 8);
@@ -315,7 +320,7 @@
   while (offset < end_offset) {
     const png_byte* chunk = ReadAsConstPngBytep(reader, offset, 8, read_buffer);
     const png_uint_32 length = png_get_uint_32(chunk);
-    DCHECK(length <= PNG_UINT_31_MAX);
+    DCHECK_LE(length, PNG_UINT_31_MAX);
 
     if (IsChunk(chunk, "fdAT")) {
       ProcessFdatChunkAsIdat(length);
@@ -337,7 +342,7 @@
                      size_t chunk_length) {
   constexpr size_t kSizeNeededForfcTL = 26 + 4;
   char read_buffer[kSizeNeededForfcTL];
-  DCHECK(chunk_length + 4 <= kSizeNeededForfcTL);
+  DCHECK_LE(chunk_length + 4u, kSizeNeededForfcTL);
   const png_byte* chunk = ReadAsConstPngBytep(reader, chunk_start + 4,
                                               chunk_length + 4, read_buffer);
 
@@ -404,16 +409,22 @@
     const size_t length = png_get_uint_32(chunk);
     if (length > PNG_UINT_31_MAX)
       return false;
+    size_t chunk_end_offset;
+    if (!base::CheckAdd(read_offset_, base::CheckAdd(12, length))
+             .AssignIfValid(&chunk_end_offset)) {
+      // Overflow
+      return false;
+    }
 
     const bool idat = IsChunk(chunk, "IDAT");
     if (idat && !expect_idats_)
       return false;
 
-    const bool fd_at = IsChunk(chunk, "fdAT");
-    if (fd_at && expect_idats_)
+    const bool fdat = IsChunk(chunk, "fdAT");
+    if (fdat && expect_idats_)
       return false;
 
-    if (fd_at || (idat && idat_is_part_of_animation_)) {
+    if (fdat || (idat && idat_is_part_of_animation_)) {
       fctl_needs_dat_chunk_ = false;
       if (!new_frame_.start_offset) {
         // Beginning of a new frame's data.
@@ -427,7 +438,13 @@
         }
       }
 
-      if (fd_at) {
+      if (fdat) {
+        if (length < 4) {
+          // The sequence number requires 4 bytes. Further,
+          // ProcessFdatChunkAsIdat expects to be able to create an IDAT with
+          // |newLength| = length - 4. Prevent underflow in that calculation.
+          return false;
+        }
         if (reader.size() < read_offset_ + 8 + 4)
           return true;
         const png_byte* sequence_position =
@@ -456,7 +473,7 @@
         new_frame_.start_offset = 0;
       }
 
-      if (reader.size() < read_offset_ + 12 + length)
+      if (reader.size() < chunk_end_offset)
         return true;
 
       if (IsChunk(chunk, "IEND")) {
@@ -479,7 +496,7 @@
       return false;
     }
 
-    read_offset_ += 12 + length;
+    read_offset_ = chunk_end_offset;
   }
   return true;
 }
@@ -532,10 +549,20 @@
 
   // Process APNG chunks manually, pass other chunks to libpng.
   for (png_uint_32 length = 0; reader.size() >= read_offset_ + 8;
+       // This call will not overflow since it was already checked below, after
+       // calculating chunk_end_offset.
        read_offset_ += length + 12) {
     const png_byte* chunk =
         ReadAsConstPngBytep(reader, read_offset_, 8, read_buffer);
     length = png_get_uint_32(chunk);
+    if (length > PNG_UINT_31_MAX)
+      return false;
+    size_t chunk_end_offset;
+    if (!base::CheckAdd(read_offset_, base::CheckAdd(12, length))
+             .AssignIfValid(&chunk_end_offset)) {
+      // Overflow
+      return false;
+    }
 
     if (IsChunk(chunk, "IDAT")) {
       // Done with header chunks.
@@ -559,7 +586,7 @@
     }
 
     // Wait until the entire chunk is available for parsing simplicity.
-    if (reader.size() < read_offset_ + length + 12)
+    if (reader.size() < chunk_end_offset)
       break;
 
     if (IsChunk(chunk, "acTL")) {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 0b92230a..ab4f1d9 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1119,7 +1119,7 @@
       status: {"Android": "", "default": "stable"},
     },
     {
-      name: "PointerRawMove",
+      name: "PointerRawUpdate",
       status: "experimental",
     },
     {
diff --git a/third_party/blink/renderer/platform/testing/paint_test_configurations.h b/third_party/blink/renderer/platform/testing/paint_test_configurations.h
index f25b5f9..81c3300c 100644
--- a/third_party/blink/renderer/platform/testing/paint_test_configurations.h
+++ b/third_party/blink/renderer/platform/testing/paint_test_configurations.h
@@ -15,19 +15,22 @@
   kBlinkGenPropertyTrees = 1 << 0,
   kCompositeAfterPaint = 1 << 1,
   kUnderInvalidationChecking = 1 << 2,
+  kFastBorderRadius = 1 << 3,
 };
 
 class PaintTestConfigurations
     : public testing::WithParamInterface<unsigned>,
       private ScopedBlinkGenPropertyTreesForTest,
       private ScopedCompositeAfterPaintForTest,
-      private ScopedPaintUnderInvalidationCheckingForTest {
+      private ScopedPaintUnderInvalidationCheckingForTest,
+      private ScopedFastBorderRadiusForTest {
  public:
   PaintTestConfigurations()
       : ScopedBlinkGenPropertyTreesForTest(GetParam() & kBlinkGenPropertyTrees),
         ScopedCompositeAfterPaintForTest(GetParam() & kCompositeAfterPaint),
-        ScopedPaintUnderInvalidationCheckingForTest(
-            GetParam() & kUnderInvalidationChecking) {}
+        ScopedPaintUnderInvalidationCheckingForTest(GetParam() &
+                                                    kUnderInvalidationChecking),
+        ScopedFastBorderRadiusForTest(GetParam() & kFastBorderRadius) {}
   ~PaintTestConfigurations() {
     // Must destruct all objects before toggling back feature flags.
     WebHeap::CollectAllGarbageForTesting();
@@ -45,11 +48,12 @@
       All, test_class,                           \
       ::testing::Values(kBlinkGenPropertyTrees | kCompositeAfterPaint))
 
-#define INSTANTIATE_LAYER_LIST_TEST_SUITE_P(test_class) \
-  INSTANTIATE_TEST_SUITE_P(                             \
-      All, test_class,                                  \
-      ::testing::Values(kBlinkGenPropertyTrees,         \
-                        kBlinkGenPropertyTrees | kCompositeAfterPaint))
+#define INSTANTIATE_LAYER_LIST_TEST_SUITE_P(test_class)                \
+  INSTANTIATE_TEST_SUITE_P(                                            \
+      All, test_class,                                                 \
+      ::testing::Values(kBlinkGenPropertyTrees,                        \
+                        kBlinkGenPropertyTrees | kCompositeAfterPaint, \
+                        kBlinkGenPropertyTrees | kFastBorderRadius))
 
 }  // namespace blink
 
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
index fa24038..c8e0153e 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
@@ -12,7 +12,6 @@
 from blinkpy.common.path_finder import PathFinder
 from blinkpy.tool.commands.rebaseline import AbstractParallelRebaselineCommand
 from blinkpy.tool.commands.rebaseline import TestBaselineSet
-from blinkpy.w3c.wpt_manifest import WPTManifest
 
 
 _log = logging.getLogger(__name__)
@@ -78,11 +77,6 @@
                        'positional parameters.')
             return 1
 
-        # The WPT manifest is required when iterating through tests
-        # TestBaselineSet if there are any tests in web-platform-tests.
-        # TODO(crbug.com/698294): Consider calling ensure_manifest in BlinkTool.
-        WPTManifest.ensure_manifest(tool)
-
         if not self.check_ok_to_run():
             return 1
 
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
index ce7695b..cee2127bd 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -19,7 +19,6 @@
 from blinkpy.common.path_finder import PathFinder
 from blinkpy.common.system.executive import ScriptError
 from blinkpy.common.system.log_utils import configure_logging
-from blinkpy.w3c.wpt_manifest import WPTManifest
 
 _log = logging.getLogger(__name__)
 
@@ -75,9 +74,6 @@
         if not build_to_status:
             raise ScriptError('No try job information was collected.')
 
-        # The manifest may be used below to do check which tests are reference tests.
-        WPTManifest.ensure_manifest(self.host)
-
         # Here we build up a dict of failing test results for all platforms.
         test_expectations = {}
         for build, job_status in build_to_status.iteritems():
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
index 5308a22..0ab0843 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
@@ -14,6 +14,7 @@
 from blinkpy.common.system.executive import ScriptError
 from blinkpy.common.system.log_testing import LoggingTestCase
 from blinkpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater, SimpleTestResult, MARKER_COMMENT
+from blinkpy.w3c.wpt_manifest import BASE_MANIFEST_NAME
 from blinkpy.web_tests.builder_list import BuilderList
 from blinkpy.web_tests.port.factory_mock import MockPortFactory
 
@@ -61,7 +62,7 @@
 
         # Write a dummy manifest file, describing what tests exist.
         host.filesystem.write_text_file(
-            host.port_factory.get().web_tests_dir() + '/external/wpt/MANIFEST.json',
+            host.port_factory.get().web_tests_dir() + '/external/' + BASE_MANIFEST_NAME,
             json.dumps({
                 'items': {
                     'reftest': {
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py b/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
index 4dc48e7..3906dd48 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
@@ -74,7 +74,7 @@
         Returns:
             A list of manifest items, or None if not found.
         """
-        items = self.raw_dict['items']
+        items = self.raw_dict.get('items', {})
         for test_type in self.test_types:
             if test_type not in items:
                 continue
@@ -168,7 +168,7 @@
            [("==", "/foo/bar/baz-match.html"),
             ("!=", "/foo/bar/baz-mismatch.html")]
         """
-        items = self.raw_dict['items']
+        items = self.raw_dict.get('items', {})
         if path_in_wpt not in items.get('reftest', {}):
             return []
         reftest_list = []
@@ -182,36 +182,40 @@
         return reftest_list
 
     @staticmethod
-    def ensure_manifest(host, path=None):
+    def ensure_manifest(port, path=None):
         """Updates the MANIFEST.json file, or generates if it does not exist.
 
         Args:
+            port: A blinkpy.web_tests.port.Port object.
             path: The path to a WPT root (relative to web_tests, optional).
         """
+        fs = port.host.filesystem
         if path is None:
-            path = host.filesystem.join('external', 'wpt')
-        finder = PathFinder(host.filesystem)
-        wpt_path = finder.path_from_web_tests(path)
-        manifest_path = host.filesystem.join(wpt_path, MANIFEST_NAME)
+            path = fs.join('external', 'wpt')
+        wpt_path = fs.join(port.web_tests_dir(), path)
+        manifest_path = fs.join(wpt_path, MANIFEST_NAME)
 
         # Unconditionally delete local MANIFEST.json to avoid regenerating the
         # manifest from scratch (when version is bumped) or invalid/out-of-date
         # local manifest breaking the runner.
-        if host.filesystem.exists(manifest_path):
-            host.filesystem.remove(manifest_path)
+        if fs.exists(manifest_path):
+            fs.remove(manifest_path)
 
         # TODO(crbug.com/853815): perhaps also cache the manifest for wpt_internal.
         if 'external' in path:
-            base_manifest_path = finder.path_from_web_tests('external', BASE_MANIFEST_NAME)
-            if not host.filesystem.exists(base_manifest_path):
+            base_manifest_path = fs.join(port.web_tests_dir(), 'external', BASE_MANIFEST_NAME)
+            if fs.exists(base_manifest_path):
+                fs.copyfile(base_manifest_path, manifest_path)
+            else:
                 _log.error('Manifest base not found at "%s".', base_manifest_path)
-                host.filesystem.write_text_file(base_manifest_path, '{}')
 
-            host.filesystem.copyfile(base_manifest_path, manifest_path)
+        WPTManifest.generate_manifest(port.host, wpt_path)
 
-        WPTManifest.generate_manifest(host, wpt_path)
-
-        _log.debug('Manifest generation completed.')
+        if fs.isfile(manifest_path):
+            _log.debug('Manifest generation completed.')
+        else:
+            _log.error('Manifest generation failed; creating an empty MANIFEST.json...')
+            fs.write_text_file(manifest_path, '{}')
 
     @staticmethod
     def generate_manifest(host, dest_path):
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
index eb9a5be65..537b298 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
@@ -5,22 +5,21 @@
 import unittest
 
 from blinkpy.common.host_mock import MockHost
-from blinkpy.common.path_finder import RELATIVE_WEB_TESTS
 from blinkpy.common.system.executive import ScriptError
 from blinkpy.common.system.executive_mock import MockExecutive
 from blinkpy.w3c.wpt_manifest import WPTManifest
+from blinkpy.web_tests.port.test import TestPort, WEB_TEST_DIR
 
 
-MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS
-
 class WPTManifestUnitTest(unittest.TestCase):
 
     def test_ensure_manifest_copies_new_manifest(self):
         host = MockHost()
-        manifest_path = MOCK_WEB_TESTS + 'external/wpt/MANIFEST.json'
+        port = TestPort(host)
+        manifest_path = WEB_TEST_DIR + '/external/wpt/MANIFEST.json'
 
         self.assertFalse(host.filesystem.exists(manifest_path))
-        WPTManifest.ensure_manifest(host)
+        WPTManifest.ensure_manifest(port)
         self.assertTrue(host.filesystem.exists(manifest_path))
         self.assertEqual(host.filesystem.written_files, {manifest_path: '{"manifest": "base"}'})
 
@@ -34,19 +33,20 @@
                     '--work',
                     '--no-download',
                     '--tests-root',
-                    MOCK_WEB_TESTS + 'external/wpt',
+                    WEB_TEST_DIR + '/external/wpt',
                 ]
             ]
         )
 
     def test_ensure_manifest_updates_manifest_if_it_exists(self):
         host = MockHost()
-        manifest_path = MOCK_WEB_TESTS + 'external/wpt/MANIFEST.json'
+        port = TestPort(host)
+        manifest_path = WEB_TEST_DIR + '/external/wpt/MANIFEST.json'
 
         host.filesystem.write_text_file(manifest_path, '{"manifest": "NOT base"}')
 
         self.assertTrue(host.filesystem.exists(manifest_path))
-        WPTManifest.ensure_manifest(host)
+        WPTManifest.ensure_manifest(port)
         self.assertTrue(host.filesystem.exists(manifest_path))
         self.assertEqual(host.filesystem.written_files, {manifest_path: '{"manifest": "base"}'})
 
@@ -60,7 +60,7 @@
                     '--work',
                     '--no-download',
                     '--tests-root',
-                    MOCK_WEB_TESTS + 'external/wpt',
+                    WEB_TEST_DIR + '/external/wpt',
                 ]
             ]
         )
@@ -68,13 +68,15 @@
     def test_ensure_manifest_raises_exception(self):
         host = MockHost()
         host.executive = MockExecutive(should_throw=True)
+        port = TestPort(host)
 
         with self.assertRaises(ScriptError):
-            WPTManifest.ensure_manifest(host)
+            WPTManifest.ensure_manifest(port)
 
     def test_ensure_manifest_takes_optional_dest(self):
         host = MockHost()
-        WPTManifest.ensure_manifest(host, 'wpt_internal')
+        port = TestPort(host)
+        WPTManifest.ensure_manifest(port, 'wpt_internal')
         self.assertEqual(
             host.executive.calls,
             [
@@ -85,7 +87,7 @@
                     '--work',
                     '--no-download',
                     '--tests-root',
-                    MOCK_WEB_TESTS + 'wpt_internal',
+                    WEB_TEST_DIR + '/wpt_internal',
                 ]
             ]
         )
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py b/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py
index 5b5eb40..fb2dc36 100644
--- a/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py
+++ b/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py
@@ -47,7 +47,6 @@
 from blinkpy.common.net.file_uploader import FileUploader
 from blinkpy.common.path_finder import PathFinder
 from blinkpy.tool import grammar
-from blinkpy.w3c.wpt_manifest import WPTManifest
 from blinkpy.web_tests.controllers.test_result_writer import TestResultWriter
 from blinkpy.web_tests.controllers.web_test_finder import WebTestFinder
 from blinkpy.web_tests.controllers.web_test_runner import WebTestRunner
@@ -99,19 +98,6 @@
         self._printer.write_update('Collecting tests ...')
         running_all_tests = False
 
-        if self._options.manifest_update:
-            # TODO(robertma): Consolidate the two cases to `for wpt_path in
-            # WPT_DIRS` when external/wpt is moved to wpt.
-            if not args or any('external' in path for path in args):
-                self._printer.write_update('Generating MANIFEST.json for external/wpt...')
-                WPTManifest.ensure_manifest(self._port.host)
-                self._printer.write_update('Completed generating manifest.')
-            if not args or any('wpt_internal' in path for path in args):
-                self._printer.write_update('Generating MANIFEST.json for wpt_internal...')
-                WPTManifest.ensure_manifest(self._port.host, 'wpt_internal')
-                self._printer.write_update('Completed generating manifest.')
-
-        self._printer.write_update('Collecting tests ...')
         try:
             paths, all_test_names, running_all_tests = self._collect_tests(args)
         except IOError:
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py
index 1d7ec88..4980b26 100644
--- a/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py
+++ b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py
@@ -27,6 +27,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 import collections
+import copy
 import itertools
 import logging
 import math
@@ -151,7 +152,6 @@
         return test_run_results
 
     def _reorder_tests_by_args(self, shards):
-        reordered_shards = []
         for shard in shards:
             tests_by_args = collections.OrderedDict()
             for test_input in shard.test_inputs:
@@ -242,7 +242,10 @@
         self._worker_number = caller.worker_number
         self._name = caller.name
         self._results_directory = results_directory
-        self._options = options
+        # We have already updated the manifest when collecting tests, so skip it
+        # in the workers (this also prevents race conditions among workers).
+        self._options = copy.copy(options)
+        self._options.manifest_update = False
 
         # The remaining fields are initialized in start()
         self._host = None
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittest.py b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittest.py
index 50751bd..38bd0af 100644
--- a/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittest.py
@@ -33,7 +33,7 @@
 from blinkpy.common.host_mock import MockHost
 from blinkpy.common.system.system_host_mock import MockSystemHost
 from blinkpy.web_tests import run_web_tests
-from blinkpy.web_tests.controllers.web_test_runner import WebTestRunner, Sharder, TestRunInterruptedException
+from blinkpy.web_tests.controllers.web_test_runner import WebTestRunner, Worker, Sharder, TestRunInterruptedException
 from blinkpy.web_tests.models import test_expectations
 from blinkpy.web_tests.models import test_failures
 from blinkpy.web_tests.models.test_run_results import TestRunResults
@@ -201,10 +201,10 @@
         self.assert_shards(unlocked,
                            [('virtual/threaded/dir', ['virtual/threaded/dir/test.html']),
                             ('virtual/threaded/fast/foo', ['virtual/threaded/fast/foo/test.html']),
-                               ('animations', ['animations/keyframes.html']),
-                               ('dom/html/level2/html', ['dom/html/level2/html/HTMLAnchorElement03.html',
-                                                         'dom/html/level2/html/HTMLAnchorElement06.html']),
-                               ('fast/css', ['fast/css/display-none-inline-style-change-crash.html'])])
+                            ('animations', ['animations/keyframes.html']),
+                            ('dom/html/level2/html', ['dom/html/level2/html/HTMLAnchorElement03.html',
+                                                      'dom/html/level2/html/HTMLAnchorElement06.html']),
+                            ('fast/css', ['fast/css/display-none-inline-style-change-crash.html'])])
 
     def test_shard_every_file(self):
         locked, unlocked = self.get_shards(num_workers=2, fully_parallel=True, max_locked_shards=2, run_singly=False)
@@ -213,16 +213,16 @@
                              ['http/tests/websocket/tests/unicode.htm',
                               'http/tests/security/view-source-no-refresh.html',
                               'http/tests/websocket/tests/websocket-protocol-ignored.html']),
-                               ('locked_shard_2',
-                                ['http/tests/xmlhttprequest/supported-xml-content-types.html',
-                                 'perf/object-keys.html'])])
+                            ('locked_shard_2',
+                             ['http/tests/xmlhttprequest/supported-xml-content-types.html',
+                              'perf/object-keys.html'])])
         self.assert_shards(unlocked,
                            [('virtual/threaded/dir', ['virtual/threaded/dir/test.html']),
                             ('virtual/threaded/fast/foo', ['virtual/threaded/fast/foo/test.html']),
-                               ('.', ['animations/keyframes.html']),
-                               ('.', ['fast/css/display-none-inline-style-change-crash.html']),
-                               ('.', ['dom/html/level2/html/HTMLAnchorElement03.html']),
-                               ('.', ['dom/html/level2/html/HTMLAnchorElement06.html'])])
+                            ('.', ['animations/keyframes.html']),
+                            ('.', ['fast/css/display-none-inline-style-change-crash.html']),
+                            ('.', ['dom/html/level2/html/HTMLAnchorElement03.html']),
+                            ('.', ['dom/html/level2/html/HTMLAnchorElement06.html'])])
 
     def test_shard_in_two(self):
         locked, unlocked = self.get_shards(num_workers=1, fully_parallel=False, run_singly=False)
@@ -261,9 +261,9 @@
                              ['http/tests/security/view-source-no-refresh.html',
                               'http/tests/websocket/tests/unicode.htm',
                               'http/tests/websocket/tests/websocket-protocol-ignored.html']),
-                               ('locked_shard_2',
-                                ['http/tests/xmlhttprequest/supported-xml-content-types.html',
-                                 'perf/object-keys.html'])])
+                            ('locked_shard_2',
+                             ['http/tests/xmlhttprequest/supported-xml-content-types.html',
+                              'perf/object-keys.html'])])
 
         locked, _ = self.get_shards(num_workers=4, fully_parallel=False, run_singly=False)
         self.assert_shards(locked,
@@ -288,3 +288,17 @@
         self.assert_shards(unlocked,
                            [('.', ['virtual/foo/bar1.html']),
                             ('.', ['virtual/foo/bar2.html'])])
+
+
+class WorkerTests(unittest.TestCase):
+
+    class DummyCaller(object):
+        worker_number = 1
+        name = 'dummy_caller'
+
+    def test_worker_no_manifest_update(self):
+        # pylint: disable=protected-access
+        options = run_web_tests.parse_args(['--platform', 'test-mac-mac10.11'])[0]
+        worker = Worker(self.DummyCaller(), '/results', options)
+        self.assertTrue(options.manifest_update)
+        self.assertFalse(worker._options.manifest_update)
diff --git a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
index 1b2e7607..52819a1 100644
--- a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
+++ b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
@@ -36,7 +36,6 @@
 from blinkpy.common.system.log_utils import configure_logging
 from blinkpy.web_tests.models import test_expectations
 from blinkpy.web_tests.port.factory import platform_options
-from blinkpy.w3c.wpt_manifest import WPTManifest
 
 _log = logging.getLogger(__name__)
 
@@ -194,10 +193,6 @@
         configure_logging(logging_level=logging.INFO, stream=stderr, include_time=False)
 
     try:
-        # Need to generate MANIFEST.json since some expectations correspond to WPT
-        # tests that aren't files and only exist in the manifest.
-        _log.debug('Generating MANIFEST.json for web-platform-tests ...')
-        WPTManifest.ensure_manifest(host)
         exit_status = run_checks(host, options)
     except KeyboardInterrupt:
         exit_status = exit_codes.INTERRUPTED_EXIT_STATUS
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py
index d5c57ac3..6ff3cb1 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -458,7 +458,7 @@
         # diff. To account for variances when the tests are ran on an actual
         # GPU.
         if self.get_option('fuzzy_diff'):
-          command.append('--fuzzy-diff')
+            command.append('--fuzzy-diff')
 
         result = None
         err_str = None
@@ -806,9 +806,9 @@
         # Convert '/' to the platform-specific separator.
         path = self._filesystem.normpath(path)
         manifest_path = self._filesystem.join(self.web_tests_dir(), path, MANIFEST_NAME)
-        if not self._filesystem.exists(manifest_path):
-            _log.error('Manifest not found at %s. Remove the --no-manifest-update argument to generate it.', manifest_path)
-            return WPTManifest('{}')
+        if not self._filesystem.exists(manifest_path) or self.get_option('manifest_update', True):
+            _log.debug('Generating MANIFEST.json for %s...', path)
+            WPTManifest.ensure_manifest(self, path)
         return WPTManifest(self._filesystem.read_text_file(manifest_path))
 
     def is_slow_wpt_test(self, test_file):
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
index ef04a83..ab9acf3 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
@@ -479,8 +479,40 @@
         tests = port.tests(['userscripts/resources'])
         self.assertEqual(tests, [])
 
+    def test_update_manifest_once_by_default(self):
+        # pylint: disable=protected-access
+        port = self.make_port(with_tests=True)
+        port._wpt_manifest('external/wpt')
+        port._wpt_manifest('external/wpt')
+        self.assertEqual(len(port.host.filesystem.written_files), 1)
+        self.assertEqual(len(port.host.executive.calls), 1)
+
+    def test_no_manifest_update_with_existing_manifest(self):
+        # pylint: disable=protected-access
+        port = self.make_port(with_tests=True)
+        port.set_option_default('manifest_update', False)
+        filesystem = port.host.filesystem
+        filesystem.write_text_file(WEB_TEST_DIR + '/external/wpt/MANIFEST.json', '{}')
+        filesystem.clear_written_files()
+
+        port._wpt_manifest('external/wpt')
+        self.assertEqual(len(port.host.filesystem.written_files), 0)
+        self.assertEqual(len(port.host.executive.calls), 0)
+
+    def test_no_manifest_update_without_existing_manifest(self):
+        # pylint: disable=protected-access
+        port = self.make_port(with_tests=True)
+        port.set_option_default('manifest_update', False)
+
+        port._wpt_manifest('external/wpt')
+        self.assertEqual(len(port.host.filesystem.written_files), 1)
+        self.assertEqual(len(port.host.executive.calls), 1)
+
     @staticmethod
-    def _add_manifest_to_mock_file_system(filesystem):
+    def _add_manifest_to_mock_file_system(port):
+        # Disable manifest update otherwise they'll be overwritten.
+        port.set_option_default('manifest_update', False)
+        filesystem = port.host.filesystem
         filesystem.write_text_file(WEB_TEST_DIR + '/external/wpt/MANIFEST.json', json.dumps({
             'items': {
                 'testharness': {
@@ -532,19 +564,19 @@
 
     def test_find_none_if_not_in_manifest(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
         self.assertNotIn('external/wpt/common/blank.html', port.tests([]))
         self.assertNotIn('external/wpt/console/console-is-a-namespace.any.js', port.tests([]))
 
     def test_find_one_if_in_manifest(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
         self.assertIn('external/wpt/dom/ranges/Range-attributes.html', port.tests([]))
         self.assertIn('external/wpt/console/console-is-a-namespace.any.html', port.tests([]))
 
     def test_wpt_tests_paths(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
         all_wpt = [
             'external/wpt/console/console-is-a-namespace.any.html',
             'external/wpt/console/console-is-a-namespace.any.worker.html',
@@ -587,7 +619,7 @@
 
     def test_virtual_wpt_tests_paths(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
         all_wpt = [
             'virtual/virtual_wpt/external/wpt/console/console-is-a-namespace.any.html',
             'virtual/virtual_wpt/external/wpt/console/console-is-a-namespace.any.worker.html',
@@ -663,7 +695,7 @@
 
     def test_is_slow_wpt_test(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
 
         self.assertFalse(port.is_slow_wpt_test('external/wpt/dom/ranges/Range-attributes.html'))
         self.assertTrue(port.is_slow_wpt_test('external/wpt/dom/ranges/Range-attributes-slow.html'))
@@ -671,7 +703,7 @@
 
     def test_is_slow_wpt_test_with_variations(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
 
         self.assertFalse(port.is_slow_wpt_test('external/wpt/console/console-is-a-namespace.any.html'))
         self.assertTrue(port.is_slow_wpt_test('external/wpt/console/console-is-a-namespace.any.worker.html'))
@@ -680,14 +712,14 @@
 
     def test_is_slow_wpt_test_takes_virtual_tests(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
 
         self.assertFalse(port.is_slow_wpt_test('virtual/virtual_wpt/external/wpt/dom/ranges/Range-attributes.html'))
         self.assertTrue(port.is_slow_wpt_test('virtual/virtual_wpt/external/wpt/dom/ranges/Range-attributes-slow.html'))
 
     def test_is_slow_wpt_test_returns_false_for_illegal_paths(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
 
         self.assertFalse(port.is_slow_wpt_test('dom/ranges/Range-attributes.html'))
         self.assertFalse(port.is_slow_wpt_test('dom/ranges/Range-attributes-slow.html'))
@@ -705,7 +737,7 @@
 
     def test_reference_files_from_manifest(self):
         port = self.make_port(with_tests=True)
-        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        PortTest._add_manifest_to_mock_file_system(port)
 
         self.assertEqual(port.reference_files('external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html'),
                          [('==', port.web_tests_dir() +
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/test.py b/third_party/blink/tools/blinkpy/web_tests/port/test.py
index 0d777d7..2fa55f6 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/test.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/test.py
@@ -34,6 +34,7 @@
 from blinkpy.web_tests.models.test_configuration import TestConfiguration
 from blinkpy.web_tests.port.base import Port, VirtualTestSuite
 from blinkpy.web_tests.port.driver import DeviceFailure, Driver, DriverOutput
+from blinkpy.w3c.wpt_manifest import BASE_MANIFEST_NAME
 
 
 # Here we use a non-standard location for the web tests, to ensure that
@@ -228,9 +229,11 @@
     tests.add_reftest('passes/xhtreftest.xht', 'passes/xhtreftest-expected.html')
     tests.add_reftest('passes/phpreftest.php', 'passes/phpreftest-expected-mismatch.svg', same_image=False)
     tests.add_reftest('failures/expected/reftest.html', 'failures/expected/reftest-expected.html', same_image=False)
-    tests.add_reftest('failures/unexpected/reftest-with-matching-text.html', 'failures/unexpected/reftest-with-matching-text-expected.html',
+    tests.add_reftest('failures/unexpected/reftest-with-matching-text.html',
+                      'failures/unexpected/reftest-with-matching-text-expected.html',
                       same_image=False, actual_text='reftest', expected_text='reftest')
-    tests.add_reftest('failures/unexpected/reftest-with-mismatching-text.html', 'failures/unexpected/reftest-with-mismatching-text-expected.html',
+    tests.add_reftest('failures/unexpected/reftest-with-mismatching-text.html',
+                      'failures/unexpected/reftest-with-mismatching-text-expected.html',
                       actual_text='reftest', expected_text='reftest-different')
     tests.add_reftest('failures/expected/mismatch.html', 'failures/expected/mismatch-expected-mismatch.html')
     tests.add_reftest('failures/unexpected/crash-reftest.html', 'failures/unexpected/crash-reftest-expected.html', crash=True)
@@ -335,6 +338,11 @@
 
     filesystem.write_text_file(filesystem.join(WEB_TEST_DIR, 'virtual', 'virtual_passes',
                                                'passes', 'args-expected.txt'), 'args-txt --virtual-arg')
+
+    filesystem.maybe_make_directory(filesystem.join(WEB_TEST_DIR, 'external', 'wpt'))
+    filesystem.write_text_file(filesystem.join(WEB_TEST_DIR, 'external', BASE_MANIFEST_NAME),
+                               '{"manifest": "base"}')
+
     # Clear the list of written files so that we can watch what happens during testing.
     filesystem.clear_written_files()
 
@@ -411,7 +419,7 @@
             'linux': ['precise', 'trusty']
         }
 
-    def _path_to_driver(self):
+    def _path_to_driver(self, target=None):
         # This routine shouldn't normally be called, but it is called by
         # the mock_drt Driver. We return something, but make sure it's useless.
         return 'MOCK _path_to_driver'
@@ -520,6 +528,8 @@
     """Test/Dummy implementation of the driver interface."""
     next_pid = 1
 
+    # pylint: disable=protected-access
+
     def __init__(self, *args, **kwargs):
         super(TestDriver, self).__init__(*args, **kwargs)
         self.started = False
@@ -608,5 +618,5 @@
                             test_time=time.time() - start_time, timeout=test.timeout, error=test.error, pid=self.pid,
                             leak=test.leak)
 
-    def stop(self):
+    def stop(self, timeout_secs=0.0):
         self.started = False
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py b/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py
index 65dd5348..5bd63d54 100644
--- a/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py
+++ b/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py
@@ -482,7 +482,8 @@
                 dest='manifest_update',
                 action='store_false',
                 default=True,
-                help=('Do not update the web-platform-tests MANIFEST.json.')),
+                help=('Do not update the web-platform-tests MANIFEST.json'
+                      ' (unless it does not exist).')),
         ]))
 
     # FIXME: Move these into json_results_generator.py.
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_web_tests_unittest.py b/third_party/blink/tools/blinkpy/web_tests/run_web_tests_unittest.py
index f43af99..65e8ee0 100644
--- a/third_party/blink/tools/blinkpy/web_tests/run_web_tests_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/run_web_tests_unittest.py
@@ -52,7 +52,7 @@
 _MOCK_ROOT = os.path.join(
     path_finder.get_chromium_src_dir(), 'third_party', 'pymock')
 sys.path.insert(0, _MOCK_ROOT)
-import mock
+import mock  # pylint: disable=wrong-import-position
 
 
 def parse_args(extra_args=None, tests_included=False):
@@ -531,29 +531,27 @@
         tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html']
 
         with mock.patch('__builtin__.hash', len):
-
-          # Shard 0 of 2
-          tests_run = get_tests_run(['--shard-index', '0', '--total-shards', '2', '--order', 'natural'] + tests_to_run)
-          self.assertEqual(tests_run, ['passes/platform_image.html', 'passes/text.html'])
-          # Shard 1 of 2
-          tests_run = get_tests_run(['--shard-index', '1', '--total-shards', '2', '--order', 'natural'] + tests_to_run)
-          self.assertEqual(tests_run, ['passes/error.html', 'passes/image.html'])
+            # Shard 0 of 2
+            tests_run = get_tests_run(['--shard-index', '0', '--total-shards', '2', '--order', 'natural'] + tests_to_run)
+            self.assertEqual(tests_run, ['passes/platform_image.html', 'passes/text.html'])
+            # Shard 1 of 2
+            tests_run = get_tests_run(['--shard-index', '1', '--total-shards', '2', '--order', 'natural'] + tests_to_run)
+            self.assertEqual(tests_run, ['passes/error.html', 'passes/image.html'])
 
     def test_sharding_uneven(self):
         tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html',
                         'perf/foo/test.html']
 
         with mock.patch('__builtin__.hash', len):
-
-          # Shard 0 of 3
-          tests_run = get_tests_run(['--shard-index', '0', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
-          self.assertEqual(tests_run, ['perf/foo/test.html'])
-          # Shard 1 of 3
-          tests_run = get_tests_run(['--shard-index', '1', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
-          self.assertEqual(tests_run, ['passes/text.html'])
-          # Shard 2 of 3
-          tests_run = get_tests_run(['--shard-index', '2', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
-          self.assertEqual(tests_run, ['passes/error.html', 'passes/image.html', 'passes/platform_image.html'])
+            # Shard 0 of 3
+            tests_run = get_tests_run(['--shard-index', '0', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
+            self.assertEqual(tests_run, ['perf/foo/test.html'])
+            # Shard 1 of 3
+            tests_run = get_tests_run(['--shard-index', '1', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
+            self.assertEqual(tests_run, ['passes/text.html'])
+            # Shard 2 of 3
+            tests_run = get_tests_run(['--shard-index', '2', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
+            self.assertEqual(tests_run, ['passes/error.html', 'passes/image.html', 'passes/platform_image.html'])
 
     def test_sharding_incorrect_arguments(self):
         with self.assertRaises(ValueError):
@@ -568,16 +566,15 @@
         host = MockHost()
 
         with mock.patch('__builtin__.hash', len):
+            host.environ['GTEST_SHARD_INDEX'] = '0'
+            host.environ['GTEST_TOTAL_SHARDS'] = '2'
+            shard_0_tests_run = get_tests_run(['--order', 'natural'] + tests_to_run, host=host)
+            self.assertEqual(shard_0_tests_run, ['passes/platform_image.html', 'passes/text.html'])
 
-          host.environ['GTEST_SHARD_INDEX'] = '0'
-          host.environ['GTEST_TOTAL_SHARDS'] = '2'
-          shard_0_tests_run = get_tests_run(['--order', 'natural'] + tests_to_run, host=host)
-          self.assertEqual(shard_0_tests_run, ['passes/platform_image.html', 'passes/text.html'])
-
-          host.environ['GTEST_SHARD_INDEX'] = '1'
-          host.environ['GTEST_TOTAL_SHARDS'] = '2'
-          shard_1_tests_run = get_tests_run(['--order', 'natural'] + tests_to_run, host=host)
-          self.assertEqual(shard_1_tests_run, ['passes/error.html', 'passes/image.html'])
+            host.environ['GTEST_SHARD_INDEX'] = '1'
+            host.environ['GTEST_TOTAL_SHARDS'] = '2'
+            shard_1_tests_run = get_tests_run(['--order', 'natural'] + tests_to_run, host=host)
+            self.assertEqual(shard_1_tests_run, ['passes/error.html', 'passes/image.html'])
 
     def test_smoke_test(self):
         host = MockHost()
@@ -1064,7 +1061,8 @@
         extra_png = test.WEB_TEST_DIR + '/passes/testharness-expected.png'
         host.filesystem.write_text_file(extra_png, 'Extra png')
         extra_txt = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
-        host.filesystem.write_text_file(extra_txt,
+        host.filesystem.write_text_file(
+            extra_txt,
             'This is a testharness.js-based test.\nPASS: bah\nHarness: the test ran to completion.')
         extra_wav = test.WEB_TEST_DIR + '/passes/testharness-expected.wav'
         host.filesystem.write_text_file(extra_wav, 'Extra wav')
@@ -1085,7 +1083,8 @@
     def test_passing_testharness_extra_txt_baseline(self):
         host = MockHost()
         extra_txt = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
-        host.filesystem.write_text_file(extra_txt,
+        host.filesystem.write_text_file(
+            extra_txt,
             'This is a testharness.js-based test.\nPASS: bah\nHarness: the test ran to completion.')
         test_name = 'passes/testharness.html'
         run_details, log_stream, _ = logging_run([test_name], tests_included=True, host=host)
@@ -1096,7 +1095,8 @@
     def test_passing_testharness_extra_mismatching_txt_baseline(self):
         host = MockHost()
         extra_txt = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
-        host.filesystem.write_text_file(extra_txt,
+        host.filesystem.write_text_file(
+            extra_txt,
             'This is a testharness.js-based test.\nFAIL: bah\nHarness: the test ran to completion.')
         test_name = 'passes/testharness.html'
         run_details, log_stream, _ = logging_run([test_name], tests_included=True, host=host)
@@ -1115,7 +1115,8 @@
         base_baseline = test.WEB_TEST_DIR + '/passes/testharness-expected.txt'
         host.filesystem.write_text_file(base_baseline, 'Failure')
         platform_baseline = test.WEB_TEST_DIR + '/platform/test-mac-mac10.10/passes/testharness-expected.txt'
-        host.filesystem.write_text_file(platform_baseline,
+        host.filesystem.write_text_file(
+            platform_baseline,
             'This is a testharness.js-based test.\nPASS: bah\nHarness: the test ran to completion.')
         run_details, log_stream, _ = logging_run(
             ['passes/testharness.html'], tests_included=True, host=host)
@@ -1613,7 +1614,7 @@
             tests_included=True, host=host)
         written_files = host.filesystem.written_files
         self.assertEqual(details.exit_code, 0)
-        self.assertEqual(len(written_files.keys()), 7)
+        self.assertEqual(len(written_files.keys()), 9)
         # We should create new image baseline only.
         self.assert_baselines(
             written_files, log_stream,
@@ -1697,7 +1698,7 @@
         self.assertEqual(details.exit_code, 0)
         self.assertFalse(host.filesystem.exists(virtual_baseline_txt))
         written_files = host.filesystem.written_files
-        self.assertEqual(len(written_files.keys()), 8)
+        self.assertEqual(len(written_files.keys()), 10)
         # We should create new image baseline only.
         self.assert_baselines(
             written_files, log_stream,
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
index ff081c8..9c8d86fd 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
@@ -5,7 +5,6 @@
 
 Bug(none) virtual/disable-blink-gen-property-trees/ [ Skip ]
 
-Bug(none) virtual/bidi-caret-affinity/ [ Skip ]
 Bug(none) virtual/gpu/fast/canvas/ [ Skip ]
 Bug(none) virtual/layout_ng/ [ Skip ]
 Bug(none) virtual/layout_ng_experimental/ [ Skip ]
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index 4bef491..5db0a398d 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -258,7 +258,7 @@
 crbug.com/591099 external/wpt/fetch/api/redirect/redirect-count.any.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
-crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener_base.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/html/user-activation/activation-transfer-without-click.tentative.html [ Pass ]
 crbug.com/591099 external/wpt/portals/portals-adopt-predecessor.html [ Pass Timeout ]
@@ -268,13 +268,12 @@
 crbug.com/591099 external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Pass ]
 crbug.com/591099 external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Pass ]
 crbug.com/591099 external/wpt/service-workers/service-worker/client-navigate.https.html [ Pass ]
-crbug.com/591099 external/wpt/wasm/webapi/rejected-arg.any.serviceworker.html [ Pass ]
 crbug.com/591099 external/wpt/webauthn/createcredential-extensions.https.html [ Pass ]
 crbug.com/591099 external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html [ Pass ]
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
 crbug.com/591099 fast/block/float/4145535Crash.html [ Pass ]
 crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
-crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
+crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-tables.html [ Failure Pass ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
@@ -282,7 +281,7 @@
 crbug.com/591099 fast/css/outline-offset-large.html [ Failure ]
 crbug.com/855279 fast/css/text-overflow-ellipsis-vertical-hittest.html [ Pass ]
 crbug.com/591099 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under.html [ Failure ]
-crbug.com/591099 fast/events/before-unload-return-value-from-listener.html [ Pass Timeout ]
+crbug.com/591099 fast/events/before-unload-return-value-from-listener.html [ Pass ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
@@ -291,6 +290,9 @@
 crbug.com/591099 fast/peerconnection/RTCPeerConnection-many.html [ Pass ]
 crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure Pass ]
 # Some outline rect is added double offset.
+crbug.com/591099 external/wpt/css/css-text/hyphens/hyphens-shaping-001.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-text/hyphens/shy-styling-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-015.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-atomic-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-atomic-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-atomic-003.html [ Pass ]
@@ -300,8 +302,20 @@
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-replaced-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-replaced-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-replaced-003.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-text/overflow-wrap/overflow-wrap-shaping-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/shaping/shaping-023.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/white-space/control-chars-00C.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-text/white-space/white-space-intrinsic-size-004.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-002.html [ Pass ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html [ Timeout ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch.html [ Timeout ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html [ Timeout ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html [ Timeout ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html [ Timeout ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-none-css_touch.html [ Failure Pass Timeout ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch.html [ Failure Pass Timeout ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html [ Pass Timeout ]
 crbug.com/835484 fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html [ Failure ]
 crbug.com/899902 fast/text/ellipsis-with-self-painting-layer.html [ Pass ]
 crbug.com/591099 fast/text/emoji-vertical-origin-visual.html [ Failure ]
@@ -315,11 +329,11 @@
 crbug.com/591099 http/tests/appcache/non-html.xhtml [ Crash Pass ]
 crbug.com/591099 http/tests/csspaint/invalidation-border-image.html [ Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js [ Crash Pass ]
-crbug.com/591099 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Pass ]
+crbug.com/591099 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/tracing-session-id.js [ Pass ]
 crbug.com/591099 http/tests/devtools/tracing/console-timeline.js [ Pass ]
 crbug.com/591099 http/tests/html/validation-bubble-oopif-clip.html [ Pass ]
-crbug.com/591099 http/tests/media/autoplay/document-user-activation-cross-origin-feature-policy-disabled.html [ Failure Pass ]
+crbug.com/591099 http/tests/media/autoplay/document-user-activation-cross-origin-feature-policy-disabled.html [ Failure ]
 crbug.com/591099 http/tests/media/video-load-metadata-decode-error.html [ Pass ]
 crbug.com/591099 http/tests/security/inactive-document-with-empty-security-origin.html [ Pass ]
 crbug.com/591099 http/tests/security/mixedContent/insecure-css-resources.html [ Failure Pass ]
@@ -331,7 +345,7 @@
 crbug.com/591099 paint/invalidation/scroll/fixed-under-composited-fixed-scrolled.html [ Failure ]
 crbug.com/591099 paint/invalidation/svg/svg-background-partial-redraw.html [ Failure ]
 crbug.com/591099 paint/invalidation/svg/transform-focus-ring-repaint.html [ Failure ]
-crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass ]
+crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass Timeout ]
 crbug.com/591099 svg/zoom/page/zoom-svg-float-border-padding.xml [ Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Pass ]
 crbug.com/591099 virtual/android/rootscroller/set-root-scroller.html [ Pass ]
@@ -339,6 +353,7 @@
 crbug.com/916511 virtual/composite-after-paint/paint/background/scrolling-background-with-negative-z-child.html [ Crash ]
 crbug.com/591099 virtual/composite-after-paint/paint/invalidation/box/margin.html [ Failure Pass ]
 Bug(none) virtual/disable-blink-gen-property-trees/ [ Skip ]
+crbug.com/591099 virtual/display-lock/http/tests/devtools/elements/highlight/highlight-display-locked.js [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/lock-after-append/acquire-after-resize.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/lock-after-append/measure-forced-layout-after-commit.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/lock-after-append/measure-forced-layout.html [ Failure ]
@@ -349,26 +364,25 @@
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/lock-before-append/measure-forced-layout.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/lock-before-append/measure-updated-layout.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-and-scrollbars.html [ Failure ]
-crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-min-content.html [ Failure ]
+crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-scrollbars.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/flex-row-horizontal-with-grow.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/flex-row-horizontal.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/flex-row-vertical-with-grow.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/flex-row-vertical.html [ Failure ]
-crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/writing-modes.html [ Failure ]
-crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/writing-modes-switch.html [ Failure ]
-crbug.com/955533 virtual/display-lock/wpt_internal/display-lock/sizing/overflow-auto-with-overflow.html [ Failure ]
-crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/min-width-respected.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/float-left.html [ Failure ]
-crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/writing-modes-inherited-after-append.html [ Failure ]
 crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/max-content-size-ignored.html [ Failure ]
-crbug.com/591099 virtual/display-lock/http/tests/devtools/elements/highlight/highlight-display-locked.js [ Failure ]
+crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/min-width-respected.html [ Failure ]
+crbug.com/955533 virtual/display-lock/wpt_internal/display-lock/sizing/overflow-auto-with-overflow.html [ Failure ]
+crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/writing-modes-inherited-after-append.html [ Failure ]
+crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/writing-modes-switch.html [ Failure ]
+crbug.com/917392 virtual/display-lock/wpt_internal/display-lock/sizing/writing-modes.html [ Failure ]
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/unscrollable-layer-subpixel-size-with-negative-overflow.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Pass ]
-crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-filter.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blend-image.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-color-over-pattern.html [ Pass ]
diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations
index 2e2c65a..bc3ce255 100644
--- a/third_party/blink/web_tests/LeakExpectations
+++ b/third_party/blink/web_tests/LeakExpectations
@@ -92,11 +92,6 @@
 #Sheriff 2019-02-21
 crbug.com/934144 [ Linux ] http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.js [ Pass Leak ]
 
-#Sheriff 2019-02-25
-crbug.com/894651 [ Linux ] virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_09_rtl_multi_line.html [ Failure Leak ]
-crbug.com/894651 [ Linux ] virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_09_ltr_multi_line.html [ Failure Leak ]
-crbug.com/894651 [ Linux ] virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_09_rtl_multi_line.html [ Failure Leak ]
-
 #Sheriff 2019-04-10
 crbug.com/951453 [ Linux ] external/wpt/html/user-activation/activation-transfer-cross-origin-with-click.sub.tentative.html [ Pass Leak ]
 
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index b2430d9..b9e2d3bc 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -145,7 +145,6 @@
 # FIXME: These tests might still be buggy and time out. They were marked as Slow on 9/20/2013.
 # Double-check the data after they've been running another week or so.
 crbug.com/245154 editing/selection/modify_move/move-by-character-brute-force.html [ Slow ]
-crbug.com/245154 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-character-brute-force.html [ Slow ]
 
 # This test takes 5+ seconds as intended because it tests connection throttling.
 crbug.com/459377 http/tests/websocket/multiple-connections-throttled.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 1aa30eb3..ae8fa4c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1681,68 +1681,6 @@
 crbug.com/875235 virtual/layout_ng_experimental/fast/forms/fieldset/legend-after-margin-with-before-border-horizontal-mode.html [ Failure ]
 crbug.com/875235 virtual/layout_ng_experimental/fast/forms/fieldset/legend-small-after-margin-before-border-horizontal-mode.html [ Failure ]
 
-### virtual/bidi-caret-affinity/editing/selection/modify_move/
-crbug.com/923087 virtual/bidi-caret-affinity/editing/selection/modify_move/css-pseudo-element.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-crash-test-1.html [ Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-crash-test-2.html [ Pass Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-crash-test-3.html [ Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-crash-test-4.html [ Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-crash-test-5.html [ Pass Timeout Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-crash-test-css-generated-content.html [ Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-inline-block-positioned-element.html [ Crash Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-mac.html [ Timeout Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-multi-space.html [ Timeout Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-single-space-inline-element.html [ Timeout Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-single-space-one-element.html [ Timeout Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-word-visually-wrong-left-right.html [ Crash Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_crossing_inline_block_boundary.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move-forward-after-line-break.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_forward_line_br.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_forward_line_range.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_forward_line_small_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_into_inline_block_multiline.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_into_inline_block_nested.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_into_inline_block_one_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_01_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_01_rtl_multi_line.html [ Failure Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_02_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_02_rtl_multi_line.html [ Failure Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_03_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_03_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_04_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_04_rtl_multi_line.html [ Failure Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_05_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_05_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_06_ltr_multi_line.html [ Failure Timeout Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_06_rtl_multi_line.html [ Failure Timeout Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_07_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_07_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_08_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_08_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_09_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_09_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_out_of_inline_block_multiline.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_out_of_inline_block_nested.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_out_of_inline_block_one_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_01_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_01_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_02_ltr_multi_line.html [ Failure Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_02_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_03_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_03_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_04_ltr_multi_line.html [ Failure Crash ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_04_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_05_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_05_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_06_ltr_multi_line.html [ Failure Crash Timeout ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_06_rtl_multi_line.html [ Failure Crash Timeout ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_07_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_07_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_08_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_08_rtl_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_09_ltr_multi_line.html [ Failure ]
-crbug.com/894651 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_09_rtl_multi_line.html [ Failure ]
-
 # ====== LayoutNG-only failures until here ======
 
 
@@ -2133,6 +2071,7 @@
 crbug.com/626703 [ Linux ] external/wpt/css/css-text/word-break/word-break-normal-lo-000.html [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/css-text/word-break/word-break-normal-lo-000.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/word-break/word-break-normal-tdd-000.html [ Failure ]
+crbug.com/952254 external/wpt/css/css-text/white-space/break-spaces-008.html [ Failure ]
 crbug.com/40634 external/wpt/css/css-text/white-space/trailing-space-before-br-001.html [ Failure ]
 
 # The 'line-break: anywhere' feature is not implemented yet
@@ -2524,8 +2463,7 @@
 
 # Since there is no compositor thread when running tests then there is no main thread event queue. Hence the
 # logic for this test will be skipped when running Layout tests.
-crbug.com/770028 external/wpt/pointerevents/extension/pointerevent_pointerrawmove-manual.html [ Skip ]
-crbug.com/770028 external/wpt/pointerevents/extension/pointerevent_pointerrawmove_in_pointerlock-manual.html [ Skip ]
+crbug.com/770028 external/wpt/pointerevents/extension/pointerevent_pointerrawupdate_in_pointerlock-manual.html [ Skip ]
 crbug.com/770028 external/wpt/pointerevents/extension/pointerevent_predicted_events_attributes-manual.html [ Skip ]
 crbug.com/770028 external/wpt/pointerevents/extension/pointerevent_getPredictedEvents_when_pointerlocked-manual.html [ Skip ]
 
@@ -2878,6 +2816,11 @@
 # Sheriff 2019-03-08
 crbug.com/940050 virtual/threaded/external/wpt/animation-worklet/playback-rate.https.html [ Pass Timeout ]
 
+crbug.com/937456 virtual/threaded/animations/animationworklet/scroll-timeline-non-compositable.html [ Failure ]
+crbug.com/937456 virtual/disable-blink-gen-property-trees/animations/animationworklet/scroll-timeline-non-compositable.html [ Failure ]
+crbug.com/937456 virtual/disable-blink-gen-property-trees/animations/animationworklet/scroll-timeline-non-scrollable.html [ Failure ]
+crbug.com/937456 virtual/threaded/animations/animationworklet/scroll-timeline-non-scrollable.html [ Failure ]
+
 # Untriaged failures after https://crrev.com/c/543695/.
 # These need to be updated but appear not to be related to that change.
 crbug.com/626703 http/tests/devtools/indexeddb/database-refresh-view.js [ Pass Failure ]
@@ -3135,7 +3078,6 @@
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-016.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-pseudo/marker-content-010.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-padding-002.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/white-space/break-spaces-008.html [ Failure ]
 crbug.com/626703 [ Win7 ] external/wpt/upgrade-insecure-requests/image-redirect-upgrade.https.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-atomic-005.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-atomic-008.html [ Failure ]
@@ -4291,15 +4233,14 @@
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/geometry-border-image-003.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/geometry-border-image-004.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/geometry-with-float-size.https.html [ Failure ]
-crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/invalid-image-constructor-error.https.html [ Crash ]
-crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/invalid-image-paint-error.https.html [ Crash ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/invalid-image-constructor-error.https.html [ Failure ]
 crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/invalid-image-pending-script.https.html [ Crash ]
-crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/paint-arguments.https.html [ Crash ]
-crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/paint-function-arguments.https.html [ Crash ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint-arguments.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint-function-arguments.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-composite.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-filter.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-gradient.https.html [ Failure ]
-crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/paint2d-image.https.html [ Crash Timeout ]
+crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/paint2d-image.https.html [ Failure Timeout ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-paths.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-rects.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-shadows.https.html [ Failure ]
@@ -4321,45 +4262,45 @@
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-015.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-016.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-017.https.html [ Failure ]
-crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-018.https.html [ Crash Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-018.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-019.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-020.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-021.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/parse-input-arguments-022.https.html [ Failure ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-001.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-002.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-003.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-004.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-005.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-006.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-007.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-008.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-009.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-010.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-invalidation-001.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-invalidation-002.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-stylemap.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-001.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-002.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-003.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-004.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-005.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-006.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-007.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-008.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-009.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-010.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-011.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-012.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-013.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-014.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-015.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-016.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-017.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-018.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/style-background-image.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/style-before-pseudo.https.html [ Crash ]
-crbug.com/957458 virtual/threaded/external/wpt/css/css-paint-api/style-first-letter-pseudo.https.html [ Crash ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-001.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-002.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-003.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-004.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-005.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-006.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-007.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-008.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-009.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-interpolation-010.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-invalidation-001.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-invalidation-002.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-stylemap.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-001.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-002.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-003.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-004.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-005.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-006.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-007.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-008.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-009.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-010.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-011.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-012.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-013.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-014.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-015.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-016.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-017.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/registered-property-value-018.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/style-background-image.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/style-before-pseudo.https.html [ Failure ]
+crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/style-first-letter-pseudo.https.html [ Failure ]
 
 # Shared memory growth temporarily disabled.
 crbug.com/951795 external/wpt/wasm/jsapi/memory/grow.any.html [ Pass Failure ]
@@ -6255,3 +6196,10 @@
 crbug.com/958347 [ Linux ] external/wpt/editing/run/removeformat.html [ Pass Crash ]
 crbug.com/941931 [ Linux Win ] virtual/outofblink-cors/http/tests/security/contentSecurityPolicy/1.1/plugintypes-affects-cross-site-child-disallowed.html [ Pass Failure ]
 crbug.com/958426 [ Mac10.13 ] fast/text/line-break-ascii.html [ Timeout Pass ]
+
+# Pointer Events moving to WPT, timeout failures, see bug
+crbug.com/959168 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html [ Timeout Pass ]
+crbug.com/959168 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch.html [ Timeout Pass ]
+crbug.com/959168 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html [ Timeout Pass ]
+crbug.com/959168 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html [ Timeout Pass ]
+crbug.com/959168 external/wpt/pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html [ Timeout Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 3a34f5e..77f9fc7 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1048,11 +1048,6 @@
              "--enable-spatial-navigation"]
   },
   {
-    "prefix": "bidi-caret-affinity",
-    "base": "editing/selection/modify_move",
-    "args": ["--enable-blink-features=BidiCaretAffinity,EditingNG"]
-  },
-  {
     "prefix": "passive-fingerprinting",
     "base": "http/tests/navigation/useragent.php",
     "args": ["--enable-features=FreezeUserAgent"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index b43990bc..7b26c937 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -5827,6 +5827,12 @@
      {}
     ]
    ],
+   "html/user-activation/no-activation-thru-escape-key-manual.html": [
+    [
+     "html/user-activation/no-activation-thru-escape-key-manual.html",
+     {}
+    ]
+   ],
    "html/webappapis/animation-frames/cancel-handle-manual.html": [
     [
      "html/webappapis/animation-frames/cancel-handle-manual.html",
@@ -6385,6 +6391,12 @@
      {}
     ]
    ],
+   "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked-manual.html": [
+    [
+     "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked-manual.html",
+     {}
+    ]
+   ],
    "pointerevents/extension/pointerevent_getPredictedEvents_when_pointerlocked-manual.html": [
     [
      "pointerevents/extension/pointerevent_getPredictedEvents_when_pointerlocked-manual.html",
@@ -6451,6 +6463,12 @@
      {}
     ]
    ],
+   "pointerevents/pointerevent_boundary_events_in_capturing-manual.html": [
+    [
+     "pointerevents/pointerevent_boundary_events_in_capturing-manual.html",
+     {}
+    ]
+   ],
    "pointerevents/pointerevent_capture_suppressing_mouse-manual.html": [
     [
      "pointerevents/pointerevent_capture_suppressing_mouse-manual.html",
@@ -6481,48 +6499,30 @@
      {}
     ]
    ],
+   "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html": [
+    [
+     "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html",
+     {}
+    ]
+   ],
    "pointerevents/pointerevent_sequence_at_implicit_release_on_click-manual.html": [
     [
      "pointerevents/pointerevent_sequence_at_implicit_release_on_click-manual.html",
      {}
     ]
    ],
+   "pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html": [
+    [
+     "pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html",
+     {}
+    ]
+   ],
    "pointerevents/pointerevent_touch-action-button-test_touch-manual.html": [
     [
      "pointerevents/pointerevent_touch-action-button-test_touch-manual.html",
      {}
     ]
    ],
-   "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html": [
-    [
-     "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html": [
-    [
-     "pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html": [
-    [
-     "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html": [
-    [
-     "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html",
-     {}
-    ]
-   ],
-   "pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html": [
-    [
-     "pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html",
-     {}
-    ]
-   ],
    "pointerevents/pointerevent_touch-action-keyboard-manual.html": [
     [
      "pointerevents/pointerevent_touch-action-keyboard-manual.html",
@@ -6565,6 +6565,12 @@
      {}
     ]
    ],
+   "pointerevents/pointerlock/pointerevent_movementxy_when_locked-manual.html": [
+    [
+     "pointerevents/pointerlock/pointerevent_movementxy_when_locked-manual.html",
+     {}
+    ]
+   ],
    "pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html": [
     [
      "pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html",
@@ -158511,11 +158517,6 @@
      {}
     ]
    ],
-   "css/mediaqueries/prefers-color-scheme-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "css/mediaqueries/reference/ref-green-body.xht": [
     [
      {}
@@ -169046,6 +169047,11 @@
      {}
     ]
    ],
+   "html/browsers/the-window-object/support/sizing-target.html": [
+    [
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/window-indexed-properties-expected.txt": [
     [
      {}
@@ -176386,11 +176392,6 @@
      {}
     ]
    ],
-   "html/semantics/embedded-content/the-object-element/test2.html": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/embedded-content/the-object-element/usemap-casing-expected.txt": [
     [
      {}
@@ -176441,6 +176442,11 @@
      {}
     ]
    ],
+   "html/semantics/forms/autofocus/resources/child-autofocus.html": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/forms/constraints/contains.json": [
     [
      {}
@@ -178931,11 +178937,26 @@
      {}
     ]
    ],
+   "html/webappapis/scripting/event-loops/fully_active_document.window-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/webappapis/scripting/event-loops/resources/common.js": [
     [
      {}
     ]
    ],
+   "html/webappapis/scripting/event-loops/resources/iframe.html": [
+    [
+     {}
+    ]
+   ],
+   "html/webappapis/scripting/event-loops/resources/page-with-frame.html": [
+    [
+     {}
+    ]
+   ],
    "html/webappapis/scripting/events/OWNERS": [
     [
      {}
@@ -199406,6 +199427,16 @@
      {}
     ]
    ],
+   "trusted-types/support/WorkerGlobalScope-importScripts.https.js": [
+    [
+     {}
+    ]
+   ],
+   "trusted-types/support/WorkerGlobalScope-importScripts.https.js.headers": [
+    [
+     {}
+    ]
+   ],
    "trusted-types/support/helper.sub.js": [
     [
      {}
@@ -232665,6 +232696,12 @@
      {}
     ]
    ],
+   "css/css-position/position-absolute-in-inline-002.html": [
+    [
+     "css/css-position/position-absolute-in-inline-002.html",
+     {}
+    ]
+   ],
    "css/css-position/position-absolute-in-inline-crash.html": [
     [
      "css/css-position/position-absolute-in-inline-crash.html",
@@ -261534,6 +261571,12 @@
      {}
     ]
    ],
+   "html/browsers/the-window-object/noopener-noreferrer-sizing.window.js": [
+    [
+     "html/browsers/the-window-object/noopener-noreferrer-sizing.window.html",
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/security-window/window-security.https.html": [
     [
      "html/browsers/the-window-object/security-window/window-security.https.html",
@@ -266723,12 +266766,6 @@
      {}
     ]
    ],
-   "html/semantics/embedded-content/the-object-element/object-fallback.html": [
-    [
-     "html/semantics/embedded-content/the-object-element/object-fallback.html",
-     {}
-    ]
-   ],
    "html/semantics/embedded-content/the-object-element/object-handler.html": [
     [
      "html/semantics/embedded-content/the-object-element/object-handler.html",
@@ -266819,6 +266856,14 @@
      {}
     ]
    ],
+   "html/semantics/forms/autofocus/no-cross-origin-autofocus.sub.html": [
+    [
+     "html/semantics/forms/autofocus/no-cross-origin-autofocus.sub.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "html/semantics/forms/autofocus/not-on-first-task.html": [
     [
      "html/semantics/forms/autofocus/not-on-first-task.html",
@@ -272858,6 +272903,12 @@
      {}
     ]
    ],
+   "html/webappapis/scripting/event-loops/fully_active_document.window.js": [
+    [
+     "html/webappapis/scripting/event-loops/fully_active_document.window.html",
+     {}
+    ]
+   ],
    "html/webappapis/scripting/event-loops/microtask_after_raf.html": [
     [
      "html/webappapis/scripting/event-loops/microtask_after_raf.html",
@@ -290218,14 +290269,6 @@
      {}
     ]
    ],
-   "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked.html": [
-    [
-     "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked.html",
-     {
-      "testdriver": true
-     }
-    ]
-   ],
    "pointerevents/extension/pointerevent_touch-action-verification.html": [
     [
      "pointerevents/extension/pointerevent_touch-action-verification.html",
@@ -290257,14 +290300,6 @@
      }
     ]
    ],
-   "pointerevents/pointerevent_boundary_events_in_capturing.html": [
-    [
-     "pointerevents/pointerevent_boundary_events_in_capturing.html",
-     {
-      "testdriver": true
-     }
-    ]
-   ],
    "pointerevents/pointerevent_capture_mouse.html": [
     [
      "pointerevents/pointerevent_capture_mouse.html",
@@ -290438,14 +290473,6 @@
      }
     ]
    ],
-   "pointerevents/pointerevent_releasepointercapture_events_to_original_target.html": [
-    [
-     "pointerevents/pointerevent_releasepointercapture_events_to_original_target.html",
-     {
-      "testdriver": true
-     }
-    ]
-   ],
    "pointerevents/pointerevent_releasepointercapture_invalid_pointerid.html": [
     [
      "pointerevents/pointerevent_releasepointercapture_invalid_pointerid.html",
@@ -290483,14 +290510,6 @@
      {}
     ]
    ],
-   "pointerevents/pointerevent_sequence_at_implicit_release_on_drag.html": [
-    [
-     "pointerevents/pointerevent_sequence_at_implicit_release_on_drag.html",
-     {
-      "testdriver": true
-     }
-    ]
-   ],
    "pointerevents/pointerevent_setpointercapture_disconnected.html": [
     [
      "pointerevents/pointerevent_setpointercapture_disconnected.html",
@@ -290553,6 +290572,38 @@
      {}
     ]
    ],
+   "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html": [
+    [
+     "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/pointerevent_touch-action-inherit_child-none_touch.html": [
+    [
+     "pointerevents/pointerevent_touch-action-inherit_child-none_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html": [
+    [
+     "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html": [
+    [
+     "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html": [
     [
      "pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html",
@@ -290561,6 +290612,14 @@
      }
     ]
    ],
+   "pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html": [
+    [
+     "pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "pointerevents/pointerevent_touch-action-none-css_touch.html": [
     [
      "pointerevents/pointerevent_touch-action-none-css_touch.html",
@@ -290616,14 +290675,6 @@
      }
     ]
    ],
-   "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html": [
-    [
-     "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html",
-     {
-      "testdriver": true
-     }
-    ]
-   ],
    "pointerlock/constructor.html": [
     [
      "pointerlock/constructor.html",
@@ -290690,6 +290741,12 @@
      }
     ]
    ],
+   "portals/htmlportalelement-event-handler-content-attributes.html": [
+    [
+     "portals/htmlportalelement-event-handler-content-attributes.html",
+     {}
+    ]
+   ],
    "portals/portal-activate-data.html": [
     [
      "portals/portal-activate-data.html",
@@ -311762,6 +311819,12 @@
      {}
     ]
    ],
+   "trusted-types/WorkerGlobalScope-importScripts.https.html": [
+    [
+     "trusted-types/WorkerGlobalScope-importScripts.https.html",
+     {}
+    ]
+   ],
    "trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html": [
     [
      "trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html",
@@ -391315,6 +391378,10 @@
    "204260ee6784c9e648ab9f1e86b113f0d7227e22",
    "testharness"
   ],
+  "css/css-position/position-absolute-in-inline-002.html": [
+   "8ec3838fc773f92fdaa27b73e1bf604ec7001078",
+   "testharness"
+  ],
   "css/css-position/position-absolute-in-inline-crash.html": [
    "5d36710b6fe694b256d9841b3e7a0fff4535c85b",
    "testharness"
@@ -422351,10 +422418,6 @@
    "d039281c0254e2bb794e229baecbe4d39c547baa",
    "reftest"
   ],
-  "css/mediaqueries/prefers-color-scheme-expected.txt": [
-   "333ce42031903d3d01646f1679946f35a9942516",
-   "support"
-  ],
   "css/mediaqueries/prefers-color-scheme.html": [
    "c6ca45ab17201466e01006cab78331a0765cc6c8",
    "testharness"
@@ -435068,7 +435131,7 @@
    "support"
   ],
   "event-timing/resources/event-timing-support.js": [
-   "1f3d9f7d4e132a1792d7e46f876fa01ee64fc6e3",
+   "f6e450da01d80a9767a8dfbc40e9c4c3dfb7899a",
    "support"
   ],
   "event-timing/resources/slow-image.py": [
@@ -439620,7 +439683,7 @@
    "support"
   ],
   "html/browsers/browsing-the-web/history-traversal/same-url-expected.txt": [
-   "bb4f317b41a1ad2036519b5b14b3b7ca3f07ab8d",
+   "8b14979e94fff7933acf3441836ca3d5af33cf24",
    "support"
   ],
   "html/browsers/browsing-the-web/history-traversal/same-url.html": [
@@ -441727,6 +441790,10 @@
    "a75a0346501a80ceef91d25ed250a2957f42cfb9",
    "testharness"
   ],
+  "html/browsers/the-window-object/noopener-noreferrer-sizing.window.js": [
+   "cc53ba5f2f59414e097fa1cd29a877db7f8d0b9f",
+   "testharness"
+  ],
   "html/browsers/the-window-object/security-window/window-security.https.html": [
    "1fb0ed7c1e62da55b890c6434bee6e46637e0209",
    "testharness"
@@ -441751,6 +441818,10 @@
    "c2446c6fe958a5a0507ffcf729fa027a8d202832",
    "support"
   ],
+  "html/browsers/the-window-object/support/sizing-target.html": [
+   "7cd5348a8585698579548eb957006b84ddddcefe",
+   "support"
+  ],
   "html/browsers/the-window-object/window-aliases.html": [
    "135be02a30add5d51a5b870cbe519d735115d3e9",
    "testharness"
@@ -442452,7 +442523,7 @@
    "testharness"
   ],
   "html/dom/elements-embedded.js": [
-   "af6c79e74f4ee302027c8f647bd09dedd43c414e",
+   "27b5b61845d46b462ae9ccb5fd61cfdca9c804f6",
    "support"
   ],
   "html/dom/elements-forms.js": [
@@ -443344,7 +443415,7 @@
    "support"
   ],
   "html/dom/reflection-embedded-expected.txt": [
-   "edf5ad2a2430ab7ef5119f51f530e53a5ccd6091",
+   "41ca1ef36d5601818cb33cab91399e0e4ca5db3a",
    "support"
   ],
   "html/dom/reflection-embedded.html": [
@@ -452188,7 +452259,7 @@
    "testharness"
   ],
   "html/semantics/embedded-content/the-object-element/historical.html": [
-   "0fba470303db829e3df95ee8a2287002b031cbc0",
+   "2f293d372ec19082add2797e9bb43fef57fbb12d",
    "testharness"
   ],
   "html/semantics/embedded-content/the-object-element/object-attributes-expected.txt": [
@@ -452211,10 +452282,6 @@
    "d2190cc7af81e0db493fe03234cdae36dcf2b5ee",
    "testharness"
   ],
-  "html/semantics/embedded-content/the-object-element/object-fallback.html": [
-   "d5469a3edc140dd8ce4250bfc665be8ce78e9c94",
-   "testharness"
-  ],
   "html/semantics/embedded-content/the-object-element/object-handler.html": [
    "a24554e0cc32a0e3ceec301667e2048c58a940c0",
    "testharness"
@@ -452247,10 +452314,6 @@
    "cf2423275ea05b4c0d8aca59fe55f49d165b559c",
    "support"
   ],
-  "html/semantics/embedded-content/the-object-element/test2.html": [
-   "e5061eaea0d8adb6d8d3b9b84bca1c8a10d3c563",
-   "support"
-  ],
   "html/semantics/embedded-content/the-object-element/usemap-casing-expected.txt": [
    "bde917fdf4f4738fd19992389c476e1221a8b344",
    "support"
@@ -452359,10 +452422,18 @@
    "de56cf74eda506c55460cc6da85923b5b7001381",
    "testharness"
   ],
+  "html/semantics/forms/autofocus/no-cross-origin-autofocus.sub.html": [
+   "cc018814c922534d57e3945bd3990444853a5131",
+   "testharness"
+  ],
   "html/semantics/forms/autofocus/not-on-first-task.html": [
    "50efc176935c710f43a42c31ecc0b7676e96b833",
    "testharness"
   ],
+  "html/semantics/forms/autofocus/resources/child-autofocus.html": [
+   "afd5601a523ff0a1d60d37b171b2098a38600ace",
+   "support"
+  ],
   "html/semantics/forms/constraints/contains.json": [
    "67e4c3b12e0c74c3d04b21a80a902d1173772b55",
    "support"
@@ -457375,6 +457446,10 @@
    "8e2b1d07014e8bd754d943e11672fff0719bbb74",
    "testharness"
   ],
+  "html/user-activation/no-activation-thru-escape-key-manual.html": [
+   "4f03195f434742d80574c481092b307d4ad9108f",
+   "manual"
+  ],
   "html/user-activation/resources/child-five.html": [
    "9260a300a1bdd1561dbae8ae99e8be7a74bce337",
    "support"
@@ -458215,6 +458290,14 @@
    "5d7e5e600e90861a1703ae37321b1b2583024d19",
    "support"
   ],
+  "html/webappapis/scripting/event-loops/fully_active_document.window-expected.txt": [
+   "771e58ec4f284f19efda49c1e9e7d85eab53cfc3",
+   "support"
+  ],
+  "html/webappapis/scripting/event-loops/fully_active_document.window.js": [
+   "950a8a29ee5731785f350508dc8abec7ca98ba64",
+   "testharness"
+  ],
   "html/webappapis/scripting/event-loops/microtask_after_raf.html": [
    "824dbc4b92e33323862c5ce59c427cba079d98ce",
    "testharness"
@@ -458227,6 +458310,14 @@
    "e2279f93ddb09d14d7065c89357ab102e0ba0ce0",
    "support"
   ],
+  "html/webappapis/scripting/event-loops/resources/iframe.html": [
+   "32e486236079ea089c0084bad1118599af06f2cd",
+   "support"
+  ],
+  "html/webappapis/scripting/event-loops/resources/page-with-frame.html": [
+   "f13170576efc074f3c92528f707fe8952d85f0cc",
+   "support"
+  ],
   "html/webappapis/scripting/event-loops/task_microtask_ordering.html": [
    "c14a043b6ab10ab5e9e08d5bae1088f8dbf5e9c3",
    "testharness"
@@ -473595,9 +473686,9 @@
    "6971dcecfdebf3a113ef4ef9c9e8bd7bdf88ea02",
    "testharness"
   ],
-  "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked.html": [
-   "8e93cf32a38f04a18edd318aa5dd962edf7381c1",
-   "testharness"
+  "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked-manual.html": [
+   "6efded85b4562bd960a4b5e584e68984a1ce6316",
+   "manual"
   ],
   "pointerevents/extension/pointerevent_getPredictedEvents_when_pointerlocked-manual.html": [
    "eaf08d675a403aaf8bbf5a39e965af39a15d9d4e",
@@ -473663,9 +473754,9 @@
    "e860cd082bede68aa014fe36ceff011e8227e2ad",
    "testharness"
   ],
-  "pointerevents/pointerevent_boundary_events_in_capturing.html": [
-   "1ed26eb6dcfcd728440a0eae5ddede45fe9a8dcf",
-   "testharness"
+  "pointerevents/pointerevent_boundary_events_in_capturing-manual.html": [
+   "0de4d55ed13ed67229cc4a6a0f77635fad815d01",
+   "manual"
   ],
   "pointerevents/pointerevent_capture_mouse.html": [
    "d8d54db6ba302eff8e2df5c5fe13c209b3183a55",
@@ -473775,9 +473866,9 @@
    "07df04fc2046737997b70b50063825d292af90de",
    "testharness"
   ],
-  "pointerevents/pointerevent_releasepointercapture_events_to_original_target.html": [
-   "12e31cdb234d1bbb5cc43b436415e44b12daaef2",
-   "testharness"
+  "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html": [
+   "89f3d839f46d9982130d6aec3c9c0ed75862bfa4",
+   "manual"
   ],
   "pointerevents/pointerevent_releasepointercapture_invalid_pointerid.html": [
    "824494551671a8a15a6aa2a73a110a65beff0086",
@@ -473803,9 +473894,9 @@
    "0b93c847ed216653891d00cf55b5b00e41424b50",
    "manual"
   ],
-  "pointerevents/pointerevent_sequence_at_implicit_release_on_drag.html": [
-   "5f75243347a83b32a17652880c356a72bd80591a",
-   "testharness"
+  "pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html": [
+   "982167dc5014d06c0babd3222696c8ba556d882e",
+   "manual"
   ],
   "pointerevents/pointerevent_setpointercapture_disconnected.html": [
    "a7cc3e00e23f1544cdb81762025929a194df0f75",
@@ -473828,7 +473919,7 @@
    "support"
   ],
   "pointerevents/pointerevent_support.js": [
-   "44dba450a3a2d558d3314da9413eb18a5ba9a1ff",
+   "e8c847b12a880a557d8d3cd69bc0bc77cf3378af",
    "support"
   ],
   "pointerevents/pointerevent_suppress_compat_events_on_click.html": [
@@ -473851,29 +473942,29 @@
    "5fe6179840eeda9a025e951f8ff28b211da9fafe",
    "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html": [
-   "dcea2837502b82b3fc873ddf3a4b044e38165c02",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html": [
+   "ae2373c3f532fdada27c941617f8d05d0d2a7da3",
+   "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html": [
-   "16e42954e51abc58c89e608c0edfa29d9a44b63b",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_child-none_touch.html": [
+   "81f0ea6050a4b060708bcebc1eeb65d7ee904c70",
+   "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html": [
-   "c75d067e447f7382005542df6ed267850ef6aa0a",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html": [
+   "775708d4a7741d053ea20472d94bf4f936175804",
+   "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html": [
-   "d420cc56c77b6910ee96d875ee24eb0b9b0a4c71",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html": [
+   "592cfd6ae5367d2830ce3343aae7cae0e1d737a0",
+   "testharness"
   ],
   "pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html": [
    "a1fefe16982316546b2cb0a7bf14362fe21f7145",
    "testharness"
   ],
-  "pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html": [
-   "5e674a14da550fb63bfe53859a8e4db529f559e8",
-   "manual"
+  "pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html": [
+   "45ea1432b4e4ad5de824bf1d1798e458a939dbc7",
+   "testharness"
   ],
   "pointerevents/pointerevent_touch-action-keyboard-manual.html": [
    "a41d7078f2ee87a8a5686379536aaf1e0de915df",
@@ -473931,9 +474022,9 @@
    "6d903c405e95bd140cc201b7191434fac57931c8",
    "manual"
   ],
-  "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html": [
-   "bdad97df04b2ca67fc1f92e256c979c137a4c66a",
-   "testharness"
+  "pointerevents/pointerlock/pointerevent_movementxy_when_locked-manual.html": [
+   "ccb8c27cb59bb1732dc72c5c26b6ca2a8fdf9f5c",
+   "manual"
   ],
   "pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html": [
    "8ac35f82856a38e887ec84ad67f5c374014905c5",
@@ -474055,6 +474146,10 @@
    "29134d490f7bdfb09255e190fe91576629057c78",
    "support"
   ],
+  "portals/htmlportalelement-event-handler-content-attributes.html": [
+   "8fc26386cfc9d30e89062440b9347c62b60aa592",
+   "testharness"
+  ],
   "portals/portal-activate-data.html": [
    "d35282666d824b2d44d8f4b7e29e3cb549b04cec",
    "testharness"
@@ -474108,7 +474203,7 @@
    "testharness"
   ],
   "portals/portals-host-post-message.sub.html": [
-   "a142f5570c5c9e6cd8e095b81f2cacd7e9f97dff",
+   "a19715eb0af90c38aec08e3d488523a9c3674a1f",
    "testharness"
   ],
   "portals/portals-nested.html": [
@@ -474188,7 +474283,7 @@
    "support"
   ],
   "portals/resources/portal-host-post-message.sub.html": [
-   "8df9830d175ee546264f1f611b0341007a7c21a8",
+   "06d42820a3a9a907de9904fbe8e4b00c3dc55caf",
    "support"
   ],
   "portals/resources/portal-host.html": [
@@ -474220,7 +474315,7 @@
    "support"
   ],
   "portals/resources/portal-post-message-portal.html": [
-   "539048c13f5e8c21f7bda5e7d7e1b4772efb5ded",
+   "1dae5d1fb4528f640006fe4598c015db778d35c0",
    "support"
   ],
   "portals/resources/portals-adopt-predecessor-portal.html": [
@@ -497687,6 +497782,10 @@
    "172d566e57fc635b551b5d355661db690869b220",
    "testharness"
   ],
+  "trusted-types/WorkerGlobalScope-importScripts.https.html": [
+   "6ae52639d1dc0d5b303cb4cdb6fb727481234be9",
+   "testharness"
+  ],
   "trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html": [
    "4446a58836695355efd0fbf3f9f5a0bd6c60c8a3",
    "testharness"
@@ -497751,6 +497850,14 @@
    "de13697764ed487060de3dd425cd39cba73ff13b",
    "testharness"
   ],
+  "trusted-types/support/WorkerGlobalScope-importScripts.https.js": [
+   "8665c695c92137147193cfed075083e2de15cd90",
+   "support"
+  ],
+  "trusted-types/support/WorkerGlobalScope-importScripts.https.js.headers": [
+   "1bc33add09b4b34ce2cba21f488f8ed53345a27a",
+   "support"
+  ],
   "trusted-types/support/helper.sub.js": [
    "36ee24046ed283fc294978ada74168c515d3e17f",
    "support"
@@ -503456,7 +503563,7 @@
    "testharness"
   ],
   "webrtc/RTCTrackEvent-fire.html": [
-   "2e226c35174ec2030550cbd1788737573ca49eeb",
+   "eca8644120e86c99f01cfbaf27a1b33847b975bb",
    "testharness"
   ],
   "webrtc/coverage/RTCDTMFSender.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any-expected.txt b/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any-expected.txt
deleted file mode 100644
index c28fc328..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL cursor.request from IDBObjectStore.openCursor assert_equals: cursor.request expected (object) object "[object IDBRequest]" but got (undefined) undefined
-FAIL cursor.request from IDBObjectStore.openKeyCursor assert_equals: cursor.request expected (object) object "[object IDBRequest]" but got (undefined) undefined
-FAIL cursor.request from IDBIndex.openCursor assert_equals: cursor.request expected (object) object "[object IDBRequest]" but got (undefined) undefined
-FAIL cursor.request from IDBIndex.openKeyCursor assert_equals: cursor.request expected (object) object "[object IDBRequest]" but got (undefined) undefined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any.js
index a62efc0..60e6854 100644
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any.js
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any.js
@@ -18,6 +18,7 @@
         cursor = req.result;
         assert_equals(cursor.request, req, 'cursor.request');
         assert_readonly(cursor, 'request');
+        assert_equals(cursor.request, cursor.request, 'cursor.request does not change');
       });
 
       req.transaction.oncomplete = t.step_func(() => {
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any.worker-expected.txt
deleted file mode 100644
index c28fc328..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbcursor-request.any.worker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL cursor.request from IDBObjectStore.openCursor assert_equals: cursor.request expected (object) object "[object IDBRequest]" but got (undefined) undefined
-FAIL cursor.request from IDBObjectStore.openKeyCursor assert_equals: cursor.request expected (object) object "[object IDBRequest]" but got (undefined) undefined
-FAIL cursor.request from IDBIndex.openCursor assert_equals: cursor.request expected (object) object "[object IDBRequest]" but got (undefined) undefined
-FAIL cursor.request from IDBIndex.openKeyCursor assert_equals: cursor.request expected (object) object "[object IDBRequest]" but got (undefined) undefined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any-expected.txt
deleted file mode 100644
index b2a16a0..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any-expected.txt
+++ /dev/null
@@ -1,190 +0,0 @@
-This is a testharness.js-based test.
-Found 186 tests; 185 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS idl_test setup
-PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
-PASS IDBRequest interface: existence and properties of interface object
-PASS IDBRequest interface object length
-PASS IDBRequest interface object name
-PASS IDBRequest interface: existence and properties of interface prototype object
-PASS IDBRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBRequest interface: attribute result
-PASS IDBRequest interface: attribute error
-PASS IDBRequest interface: attribute source
-PASS IDBRequest interface: attribute transaction
-PASS IDBRequest interface: attribute readyState
-PASS IDBRequest interface: attribute onsuccess
-PASS IDBRequest interface: attribute onerror
-PASS IDBOpenDBRequest interface: existence and properties of interface object
-PASS IDBOpenDBRequest interface object length
-PASS IDBOpenDBRequest interface object name
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBOpenDBRequest interface: attribute onblocked
-PASS IDBOpenDBRequest interface: attribute onupgradeneeded
-PASS IDBVersionChangeEvent interface: existence and properties of interface object
-PASS IDBVersionChangeEvent interface object length
-PASS IDBVersionChangeEvent interface object name
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBVersionChangeEvent interface: attribute oldVersion
-PASS IDBVersionChangeEvent interface: attribute newVersion
-PASS IDBVersionChangeEvent must be primary interface of new IDBVersionChangeEvent("type")
-PASS Stringification of new IDBVersionChangeEvent("type")
-PASS IDBVersionChangeEvent interface: new IDBVersionChangeEvent("type") must inherit property "oldVersion" with the proper type
-PASS IDBVersionChangeEvent interface: new IDBVersionChangeEvent("type") must inherit property "newVersion" with the proper type
-PASS IDBFactory interface: existence and properties of interface object
-PASS IDBFactory interface object length
-PASS IDBFactory interface object name
-PASS IDBFactory interface: existence and properties of interface prototype object
-PASS IDBFactory interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBFactory interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBFactory interface: operation open(DOMString, unsigned long long)
-PASS IDBFactory interface: operation deleteDatabase(DOMString)
-PASS IDBFactory interface: operation databases()
-PASS IDBFactory interface: operation cmp(any, any)
-PASS IDBFactory must be primary interface of [object IDBFactory]
-PASS Stringification of [object IDBFactory]
-PASS IDBFactory interface: [object IDBFactory] must inherit property "open(DOMString, unsigned long long)" with the proper type
-PASS IDBFactory interface: calling open(DOMString, unsigned long long) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBFactory interface: [object IDBFactory] must inherit property "deleteDatabase(DOMString)" with the proper type
-PASS IDBFactory interface: calling deleteDatabase(DOMString) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBFactory interface: [object IDBFactory] must inherit property "databases()" with the proper type
-PASS IDBFactory interface: [object IDBFactory] must inherit property "cmp(any, any)" with the proper type
-PASS IDBFactory interface: calling cmp(any, any) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBDatabase interface: existence and properties of interface object
-PASS IDBDatabase interface object length
-PASS IDBDatabase interface object name
-PASS IDBDatabase interface: existence and properties of interface prototype object
-PASS IDBDatabase interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBDatabase interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBDatabase interface: attribute name
-PASS IDBDatabase interface: attribute version
-PASS IDBDatabase interface: attribute objectStoreNames
-PASS IDBDatabase interface: operation transaction([object Object],[object Object], IDBTransactionMode)
-PASS IDBDatabase interface: operation close()
-PASS IDBDatabase interface: operation createObjectStore(DOMString, IDBObjectStoreParameters)
-PASS IDBDatabase interface: operation deleteObjectStore(DOMString)
-PASS IDBDatabase interface: attribute onabort
-PASS IDBDatabase interface: attribute onclose
-PASS IDBDatabase interface: attribute onerror
-PASS IDBDatabase interface: attribute onversionchange
-PASS IDBObjectStore interface: existence and properties of interface object
-PASS IDBObjectStore interface object length
-PASS IDBObjectStore interface object name
-PASS IDBObjectStore interface: existence and properties of interface prototype object
-PASS IDBObjectStore interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBObjectStore interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBObjectStore interface: attribute name
-PASS IDBObjectStore interface: attribute keyPath
-PASS IDBObjectStore interface: attribute indexNames
-PASS IDBObjectStore interface: attribute transaction
-PASS IDBObjectStore interface: attribute autoIncrement
-PASS IDBObjectStore interface: operation put(any, any)
-PASS IDBObjectStore interface: operation add(any, any)
-PASS IDBObjectStore interface: operation delete(any)
-PASS IDBObjectStore interface: operation clear()
-PASS IDBObjectStore interface: operation get(any)
-PASS IDBObjectStore interface: operation getKey(any)
-PASS IDBObjectStore interface: operation getAll(any, unsigned long)
-PASS IDBObjectStore interface: operation getAllKeys(any, unsigned long)
-PASS IDBObjectStore interface: operation count(any)
-PASS IDBObjectStore interface: operation openCursor(any, IDBCursorDirection)
-PASS IDBObjectStore interface: operation openKeyCursor(any, IDBCursorDirection)
-PASS IDBObjectStore interface: operation index(DOMString)
-PASS IDBObjectStore interface: operation createIndex(DOMString, [object Object],[object Object], IDBIndexParameters)
-PASS IDBObjectStore interface: operation deleteIndex(DOMString)
-PASS IDBIndex interface: existence and properties of interface object
-PASS IDBIndex interface object length
-PASS IDBIndex interface object name
-PASS IDBIndex interface: existence and properties of interface prototype object
-PASS IDBIndex interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBIndex interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBIndex interface: attribute name
-PASS IDBIndex interface: attribute objectStore
-PASS IDBIndex interface: attribute keyPath
-PASS IDBIndex interface: attribute multiEntry
-PASS IDBIndex interface: attribute unique
-PASS IDBIndex interface: operation get(any)
-PASS IDBIndex interface: operation getKey(any)
-PASS IDBIndex interface: operation getAll(any, unsigned long)
-PASS IDBIndex interface: operation getAllKeys(any, unsigned long)
-PASS IDBIndex interface: operation count(any)
-PASS IDBIndex interface: operation openCursor(any, IDBCursorDirection)
-PASS IDBIndex interface: operation openKeyCursor(any, IDBCursorDirection)
-PASS IDBKeyRange interface: existence and properties of interface object
-PASS IDBKeyRange interface object length
-PASS IDBKeyRange interface object name
-PASS IDBKeyRange interface: existence and properties of interface prototype object
-PASS IDBKeyRange interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBKeyRange interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBKeyRange interface: attribute lower
-PASS IDBKeyRange interface: attribute upper
-PASS IDBKeyRange interface: attribute lowerOpen
-PASS IDBKeyRange interface: attribute upperOpen
-PASS IDBKeyRange interface: operation only(any)
-PASS IDBKeyRange interface: operation lowerBound(any, boolean)
-PASS IDBKeyRange interface: operation upperBound(any, boolean)
-PASS IDBKeyRange interface: operation bound(any, any, boolean, boolean)
-PASS IDBKeyRange interface: operation includes(any)
-PASS IDBKeyRange must be primary interface of [object IDBKeyRange]
-PASS Stringification of [object IDBKeyRange]
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lower" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upper" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lowerOpen" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upperOpen" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "only(any)" with the proper type
-PASS IDBKeyRange interface: calling only(any) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lowerBound(any, boolean)" with the proper type
-PASS IDBKeyRange interface: calling lowerBound(any, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upperBound(any, boolean)" with the proper type
-PASS IDBKeyRange interface: calling upperBound(any, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "bound(any, any, boolean, boolean)" with the proper type
-PASS IDBKeyRange interface: calling bound(any, any, boolean, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "includes(any)" with the proper type
-PASS IDBKeyRange interface: calling includes(any) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBCursor interface: existence and properties of interface object
-PASS IDBCursor interface object length
-PASS IDBCursor interface object name
-PASS IDBCursor interface: existence and properties of interface prototype object
-PASS IDBCursor interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBCursor interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBCursor interface: attribute source
-PASS IDBCursor interface: attribute direction
-PASS IDBCursor interface: attribute key
-PASS IDBCursor interface: attribute primaryKey
-FAIL IDBCursor interface: attribute request assert_true: The prototype object must have a property "request" expected true got false
-PASS IDBCursor interface: operation advance(unsigned long)
-PASS IDBCursor interface: operation continue(any)
-PASS IDBCursor interface: operation continuePrimaryKey(any, any)
-PASS IDBCursor interface: operation update(any)
-PASS IDBCursor interface: operation delete()
-PASS IDBCursorWithValue interface: existence and properties of interface object
-PASS IDBCursorWithValue interface object length
-PASS IDBCursorWithValue interface object name
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBCursorWithValue interface: attribute value
-PASS IDBTransaction interface: existence and properties of interface object
-PASS IDBTransaction interface object length
-PASS IDBTransaction interface object name
-PASS IDBTransaction interface: existence and properties of interface prototype object
-PASS IDBTransaction interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBTransaction interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBTransaction interface: attribute objectStoreNames
-PASS IDBTransaction interface: attribute mode
-PASS IDBTransaction interface: attribute db
-PASS IDBTransaction interface: attribute error
-PASS IDBTransaction interface: operation objectStore(DOMString)
-PASS IDBTransaction interface: operation commit()
-PASS IDBTransaction interface: operation abort()
-PASS IDBTransaction interface: attribute onabort
-PASS IDBTransaction interface: attribute oncomplete
-PASS IDBTransaction interface: attribute onerror
-PASS Window interface: attribute indexedDB
-PASS WorkerGlobalScope interface: existence and properties of interface object
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.serviceworker-expected.txt
deleted file mode 100644
index 2dc632c..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,190 +0,0 @@
-This is a testharness.js-based test.
-Found 186 tests; 185 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS idl_test setup
-PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
-PASS IDBRequest interface: existence and properties of interface object
-PASS IDBRequest interface object length
-PASS IDBRequest interface object name
-PASS IDBRequest interface: existence and properties of interface prototype object
-PASS IDBRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBRequest interface: attribute result
-PASS IDBRequest interface: attribute error
-PASS IDBRequest interface: attribute source
-PASS IDBRequest interface: attribute transaction
-PASS IDBRequest interface: attribute readyState
-PASS IDBRequest interface: attribute onsuccess
-PASS IDBRequest interface: attribute onerror
-PASS IDBOpenDBRequest interface: existence and properties of interface object
-PASS IDBOpenDBRequest interface object length
-PASS IDBOpenDBRequest interface object name
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBOpenDBRequest interface: attribute onblocked
-PASS IDBOpenDBRequest interface: attribute onupgradeneeded
-PASS IDBVersionChangeEvent interface: existence and properties of interface object
-PASS IDBVersionChangeEvent interface object length
-PASS IDBVersionChangeEvent interface object name
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBVersionChangeEvent interface: attribute oldVersion
-PASS IDBVersionChangeEvent interface: attribute newVersion
-PASS IDBVersionChangeEvent must be primary interface of new IDBVersionChangeEvent("type")
-PASS Stringification of new IDBVersionChangeEvent("type")
-PASS IDBVersionChangeEvent interface: new IDBVersionChangeEvent("type") must inherit property "oldVersion" with the proper type
-PASS IDBVersionChangeEvent interface: new IDBVersionChangeEvent("type") must inherit property "newVersion" with the proper type
-PASS IDBFactory interface: existence and properties of interface object
-PASS IDBFactory interface object length
-PASS IDBFactory interface object name
-PASS IDBFactory interface: existence and properties of interface prototype object
-PASS IDBFactory interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBFactory interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBFactory interface: operation open(DOMString, unsigned long long)
-PASS IDBFactory interface: operation deleteDatabase(DOMString)
-PASS IDBFactory interface: operation databases()
-PASS IDBFactory interface: operation cmp(any, any)
-PASS IDBFactory must be primary interface of [object IDBFactory]
-PASS Stringification of [object IDBFactory]
-PASS IDBFactory interface: [object IDBFactory] must inherit property "open(DOMString, unsigned long long)" with the proper type
-PASS IDBFactory interface: calling open(DOMString, unsigned long long) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBFactory interface: [object IDBFactory] must inherit property "deleteDatabase(DOMString)" with the proper type
-PASS IDBFactory interface: calling deleteDatabase(DOMString) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBFactory interface: [object IDBFactory] must inherit property "databases()" with the proper type
-PASS IDBFactory interface: [object IDBFactory] must inherit property "cmp(any, any)" with the proper type
-PASS IDBFactory interface: calling cmp(any, any) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBDatabase interface: existence and properties of interface object
-PASS IDBDatabase interface object length
-PASS IDBDatabase interface object name
-PASS IDBDatabase interface: existence and properties of interface prototype object
-PASS IDBDatabase interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBDatabase interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBDatabase interface: attribute name
-PASS IDBDatabase interface: attribute version
-PASS IDBDatabase interface: attribute objectStoreNames
-PASS IDBDatabase interface: operation transaction([object Object],[object Object], IDBTransactionMode)
-PASS IDBDatabase interface: operation close()
-PASS IDBDatabase interface: operation createObjectStore(DOMString, IDBObjectStoreParameters)
-PASS IDBDatabase interface: operation deleteObjectStore(DOMString)
-PASS IDBDatabase interface: attribute onabort
-PASS IDBDatabase interface: attribute onclose
-PASS IDBDatabase interface: attribute onerror
-PASS IDBDatabase interface: attribute onversionchange
-PASS IDBObjectStore interface: existence and properties of interface object
-PASS IDBObjectStore interface object length
-PASS IDBObjectStore interface object name
-PASS IDBObjectStore interface: existence and properties of interface prototype object
-PASS IDBObjectStore interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBObjectStore interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBObjectStore interface: attribute name
-PASS IDBObjectStore interface: attribute keyPath
-PASS IDBObjectStore interface: attribute indexNames
-PASS IDBObjectStore interface: attribute transaction
-PASS IDBObjectStore interface: attribute autoIncrement
-PASS IDBObjectStore interface: operation put(any, any)
-PASS IDBObjectStore interface: operation add(any, any)
-PASS IDBObjectStore interface: operation delete(any)
-PASS IDBObjectStore interface: operation clear()
-PASS IDBObjectStore interface: operation get(any)
-PASS IDBObjectStore interface: operation getKey(any)
-PASS IDBObjectStore interface: operation getAll(any, unsigned long)
-PASS IDBObjectStore interface: operation getAllKeys(any, unsigned long)
-PASS IDBObjectStore interface: operation count(any)
-PASS IDBObjectStore interface: operation openCursor(any, IDBCursorDirection)
-PASS IDBObjectStore interface: operation openKeyCursor(any, IDBCursorDirection)
-PASS IDBObjectStore interface: operation index(DOMString)
-PASS IDBObjectStore interface: operation createIndex(DOMString, [object Object],[object Object], IDBIndexParameters)
-PASS IDBObjectStore interface: operation deleteIndex(DOMString)
-PASS IDBIndex interface: existence and properties of interface object
-PASS IDBIndex interface object length
-PASS IDBIndex interface object name
-PASS IDBIndex interface: existence and properties of interface prototype object
-PASS IDBIndex interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBIndex interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBIndex interface: attribute name
-PASS IDBIndex interface: attribute objectStore
-PASS IDBIndex interface: attribute keyPath
-PASS IDBIndex interface: attribute multiEntry
-PASS IDBIndex interface: attribute unique
-PASS IDBIndex interface: operation get(any)
-PASS IDBIndex interface: operation getKey(any)
-PASS IDBIndex interface: operation getAll(any, unsigned long)
-PASS IDBIndex interface: operation getAllKeys(any, unsigned long)
-PASS IDBIndex interface: operation count(any)
-PASS IDBIndex interface: operation openCursor(any, IDBCursorDirection)
-PASS IDBIndex interface: operation openKeyCursor(any, IDBCursorDirection)
-PASS IDBKeyRange interface: existence and properties of interface object
-PASS IDBKeyRange interface object length
-PASS IDBKeyRange interface object name
-PASS IDBKeyRange interface: existence and properties of interface prototype object
-PASS IDBKeyRange interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBKeyRange interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBKeyRange interface: attribute lower
-PASS IDBKeyRange interface: attribute upper
-PASS IDBKeyRange interface: attribute lowerOpen
-PASS IDBKeyRange interface: attribute upperOpen
-PASS IDBKeyRange interface: operation only(any)
-PASS IDBKeyRange interface: operation lowerBound(any, boolean)
-PASS IDBKeyRange interface: operation upperBound(any, boolean)
-PASS IDBKeyRange interface: operation bound(any, any, boolean, boolean)
-PASS IDBKeyRange interface: operation includes(any)
-PASS IDBKeyRange must be primary interface of [object IDBKeyRange]
-PASS Stringification of [object IDBKeyRange]
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lower" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upper" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lowerOpen" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upperOpen" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "only(any)" with the proper type
-PASS IDBKeyRange interface: calling only(any) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lowerBound(any, boolean)" with the proper type
-PASS IDBKeyRange interface: calling lowerBound(any, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upperBound(any, boolean)" with the proper type
-PASS IDBKeyRange interface: calling upperBound(any, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "bound(any, any, boolean, boolean)" with the proper type
-PASS IDBKeyRange interface: calling bound(any, any, boolean, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "includes(any)" with the proper type
-PASS IDBKeyRange interface: calling includes(any) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBCursor interface: existence and properties of interface object
-PASS IDBCursor interface object length
-PASS IDBCursor interface object name
-PASS IDBCursor interface: existence and properties of interface prototype object
-PASS IDBCursor interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBCursor interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBCursor interface: attribute source
-PASS IDBCursor interface: attribute direction
-PASS IDBCursor interface: attribute key
-PASS IDBCursor interface: attribute primaryKey
-FAIL IDBCursor interface: attribute request assert_true: The prototype object must have a property "request" expected true got false
-PASS IDBCursor interface: operation advance(unsigned long)
-PASS IDBCursor interface: operation continue(any)
-PASS IDBCursor interface: operation continuePrimaryKey(any, any)
-PASS IDBCursor interface: operation update(any)
-PASS IDBCursor interface: operation delete()
-PASS IDBCursorWithValue interface: existence and properties of interface object
-PASS IDBCursorWithValue interface object length
-PASS IDBCursorWithValue interface object name
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBCursorWithValue interface: attribute value
-PASS IDBTransaction interface: existence and properties of interface object
-PASS IDBTransaction interface object length
-PASS IDBTransaction interface object name
-PASS IDBTransaction interface: existence and properties of interface prototype object
-PASS IDBTransaction interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBTransaction interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBTransaction interface: attribute objectStoreNames
-PASS IDBTransaction interface: attribute mode
-PASS IDBTransaction interface: attribute db
-PASS IDBTransaction interface: attribute error
-PASS IDBTransaction interface: operation objectStore(DOMString)
-PASS IDBTransaction interface: operation commit()
-PASS IDBTransaction interface: operation abort()
-PASS IDBTransaction interface: attribute onabort
-PASS IDBTransaction interface: attribute oncomplete
-PASS IDBTransaction interface: attribute onerror
-PASS Window interface: existence and properties of interface object
-PASS WorkerGlobalScope interface: attribute indexedDB
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.sharedworker-expected.txt
deleted file mode 100644
index 2dc632c..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,190 +0,0 @@
-This is a testharness.js-based test.
-Found 186 tests; 185 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS idl_test setup
-PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
-PASS IDBRequest interface: existence and properties of interface object
-PASS IDBRequest interface object length
-PASS IDBRequest interface object name
-PASS IDBRequest interface: existence and properties of interface prototype object
-PASS IDBRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBRequest interface: attribute result
-PASS IDBRequest interface: attribute error
-PASS IDBRequest interface: attribute source
-PASS IDBRequest interface: attribute transaction
-PASS IDBRequest interface: attribute readyState
-PASS IDBRequest interface: attribute onsuccess
-PASS IDBRequest interface: attribute onerror
-PASS IDBOpenDBRequest interface: existence and properties of interface object
-PASS IDBOpenDBRequest interface object length
-PASS IDBOpenDBRequest interface object name
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBOpenDBRequest interface: attribute onblocked
-PASS IDBOpenDBRequest interface: attribute onupgradeneeded
-PASS IDBVersionChangeEvent interface: existence and properties of interface object
-PASS IDBVersionChangeEvent interface object length
-PASS IDBVersionChangeEvent interface object name
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBVersionChangeEvent interface: attribute oldVersion
-PASS IDBVersionChangeEvent interface: attribute newVersion
-PASS IDBVersionChangeEvent must be primary interface of new IDBVersionChangeEvent("type")
-PASS Stringification of new IDBVersionChangeEvent("type")
-PASS IDBVersionChangeEvent interface: new IDBVersionChangeEvent("type") must inherit property "oldVersion" with the proper type
-PASS IDBVersionChangeEvent interface: new IDBVersionChangeEvent("type") must inherit property "newVersion" with the proper type
-PASS IDBFactory interface: existence and properties of interface object
-PASS IDBFactory interface object length
-PASS IDBFactory interface object name
-PASS IDBFactory interface: existence and properties of interface prototype object
-PASS IDBFactory interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBFactory interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBFactory interface: operation open(DOMString, unsigned long long)
-PASS IDBFactory interface: operation deleteDatabase(DOMString)
-PASS IDBFactory interface: operation databases()
-PASS IDBFactory interface: operation cmp(any, any)
-PASS IDBFactory must be primary interface of [object IDBFactory]
-PASS Stringification of [object IDBFactory]
-PASS IDBFactory interface: [object IDBFactory] must inherit property "open(DOMString, unsigned long long)" with the proper type
-PASS IDBFactory interface: calling open(DOMString, unsigned long long) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBFactory interface: [object IDBFactory] must inherit property "deleteDatabase(DOMString)" with the proper type
-PASS IDBFactory interface: calling deleteDatabase(DOMString) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBFactory interface: [object IDBFactory] must inherit property "databases()" with the proper type
-PASS IDBFactory interface: [object IDBFactory] must inherit property "cmp(any, any)" with the proper type
-PASS IDBFactory interface: calling cmp(any, any) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBDatabase interface: existence and properties of interface object
-PASS IDBDatabase interface object length
-PASS IDBDatabase interface object name
-PASS IDBDatabase interface: existence and properties of interface prototype object
-PASS IDBDatabase interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBDatabase interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBDatabase interface: attribute name
-PASS IDBDatabase interface: attribute version
-PASS IDBDatabase interface: attribute objectStoreNames
-PASS IDBDatabase interface: operation transaction([object Object],[object Object], IDBTransactionMode)
-PASS IDBDatabase interface: operation close()
-PASS IDBDatabase interface: operation createObjectStore(DOMString, IDBObjectStoreParameters)
-PASS IDBDatabase interface: operation deleteObjectStore(DOMString)
-PASS IDBDatabase interface: attribute onabort
-PASS IDBDatabase interface: attribute onclose
-PASS IDBDatabase interface: attribute onerror
-PASS IDBDatabase interface: attribute onversionchange
-PASS IDBObjectStore interface: existence and properties of interface object
-PASS IDBObjectStore interface object length
-PASS IDBObjectStore interface object name
-PASS IDBObjectStore interface: existence and properties of interface prototype object
-PASS IDBObjectStore interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBObjectStore interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBObjectStore interface: attribute name
-PASS IDBObjectStore interface: attribute keyPath
-PASS IDBObjectStore interface: attribute indexNames
-PASS IDBObjectStore interface: attribute transaction
-PASS IDBObjectStore interface: attribute autoIncrement
-PASS IDBObjectStore interface: operation put(any, any)
-PASS IDBObjectStore interface: operation add(any, any)
-PASS IDBObjectStore interface: operation delete(any)
-PASS IDBObjectStore interface: operation clear()
-PASS IDBObjectStore interface: operation get(any)
-PASS IDBObjectStore interface: operation getKey(any)
-PASS IDBObjectStore interface: operation getAll(any, unsigned long)
-PASS IDBObjectStore interface: operation getAllKeys(any, unsigned long)
-PASS IDBObjectStore interface: operation count(any)
-PASS IDBObjectStore interface: operation openCursor(any, IDBCursorDirection)
-PASS IDBObjectStore interface: operation openKeyCursor(any, IDBCursorDirection)
-PASS IDBObjectStore interface: operation index(DOMString)
-PASS IDBObjectStore interface: operation createIndex(DOMString, [object Object],[object Object], IDBIndexParameters)
-PASS IDBObjectStore interface: operation deleteIndex(DOMString)
-PASS IDBIndex interface: existence and properties of interface object
-PASS IDBIndex interface object length
-PASS IDBIndex interface object name
-PASS IDBIndex interface: existence and properties of interface prototype object
-PASS IDBIndex interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBIndex interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBIndex interface: attribute name
-PASS IDBIndex interface: attribute objectStore
-PASS IDBIndex interface: attribute keyPath
-PASS IDBIndex interface: attribute multiEntry
-PASS IDBIndex interface: attribute unique
-PASS IDBIndex interface: operation get(any)
-PASS IDBIndex interface: operation getKey(any)
-PASS IDBIndex interface: operation getAll(any, unsigned long)
-PASS IDBIndex interface: operation getAllKeys(any, unsigned long)
-PASS IDBIndex interface: operation count(any)
-PASS IDBIndex interface: operation openCursor(any, IDBCursorDirection)
-PASS IDBIndex interface: operation openKeyCursor(any, IDBCursorDirection)
-PASS IDBKeyRange interface: existence and properties of interface object
-PASS IDBKeyRange interface object length
-PASS IDBKeyRange interface object name
-PASS IDBKeyRange interface: existence and properties of interface prototype object
-PASS IDBKeyRange interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBKeyRange interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBKeyRange interface: attribute lower
-PASS IDBKeyRange interface: attribute upper
-PASS IDBKeyRange interface: attribute lowerOpen
-PASS IDBKeyRange interface: attribute upperOpen
-PASS IDBKeyRange interface: operation only(any)
-PASS IDBKeyRange interface: operation lowerBound(any, boolean)
-PASS IDBKeyRange interface: operation upperBound(any, boolean)
-PASS IDBKeyRange interface: operation bound(any, any, boolean, boolean)
-PASS IDBKeyRange interface: operation includes(any)
-PASS IDBKeyRange must be primary interface of [object IDBKeyRange]
-PASS Stringification of [object IDBKeyRange]
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lower" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upper" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lowerOpen" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upperOpen" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "only(any)" with the proper type
-PASS IDBKeyRange interface: calling only(any) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lowerBound(any, boolean)" with the proper type
-PASS IDBKeyRange interface: calling lowerBound(any, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upperBound(any, boolean)" with the proper type
-PASS IDBKeyRange interface: calling upperBound(any, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "bound(any, any, boolean, boolean)" with the proper type
-PASS IDBKeyRange interface: calling bound(any, any, boolean, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "includes(any)" with the proper type
-PASS IDBKeyRange interface: calling includes(any) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBCursor interface: existence and properties of interface object
-PASS IDBCursor interface object length
-PASS IDBCursor interface object name
-PASS IDBCursor interface: existence and properties of interface prototype object
-PASS IDBCursor interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBCursor interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBCursor interface: attribute source
-PASS IDBCursor interface: attribute direction
-PASS IDBCursor interface: attribute key
-PASS IDBCursor interface: attribute primaryKey
-FAIL IDBCursor interface: attribute request assert_true: The prototype object must have a property "request" expected true got false
-PASS IDBCursor interface: operation advance(unsigned long)
-PASS IDBCursor interface: operation continue(any)
-PASS IDBCursor interface: operation continuePrimaryKey(any, any)
-PASS IDBCursor interface: operation update(any)
-PASS IDBCursor interface: operation delete()
-PASS IDBCursorWithValue interface: existence and properties of interface object
-PASS IDBCursorWithValue interface object length
-PASS IDBCursorWithValue interface object name
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBCursorWithValue interface: attribute value
-PASS IDBTransaction interface: existence and properties of interface object
-PASS IDBTransaction interface object length
-PASS IDBTransaction interface object name
-PASS IDBTransaction interface: existence and properties of interface prototype object
-PASS IDBTransaction interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBTransaction interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBTransaction interface: attribute objectStoreNames
-PASS IDBTransaction interface: attribute mode
-PASS IDBTransaction interface: attribute db
-PASS IDBTransaction interface: attribute error
-PASS IDBTransaction interface: operation objectStore(DOMString)
-PASS IDBTransaction interface: operation commit()
-PASS IDBTransaction interface: operation abort()
-PASS IDBTransaction interface: attribute onabort
-PASS IDBTransaction interface: attribute oncomplete
-PASS IDBTransaction interface: attribute onerror
-PASS Window interface: existence and properties of interface object
-PASS WorkerGlobalScope interface: attribute indexedDB
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.worker-expected.txt
deleted file mode 100644
index 2dc632c..0000000
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idlharness.any.worker-expected.txt
+++ /dev/null
@@ -1,190 +0,0 @@
-This is a testharness.js-based test.
-Found 186 tests; 185 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS idl_test setup
-PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
-PASS IDBRequest interface: existence and properties of interface object
-PASS IDBRequest interface object length
-PASS IDBRequest interface object name
-PASS IDBRequest interface: existence and properties of interface prototype object
-PASS IDBRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBRequest interface: attribute result
-PASS IDBRequest interface: attribute error
-PASS IDBRequest interface: attribute source
-PASS IDBRequest interface: attribute transaction
-PASS IDBRequest interface: attribute readyState
-PASS IDBRequest interface: attribute onsuccess
-PASS IDBRequest interface: attribute onerror
-PASS IDBOpenDBRequest interface: existence and properties of interface object
-PASS IDBOpenDBRequest interface object length
-PASS IDBOpenDBRequest interface object name
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBOpenDBRequest interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBOpenDBRequest interface: attribute onblocked
-PASS IDBOpenDBRequest interface: attribute onupgradeneeded
-PASS IDBVersionChangeEvent interface: existence and properties of interface object
-PASS IDBVersionChangeEvent interface object length
-PASS IDBVersionChangeEvent interface object name
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBVersionChangeEvent interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBVersionChangeEvent interface: attribute oldVersion
-PASS IDBVersionChangeEvent interface: attribute newVersion
-PASS IDBVersionChangeEvent must be primary interface of new IDBVersionChangeEvent("type")
-PASS Stringification of new IDBVersionChangeEvent("type")
-PASS IDBVersionChangeEvent interface: new IDBVersionChangeEvent("type") must inherit property "oldVersion" with the proper type
-PASS IDBVersionChangeEvent interface: new IDBVersionChangeEvent("type") must inherit property "newVersion" with the proper type
-PASS IDBFactory interface: existence and properties of interface object
-PASS IDBFactory interface object length
-PASS IDBFactory interface object name
-PASS IDBFactory interface: existence and properties of interface prototype object
-PASS IDBFactory interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBFactory interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBFactory interface: operation open(DOMString, unsigned long long)
-PASS IDBFactory interface: operation deleteDatabase(DOMString)
-PASS IDBFactory interface: operation databases()
-PASS IDBFactory interface: operation cmp(any, any)
-PASS IDBFactory must be primary interface of [object IDBFactory]
-PASS Stringification of [object IDBFactory]
-PASS IDBFactory interface: [object IDBFactory] must inherit property "open(DOMString, unsigned long long)" with the proper type
-PASS IDBFactory interface: calling open(DOMString, unsigned long long) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBFactory interface: [object IDBFactory] must inherit property "deleteDatabase(DOMString)" with the proper type
-PASS IDBFactory interface: calling deleteDatabase(DOMString) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBFactory interface: [object IDBFactory] must inherit property "databases()" with the proper type
-PASS IDBFactory interface: [object IDBFactory] must inherit property "cmp(any, any)" with the proper type
-PASS IDBFactory interface: calling cmp(any, any) on [object IDBFactory] with too few arguments must throw TypeError
-PASS IDBDatabase interface: existence and properties of interface object
-PASS IDBDatabase interface object length
-PASS IDBDatabase interface object name
-PASS IDBDatabase interface: existence and properties of interface prototype object
-PASS IDBDatabase interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBDatabase interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBDatabase interface: attribute name
-PASS IDBDatabase interface: attribute version
-PASS IDBDatabase interface: attribute objectStoreNames
-PASS IDBDatabase interface: operation transaction([object Object],[object Object], IDBTransactionMode)
-PASS IDBDatabase interface: operation close()
-PASS IDBDatabase interface: operation createObjectStore(DOMString, IDBObjectStoreParameters)
-PASS IDBDatabase interface: operation deleteObjectStore(DOMString)
-PASS IDBDatabase interface: attribute onabort
-PASS IDBDatabase interface: attribute onclose
-PASS IDBDatabase interface: attribute onerror
-PASS IDBDatabase interface: attribute onversionchange
-PASS IDBObjectStore interface: existence and properties of interface object
-PASS IDBObjectStore interface object length
-PASS IDBObjectStore interface object name
-PASS IDBObjectStore interface: existence and properties of interface prototype object
-PASS IDBObjectStore interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBObjectStore interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBObjectStore interface: attribute name
-PASS IDBObjectStore interface: attribute keyPath
-PASS IDBObjectStore interface: attribute indexNames
-PASS IDBObjectStore interface: attribute transaction
-PASS IDBObjectStore interface: attribute autoIncrement
-PASS IDBObjectStore interface: operation put(any, any)
-PASS IDBObjectStore interface: operation add(any, any)
-PASS IDBObjectStore interface: operation delete(any)
-PASS IDBObjectStore interface: operation clear()
-PASS IDBObjectStore interface: operation get(any)
-PASS IDBObjectStore interface: operation getKey(any)
-PASS IDBObjectStore interface: operation getAll(any, unsigned long)
-PASS IDBObjectStore interface: operation getAllKeys(any, unsigned long)
-PASS IDBObjectStore interface: operation count(any)
-PASS IDBObjectStore interface: operation openCursor(any, IDBCursorDirection)
-PASS IDBObjectStore interface: operation openKeyCursor(any, IDBCursorDirection)
-PASS IDBObjectStore interface: operation index(DOMString)
-PASS IDBObjectStore interface: operation createIndex(DOMString, [object Object],[object Object], IDBIndexParameters)
-PASS IDBObjectStore interface: operation deleteIndex(DOMString)
-PASS IDBIndex interface: existence and properties of interface object
-PASS IDBIndex interface object length
-PASS IDBIndex interface object name
-PASS IDBIndex interface: existence and properties of interface prototype object
-PASS IDBIndex interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBIndex interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBIndex interface: attribute name
-PASS IDBIndex interface: attribute objectStore
-PASS IDBIndex interface: attribute keyPath
-PASS IDBIndex interface: attribute multiEntry
-PASS IDBIndex interface: attribute unique
-PASS IDBIndex interface: operation get(any)
-PASS IDBIndex interface: operation getKey(any)
-PASS IDBIndex interface: operation getAll(any, unsigned long)
-PASS IDBIndex interface: operation getAllKeys(any, unsigned long)
-PASS IDBIndex interface: operation count(any)
-PASS IDBIndex interface: operation openCursor(any, IDBCursorDirection)
-PASS IDBIndex interface: operation openKeyCursor(any, IDBCursorDirection)
-PASS IDBKeyRange interface: existence and properties of interface object
-PASS IDBKeyRange interface object length
-PASS IDBKeyRange interface object name
-PASS IDBKeyRange interface: existence and properties of interface prototype object
-PASS IDBKeyRange interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBKeyRange interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBKeyRange interface: attribute lower
-PASS IDBKeyRange interface: attribute upper
-PASS IDBKeyRange interface: attribute lowerOpen
-PASS IDBKeyRange interface: attribute upperOpen
-PASS IDBKeyRange interface: operation only(any)
-PASS IDBKeyRange interface: operation lowerBound(any, boolean)
-PASS IDBKeyRange interface: operation upperBound(any, boolean)
-PASS IDBKeyRange interface: operation bound(any, any, boolean, boolean)
-PASS IDBKeyRange interface: operation includes(any)
-PASS IDBKeyRange must be primary interface of [object IDBKeyRange]
-PASS Stringification of [object IDBKeyRange]
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lower" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upper" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lowerOpen" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upperOpen" with the proper type
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "only(any)" with the proper type
-PASS IDBKeyRange interface: calling only(any) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "lowerBound(any, boolean)" with the proper type
-PASS IDBKeyRange interface: calling lowerBound(any, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "upperBound(any, boolean)" with the proper type
-PASS IDBKeyRange interface: calling upperBound(any, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "bound(any, any, boolean, boolean)" with the proper type
-PASS IDBKeyRange interface: calling bound(any, any, boolean, boolean) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBKeyRange interface: [object IDBKeyRange] must inherit property "includes(any)" with the proper type
-PASS IDBKeyRange interface: calling includes(any) on [object IDBKeyRange] with too few arguments must throw TypeError
-PASS IDBCursor interface: existence and properties of interface object
-PASS IDBCursor interface object length
-PASS IDBCursor interface object name
-PASS IDBCursor interface: existence and properties of interface prototype object
-PASS IDBCursor interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBCursor interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBCursor interface: attribute source
-PASS IDBCursor interface: attribute direction
-PASS IDBCursor interface: attribute key
-PASS IDBCursor interface: attribute primaryKey
-FAIL IDBCursor interface: attribute request assert_true: The prototype object must have a property "request" expected true got false
-PASS IDBCursor interface: operation advance(unsigned long)
-PASS IDBCursor interface: operation continue(any)
-PASS IDBCursor interface: operation continuePrimaryKey(any, any)
-PASS IDBCursor interface: operation update(any)
-PASS IDBCursor interface: operation delete()
-PASS IDBCursorWithValue interface: existence and properties of interface object
-PASS IDBCursorWithValue interface object length
-PASS IDBCursorWithValue interface object name
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBCursorWithValue interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBCursorWithValue interface: attribute value
-PASS IDBTransaction interface: existence and properties of interface object
-PASS IDBTransaction interface object length
-PASS IDBTransaction interface object name
-PASS IDBTransaction interface: existence and properties of interface prototype object
-PASS IDBTransaction interface: existence and properties of interface prototype object's "constructor" property
-PASS IDBTransaction interface: existence and properties of interface prototype object's @@unscopables property
-PASS IDBTransaction interface: attribute objectStoreNames
-PASS IDBTransaction interface: attribute mode
-PASS IDBTransaction interface: attribute db
-PASS IDBTransaction interface: attribute error
-PASS IDBTransaction interface: operation objectStore(DOMString)
-PASS IDBTransaction interface: operation commit()
-PASS IDBTransaction interface: operation abort()
-PASS IDBTransaction interface: attribute onabort
-PASS IDBTransaction interface: attribute oncomplete
-PASS IDBTransaction interface: attribute onerror
-PASS Window interface: existence and properties of interface object
-PASS WorkerGlobalScope interface: attribute indexedDB
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/inactive-timeline.https.html b/third_party/blink/web_tests/external/wpt/animation-worklet/inactive-timeline.https.html
index c2311e6..874e709 100644
--- a/third_party/blink/web_tests/external/wpt/animation-worklet/inactive-timeline.https.html
+++ b/third_party/blink/web_tests/external/wpt/animation-worklet/inactive-timeline.https.html
@@ -35,20 +35,21 @@
     scrollSource: createScroller(test),
     timeRange: 1000
   });
-  const DURATION = 10000; // ms
+  const DURATION = 1000; // ms
   const KEYFRAMES = { transform: ['translateY(100px)', 'translateY(200px)'] };
-  return new WorkletAnimation('passthrough', new KeyframeEffect(createDiv(test),
+  return new WorkletAnimation('passthrough_except_nan', new KeyframeEffect(createDiv(test),
         KEYFRAMES, DURATION), timeline);
 }
 
 setup(setupAndRegisterTests, {explicit_done: true});
 
 function setupAndRegisterTests() {
-  registerPassthroughAnimator().then(() => {
+  registerPassthroughExceptNaNAnimator().then(() => {
 
     promise_test(async t => {
       const animation = createScrollLinkedWorkletAnimation(t);
       const scroller = animation.timeline.scrollSource;
+
       const maxScroll = scroller.scrollHeight - scroller.clientHeight;
       const timeRange = animation.timeline.timeRange;
       scroller.scrollTop = 0.2 * maxScroll;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/auto-margins-002.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/auto-margins-002.html
new file mode 100644
index 0000000..454bc92
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/auto-margins-002.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>css-flexbox: Tests that we correctly align an image with auto margins and max-height</title>
+<link rel="author" title="Google LLC" href="https://www.google.com/">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#auto-margins" title="8.1. Aligning with 'auto' margins">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<!-- we position this div on top of the flexbox to cover up the red where
+     we expect it to be; letting the red in the wrong places shine through -->
+<div style="position: absolute; height: 100px; width: 100px; z-index: 1;">
+  <div style="height: 25px; background: green;"></div>
+  <div style="height: 50px; background: transparent;"></div>
+  <div style="height: 25px; background: green;"></div>
+</div>
+<div style="width: 100px; height: 100px; background: red; display: flex;">
+  <img src="support/300x150-green.png" style="margin: auto; max-width: 100%; max-height: 100px;">
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/300x150-green.png b/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/300x150-green.png
new file mode 100644
index 0000000..57ece824
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/300x150-green.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-computed.html b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-computed.html
new file mode 100644
index 0000000..712cad57
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-computed.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Shapes Module Level 1: getComputedValue().shapeOutside</title>
+<link rel="help" href="https://drafts.csswg.org/css-shapes/#clip-path-property">
+<meta name="assert" content="clip-path computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<style>
+  #target {
+    font-size: 40px;
+  }
+</style>
+<div id="target"></div>
+<script>
+test_computed_value("clip-path", "circle(calc(10px + 0.5em) at -50% 50%)", "circle(30px at -50% 50%)");
+test_computed_value("clip-path", "circle(calc(10px - 0.5em) at 50% -50%)", "circle(0px at 50% -50%)");
+test_computed_value("clip-path", "ellipse(at 50% 50%)");
+test_computed_value("clip-path", "ellipse(60% closest-side at 50% 50%)");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-invalid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-invalid-expected.txt
deleted file mode 100644
index bafc8294..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-invalid-expected.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-This is a testharness.js-based test.
-PASS e.style['clip-path'] = "auto" should not set the property value
-PASS e.style['clip-path'] = "ray(0deg)" should not set the property value
-PASS e.style['clip-path'] = "inset()" should not set the property value
-PASS e.style['clip-path'] = "inset(123)" should not set the property value
-PASS e.style['clip-path'] = "inset(1% 2% 3% 4% 5%)" should not set the property value
-PASS e.style['clip-path'] = "inset(round 0)" should not set the property value
-PASS e.style['clip-path'] = "inset(0px round)" should not set the property value
-PASS e.style['clip-path'] = "inset(0px round 123)" should not set the property value
-PASS e.style['clip-path'] = "inset(0px round 1% 2% 3% 4% 5%)" should not set the property value
-PASS e.style['clip-path'] = "inset(0px round / 1px)" should not set the property value
-PASS e.style['clip-path'] = "inset(10px round -20px)" should not set the property value
-PASS e.style['clip-path'] = "inset(30% round -40%)" should not set the property value
-PASS e.style['clip-path'] = "circle(123)" should not set the property value
-PASS e.style['clip-path'] = "circle(at)" should not set the property value
-PASS e.style['clip-path'] = "circle(10% 20%)" should not set the property value
-PASS e.style['clip-path'] = "circle(-10px at 20px 30px)" should not set the property value
-PASS e.style['clip-path'] = "circle(-10% at 20% 30%)" should not set the property value
-PASS e.style['clip-path'] = "circle(1% 2% at 0% 100%)" should not set the property value
-PASS e.style['clip-path'] = "ellipse(farthest-side at)" should not set the property value
-PASS e.style['clip-path'] = "ellipse(1% 2% top right)" should not set the property value
-FAIL e.style['clip-path'] = "ellipse(3% at 100% 0%)" should not set the property value assert_equals: expected "" but got "ellipse(3% at 100% 0%)"
-PASS e.style['clip-path'] = "ellipse(10% -20% at 30% 40%)" should not set the property value
-PASS e.style['clip-path'] = "ellipse(-50px 60px at 70% 80%)" should not set the property value
-PASS e.style['clip-path'] = "polygon(1%)" should not set the property value
-PASS e.style['clip-path'] = "unknown-box" should not set the property value
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-invalid.html
index 2672d48..129d403e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-invalid.html
@@ -35,7 +35,10 @@
 
 test_invalid_value("clip-path", "ellipse(farthest-side at)");
 test_invalid_value("clip-path", "ellipse(1% 2% top right)");
+test_invalid_value("clip-path", "ellipse(3%)");
 test_invalid_value("clip-path", "ellipse(3% at 100% 0%)");
+test_invalid_value("clip-path", "ellipse(closest-side)");
+test_invalid_value("clip-path", "ellipse(farthest-side at 100% 0%)");
 test_invalid_value("clip-path", "ellipse(10% -20% at 30% 40%)");
 test_invalid_value("clip-path", "ellipse(-50px 60px at 70% 80%)");
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
index 3b1e58479..b2b3782 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
@@ -18,6 +18,7 @@
 PASS e.style['clip-path'] = "ellipse()" should set the property value
 PASS e.style['clip-path'] = "ellipse(1px closest-side)" should set the property value
 PASS e.style['clip-path'] = "ellipse(at 10% 20%)" should set the property value
+PASS e.style['clip-path'] = "ellipse(closest-side closest-side at 10% 20%)" should set the property value
 PASS e.style['clip-path'] = "ellipse(farthest-side 4% at bottom left)" should set the property value
 PASS e.style['clip-path'] = "polygon(1% 2%)" should set the property value
 PASS e.style['clip-path'] = "polygon(nonzero, 1px 2px, 3em 4em)" should set the property value
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid.html b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid.html
index 83c76fb..e734b90 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid.html
@@ -33,8 +33,9 @@
 test_valid_value("clip-path", "circle(4% at top right)", "circle(4% at 100% 0%)");
 
 test_valid_value("clip-path", "ellipse()", "ellipse(at 50% 50%)");
-test_valid_value("clip-path", "ellipse(1px closest-side)", "ellipse(1px at 50% 50%)");
+test_valid_value("clip-path", "ellipse(1px closest-side)", "ellipse(1px closest-side at 50% 50%)");
 test_valid_value("clip-path", "ellipse(at 10% 20%)");
+test_valid_value("clip-path", "ellipse(closest-side closest-side at 10% 20%)", "ellipse(at 10% 20%)");
 test_valid_value("clip-path", "ellipse(farthest-side 4% at bottom left)", "ellipse(farthest-side 4% at 0% 100%)");
 
 test_valid_value("clip-path", "polygon(1% 2%)");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-computed.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-computed.html
index 2be31ce..fb86b66 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-computed.html
@@ -19,6 +19,7 @@
 <script>
 test_computed_value("shape-outside", "circle(calc(10px + 0.5em) at -50% 50%) border-box", "circle(30px at -50% 50%) border-box");
 test_computed_value("shape-outside", "circle(calc(10px - 0.5em) at 50% -50%) border-box", "circle(0px at 50% -50%) border-box");
+test_computed_value("shape-outside", "ellipse(60% closest-side at 50% 50%)");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid-expected.txt
deleted file mode 100644
index 0d52e47..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid-expected.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-This is a testharness.js-based test.
-PASS e.style['shape-outside'] = "auto" should not set the property value
-PASS e.style['shape-outside'] = "ray(0deg)" should not set the property value
-PASS e.style['shape-outside'] = "inset()" should not set the property value
-PASS e.style['shape-outside'] = "inset(123)" should not set the property value
-PASS e.style['shape-outside'] = "inset(1% 2% 3% 4% 5%)" should not set the property value
-PASS e.style['shape-outside'] = "inset(round 0)" should not set the property value
-PASS e.style['shape-outside'] = "inset(0px round)" should not set the property value
-PASS e.style['shape-outside'] = "inset(0px round 123)" should not set the property value
-PASS e.style['shape-outside'] = "inset(0px round 1% 2% 3% 4% 5%)" should not set the property value
-PASS e.style['shape-outside'] = "inset(0px round / 1px)" should not set the property value
-PASS e.style['shape-outside'] = "inset(10px round -20px)" should not set the property value
-PASS e.style['shape-outside'] = "inset(30% round -40%)" should not set the property value
-PASS e.style['shape-outside'] = "circle(123)" should not set the property value
-PASS e.style['shape-outside'] = "circle(at)" should not set the property value
-PASS e.style['shape-outside'] = "circle(10% 20%)" should not set the property value
-PASS e.style['shape-outside'] = "circle(-10px at 20px 30px)" should not set the property value
-PASS e.style['shape-outside'] = "circle(-10% at 20% 30%)" should not set the property value
-PASS e.style['shape-outside'] = "circle(1% 2% at 0% 100%)" should not set the property value
-PASS e.style['shape-outside'] = "ellipse(farthest-side at)" should not set the property value
-PASS e.style['shape-outside'] = "ellipse(1% 2% top right)" should not set the property value
-FAIL e.style['shape-outside'] = "ellipse(3%)" should not set the property value assert_equals: expected "" but got "ellipse(3% at 50% 50%)"
-FAIL e.style['shape-outside'] = "ellipse(3% at 100% 0%)" should not set the property value assert_equals: expected "" but got "ellipse(3% at 100% 0%)"
-PASS e.style['shape-outside'] = "ellipse(10% -20% at 30% 40%)" should not set the property value
-PASS e.style['shape-outside'] = "ellipse(-50px 60px at 70% 80%)" should not set the property value
-PASS e.style['shape-outside'] = "polygon(1%)" should not set the property value
-PASS e.style['shape-outside'] = "fill-box" should not set the property value
-PASS e.style['shape-outside'] = "stroke-box" should not set the property value
-PASS e.style['shape-outside'] = "view-box" should not set the property value
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid.html
index 484bafe..366fa92 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid.html
@@ -37,6 +37,8 @@
 test_invalid_value("shape-outside", "ellipse(1% 2% top right)");
 test_invalid_value("shape-outside", "ellipse(3%)");
 test_invalid_value("shape-outside", "ellipse(3% at 100% 0%)");
+test_invalid_value("shape-outside", "ellipse(closest-side)");
+test_invalid_value("shape-outside", "ellipse(farthest-side at 100% 0%)");
 test_invalid_value("shape-outside", "ellipse(10% -20% at 30% 40%)");
 test_invalid_value("shape-outside", "ellipse(-50px 60px at 70% 80%)");
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid-expected.txt
index 15065eae0..ff80dc81 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid-expected.txt
@@ -18,6 +18,8 @@
 PASS e.style['shape-outside'] = "ellipse()" should set the property value
 PASS e.style['shape-outside'] = "ellipse(3% 2%)" should set the property value
 PASS e.style['shape-outside'] = "ellipse(closest-side 1px)" should set the property value
+PASS e.style['shape-outside'] = "ellipse(10% closest-side)" should set the property value
+PASS e.style['shape-outside'] = "ellipse(closest-side closest-side at 60% 70%)" should set the property value
 PASS e.style['shape-outside'] = "ellipse(at 10% 20%)" should set the property value
 PASS e.style['shape-outside'] = "ellipse(farthest-side 4% at bottom left)" should set the property value
 PASS e.style['shape-outside'] = "polygon(1% 2%)" should set the property value
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid.html
index d52eb9a..43e715d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid.html
@@ -35,6 +35,8 @@
 test_valid_value("shape-outside", "ellipse()", "ellipse(at 50% 50%)");
 test_valid_value("shape-outside", "ellipse(3% 2%)", "ellipse(3% 2% at 50% 50%)");
 test_valid_value("shape-outside", "ellipse(closest-side 1px)", "ellipse(closest-side 1px at 50% 50%)");
+test_valid_value("shape-outside", "ellipse(10% closest-side)", "ellipse(10% closest-side at 50% 50%)");
+test_valid_value("shape-outside", "ellipse(closest-side closest-side at 60% 70%)", "ellipse(at 60% 70%)");
 test_valid_value("shape-outside", "ellipse(at 10% 20%)");
 test_valid_value("shape-outside", "ellipse(farthest-side 4% at bottom left)", "ellipse(farthest-side 4% at 0% 100%)");
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010-expected.txt
index d2bcdb9..b7f5a6c7 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010-expected.txt
@@ -1,11 +1,4 @@
 This is a testharness.js-based test.
-PASS ellipse(calc(10in)) - inline style
-PASS ellipse(calc(10in + 20px)) - inline style
-PASS ellipse(calc(30%)) - inline style
-PASS ellipse(calc(100%/4)) - inline style
-PASS ellipse(calc(25%*3)) - inline style
-PASS ellipse(calc(25%*3 - 10in)) - inline style
-PASS ellipse(calc((12.5%*6 + 10in) / 4)) - inline style
 PASS ellipse(farthest-side calc(10in)) - inline style
 PASS ellipse(farthest-side calc(10in + 20px)) - inline style
 PASS ellipse(farthest-side calc(30%)) - inline style
@@ -20,13 +13,6 @@
 PASS ellipse(calc(25%*3) calc(25%*3)) - inline style
 PASS ellipse(calc(25%*3 - 10in) calc(25%*3 - 10in)) - inline style
 PASS ellipse(calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - inline style
-PASS ellipse(calc(10in)) - computed style
-PASS ellipse(calc(10in + 20px)) - computed style
-PASS ellipse(calc(30%)) - computed style
-PASS ellipse(calc(100%/4)) - computed style
-PASS ellipse(calc(25%*3)) - computed style
-FAIL ellipse(calc(25%*3 - 10in)) - computed style assert_in_array: value "ellipse(calc(75% + -960px) at 50% 50%)" not in array ["ellipse(calc(75% - 960px) at 50% 50%)", "ellipse(calc(-960px + 75%) at 50% 50%)"]
-PASS ellipse(calc((12.5%*6 + 10in) / 4)) - computed style
 PASS ellipse(farthest-side calc(10in)) - computed style
 PASS ellipse(farthest-side calc(10in + 20px)) - computed style
 PASS ellipse(farthest-side calc(30%)) - computed style
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010.html
index 19f80c2..e5673b07 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010.html
@@ -20,19 +20,6 @@
             var ellipse_calc_tests = [];
             var defaultPosition = ' at 50% 50%';
             ParsingUtils.calcTestValues.forEach(function(value) {
-                testCase = ['ellipse('+ value[0] +')',
-                            'ellipse('+ value[1] + defaultPosition +')'];
-                if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
-                    testCase.push([
-                                    'ellipse('+ value[2][0]  + defaultPosition +')',
-                                    'ellipse('+ value[2][1]  + defaultPosition +')',
-                                  ]);
-                } else {
-                    testCase.push('ellipse('+ value[2] + defaultPosition +')');
-                }
-                ellipse_calc_tests.push(testCase);
-            });
-            ParsingUtils.calcTestValues.forEach(function(value) {
                 testCase = ['ellipse(farthest-side '+ value[0] +')',
                             'ellipse(farthest-side '+ value[1] + defaultPosition +')'];
                 if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011-expected.txt
index ebe434e..9bb0068 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011-expected.txt
@@ -6,13 +6,6 @@
 PASS ellipse(at calc(25%*3) 50%) - inline style
 PASS ellipse(at calc(25%*3 - 10in) 50%) - inline style
 PASS ellipse(at calc((12.5%*6 + 10in) / 4) 50%) - inline style
-PASS ellipse(farthest-side at calc(10in) 50%) - inline style
-PASS ellipse(farthest-side at calc(10in + 20px) 50%) - inline style
-PASS ellipse(farthest-side at calc(30%) 50%) - inline style
-PASS ellipse(farthest-side at calc(100%/4) 50%) - inline style
-PASS ellipse(farthest-side at calc(25%*3) 50%) - inline style
-PASS ellipse(farthest-side at calc(25%*3 - 10in) 50%) - inline style
-PASS ellipse(farthest-side at calc((12.5%*6 + 10in) / 4) 50%) - inline style
 PASS ellipse(closest-side farthest-side at calc(10in) calc(10in)) - inline style
 PASS ellipse(closest-side farthest-side at calc(10in + 20px) calc(10in + 20px)) - inline style
 PASS ellipse(closest-side farthest-side at calc(30%) calc(30%)) - inline style
@@ -27,13 +20,6 @@
 PASS ellipse(at calc(25%*3) 50%) - computed style
 FAIL ellipse(at calc(25%*3 - 10in) 50%) - computed style assert_in_array: value "ellipse(at calc(75% + -960px) 50%)" not in array ["ellipse(at calc(75% - 960px) 50%)", "ellipse(at calc(-960px + 75%) 50%)"]
 PASS ellipse(at calc((12.5%*6 + 10in) / 4) 50%) - computed style
-PASS ellipse(farthest-side at calc(10in) 50%) - computed style
-PASS ellipse(farthest-side at calc(10in + 20px) 50%) - computed style
-PASS ellipse(farthest-side at calc(30%) 50%) - computed style
-PASS ellipse(farthest-side at calc(100%/4) 50%) - computed style
-PASS ellipse(farthest-side at calc(25%*3) 50%) - computed style
-FAIL ellipse(farthest-side at calc(25%*3 - 10in) 50%) - computed style assert_in_array: value "ellipse(farthest-side at calc(75% + -960px) 50%)" not in array ["ellipse(farthest-side at calc(75% - 960px) 50%)", "ellipse(farthest-side at calc(-960px + 75%) 50%)"]
-PASS ellipse(farthest-side at calc((12.5%*6 + 10in) / 4) 50%) - computed style
 PASS ellipse(closest-side farthest-side at calc(10in) calc(10in)) - computed style
 PASS ellipse(closest-side farthest-side at calc(10in + 20px) calc(10in + 20px)) - computed style
 PASS ellipse(closest-side farthest-side at calc(30%) calc(30%)) - computed style
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011.html
index 983ff7b..ad01bb6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011.html
@@ -32,19 +32,6 @@
                 ellipse_position_calc_tests.push(testCase);
             });
             ParsingUtils.calcTestValues.forEach(function(value) {
-                testCase = ['ellipse(farthest-side at '+ value[0] +' 50%)',
-                            'ellipse(farthest-side at '+ value[1] +' 50%)'];
-                if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
-                    testCase.push([
-                                    'ellipse(farthest-side at '+ value[2][0] +' 50%)',
-                                    'ellipse(farthest-side at '+ value[2][1] +' 50%)'
-                                  ]);
-                } else {
-                    testCase.push('ellipse(farthest-side at '+ value[2] +' 50%)');
-                }
-                ellipse_position_calc_tests.push(testCase);
-            });
-            ParsingUtils.calcTestValues.forEach(function(value) {
                 testCase = ['ellipse(closest-side farthest-side at '+ value[0] +' '+ value[0] +')',
                             'ellipse(closest-side farthest-side at '+ value[1] +' '+ value[1] +')'];
                 if(Object.prototype.toString.call( value[2] ) === '[object Array]' && value[2].length == 2) {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/support/parsing-utils.js b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/support/parsing-utils.js
index 81bcf7d..118a1145 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/support/parsing-utils.js
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/support/parsing-utils.js
@@ -735,17 +735,13 @@
 ]
 var validEllipseRadii = [
     ['', 'at 50% 50%', 'at 50% 50%'],
-    ['50u1', '50u1 at 50% 50%', '50u1 at 50% 50%'],
-    ['50%', '50% at 50% 50%', '50% at 50% 50%'],
-    ['closest-side', 'at 50% 50%', 'at 50% 50%'],
-    ['farthest-side', 'farthest-side at 50% 50%', 'farthest-side at 50% 50%'],
     ['50u1 100u1', '50u1 100u1 at 50% 50%'],
     ['100u1 100px', '100u1 100px at 50% 50%'],
     ['25% 50%', '25% 50% at 50% 50%'],
     ['50u1 25%', '50u1 25% at 50% 50%'],
     ['25% 50u1', '25% 50u1 at 50% 50%'],
-    ['25% closest-side', '25% at 50% 50%'],
-    ['25u1 closest-side', '25u1 at 50% 50%'],
+    ['25% closest-side', '25% closest-side at 50% 50%'],
+    ['25u1 closest-side', '25u1 closest-side at 50% 50%'],
     ['closest-side 75%', 'closest-side 75% at 50% 50%'],
     ['closest-side 75u1', 'closest-side 75u1 at 50% 50%'],
     ['25% farthest-side', '25% farthest-side at 50% 50%'],
@@ -755,7 +751,7 @@
     ['closest-side closest-side', 'at 50% 50%'],
     ['farthest-side farthest-side', 'farthest-side farthest-side at 50% 50%'],
     ['closest-side farthest-side', 'closest-side farthest-side at 50% 50%'],
-    ['farthest-side closest-side', 'farthest-side at 50% 50%']
+    ['farthest-side closest-side', 'farthest-side closest-side at 50% 50%']
 ]
 
 var validInsets = [
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/resources/event-timing-support.js b/third_party/blink/web_tests/external/wpt/event-timing/resources/event-timing-support.js
index 1f3d9f7..f6e450d 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/resources/event-timing-support.js
+++ b/third_party/blink/web_tests/external/wpt/event-timing/resources/event-timing-support.js
@@ -8,7 +8,7 @@
   const yCenter = rect.y + rect.height / 2;
   const leftButton = 0;
   const clickHandler = () => {
-    mainThreadBusy(60);
+    mainThreadBusy(120);
     if (callback)
       callback();
     element.removeEventListener("mousedown", clickHandler);
@@ -29,8 +29,8 @@
   assert_true(entry.cancelable);
   assert_equals(entry.name, 'mousedown');
   assert_equals(entry.entryType, 'event');
-  assert_greater_than(entry.duration, 50,
-      "The entry's duration should be greater than 50ms.");
+  assert_greater_than_equal(entry.duration, 104,
+      "The entry's duration should be greater than or equal to 104 ms.");
   assert_greater_than(entry.processingStart, entry.startTime,
       "The entry's processingStart should be greater than startTime.");
   assert_greater_than_equal(entry.processingEnd, entry.processingStart,
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/noopener-noreferrer-sizing.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/noopener-noreferrer-sizing.window.js
new file mode 100644
index 0000000..cc53ba5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/noopener-noreferrer-sizing.window.js
@@ -0,0 +1,17 @@
+const windowProps = ["innerWidth", "innerHeight"];
+
+["noopener", "noreferrer"].forEach(openerStyle => {
+  async_test(t => {
+    const channelName = "34342" + openerStyle + "8907";
+    const channel = new BroadcastChannel(channelName);
+    window.open("support/sizing-target.html?" + channelName, "", openerStyle);
+    channel.onmessage = t.step_func_done(e => {
+      // Send message first so if asserts throw the popup is still closed
+      channel.postMessage(null);
+
+      for(const prop of windowProps) {
+        assert_equals(window[prop], e.data[prop]);
+      }
+    });
+  }, `window.open() with ${openerStyle} should have equal viewport width and height`);
+});
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/sizing-target.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/sizing-target.html
new file mode 100644
index 0000000..7cd5348a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/support/sizing-target.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script>
+  const windowProps = ["innerWidth", "innerHeight"];
+  const windowPropsObj = {};
+  const channelName = location.search.substr(1);
+  const channel = new BroadcastChannel(channelName);
+  for (const prop of windowProps) {
+    windowPropsObj[prop] = window[prop];
+  }
+  channel.postMessage(windowPropsObj);
+
+  // Because messages are not delivered synchronously and because closing a
+  // browsing context prompts the eventual clearing of all task sources, this
+  // document should not be closed until the opener document has confirmed
+  // receipt.
+  channel.onmessage = () => { window.close() };
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/elements-embedded.js b/third_party/blink/web_tests/external/wpt/html/dom/elements-embedded.js
index af6c79e7..27b5b61 100644
--- a/third_party/blink/web_tests/external/wpt/html/dom/elements-embedded.js
+++ b/third_party/blink/web_tests/external/wpt/html/dom/elements-embedded.js
@@ -59,7 +59,6 @@
     // Conforming
     data: "url",
     type: "string",
-    typeMustMatch: "boolean",
     name: "string",
     useMap: "string",
     width: "string",
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/reflection-embedded-expected.txt b/third_party/blink/web_tests/external/wpt/html/dom/reflection-embedded-expected.txt
index edf5ad2a..41ca1ef3 100644
--- a/third_party/blink/web_tests/external/wpt/html/dom/reflection-embedded-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/dom/reflection-embedded-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 7118 tests; 6989 PASS, 129 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 7085 tests; 6988 PASS, 97 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS picture.title: 32 tests
 PASS picture.lang: 32 tests
 PASS picture.dir: 62 tests
@@ -185,39 +185,6 @@
 PASS object.tabIndex: 24 tests
 PASS object.data: 38 tests
 PASS object.type: 32 tests
-FAIL object.typeMustMatch: typeof IDL attribute assert_equals: expected "boolean" but got "undefined"
-FAIL object.typeMustMatch: IDL get with DOM attribute unset assert_equals: expected (boolean) false but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to "" assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to " foo " assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to undefined assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to null assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to 7 assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to 1.5 assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to true assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to false assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to object "[object Object]" assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to NaN assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to Infinity assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to -Infinity assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to "\0" assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to object "test-toString" assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to object "test-valueOf" assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: setAttribute() to "typeMustMatch" assert_equals: IDL get expected (boolean) true but got (undefined) undefined
-FAIL object.typeMustMatch: IDL set to "" assert_equals: hasAttribute() expected false but got true
-FAIL object.typeMustMatch: IDL set to " foo " assert_equals: IDL get expected (boolean) true but got (string) " foo "
-FAIL object.typeMustMatch: IDL set to undefined assert_equals: hasAttribute() expected false but got true
-FAIL object.typeMustMatch: IDL set to null assert_equals: hasAttribute() expected false but got true
-FAIL object.typeMustMatch: IDL set to 7 assert_equals: IDL get expected (boolean) true but got (number) 7
-FAIL object.typeMustMatch: IDL set to 1.5 assert_equals: IDL get expected (boolean) true but got (number) 1.5
-PASS object.typeMustMatch: IDL set to true
-FAIL object.typeMustMatch: IDL set to false assert_equals: hasAttribute() expected false but got true
-FAIL object.typeMustMatch: IDL set to object "[object Object]" assert_equals: IDL get expected (boolean) true but got (object) object "[object Object]"
-FAIL object.typeMustMatch: IDL set to NaN assert_equals: hasAttribute() expected false but got true
-FAIL object.typeMustMatch: IDL set to Infinity assert_equals: IDL get expected (boolean) true but got (number) Infinity
-FAIL object.typeMustMatch: IDL set to -Infinity assert_equals: IDL get expected (boolean) true but got (number) -Infinity
-FAIL object.typeMustMatch: IDL set to "\0" assert_equals: IDL get expected (boolean) true but got (string) "\0"
-FAIL object.typeMustMatch: IDL set to object "test-toString" assert_equals: IDL get expected (boolean) true but got (object) object "test-toString"
-FAIL object.typeMustMatch: IDL set to object "test-valueOf" assert_equals: IDL get expected (boolean) true but got (object) object "test-valueOf"
 PASS object.name: 32 tests
 PASS object.useMap: 32 tests
 PASS object.width: 32 tests
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/historical.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/historical.html
index 0fba470..2f293d3 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/historical.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/historical.html
@@ -12,4 +12,22 @@
     elm();
   });
 }, 'object legacycaller should not be supported');
+
+test(() => {
+  const obj = document.createElement("object");
+  assert_false("typeMustMatch" in obj);
+}, "object's typeMustMatch IDL attribute should not be supported");
+
+async_test(t => {
+  const obj = document.createElement("object");
+  t.add_cleanup(() => obj.remove());
+  obj.setAttribute("data", "/common/blank.html");
+  obj.setAttribute("type", "text/plain");
+  obj.setAttribute("typemustmatch", "");
+  obj.onload = t.step_func_done(() => {
+    assert_not_equals(obj.contentDocument, null, "/common/blank.html should be loaded");
+  });
+  obj.onerror = t.unreached_func();
+  document.body.appendChild(obj);
+}, "object's typemustmatch content attribute should not be supported");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback.html
deleted file mode 100644
index d5469a3e..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>HTML Test: display fallback content</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-
-var t1 = async_test("the typemustmatch attribute is specified");
-var t2 = async_test("the typemustmatch attribute is not specified");
-
-</script>
-<body onload="t1.done(); t2.done()">
-<object id="obj"></object>
-<div id="log"></div>
-<script>
-
-t1.step(function() {
-  var obj1 = document.createElement("object");
-  obj1.setAttribute("data", "/images/blue.png");
-  obj1.setAttribute("type", "text/plain");
-  obj1.setAttribute("typemustmatch", "");
-  obj1.onload = t1.step_func(function () {
-    assert_true("typeMustMatch" in obj1, "typeMustMatch is not supported.");
-    assert_unreached("The image of the first object should not be loaded.");
-  });
-  document.getElementById("obj").appendChild(obj1);
-});
-
-t2.step(function () {
-  var obj2 = document.createElement("object");
-  obj2.setAttribute("data", "test2.html");
-  obj2.setAttribute("type", "text/plain");
-  obj2.onload = t2.step_func( function () {
-    assert_not_equals(obj2.contentDocument, null, "The test2.html should be loaded.");
-  });
-  document.getElementById("obj").appendChild(obj2);
-});
-
-</script>
-</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/test2.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/test2.html
deleted file mode 100644
index e5061ea..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/test2.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>HTML Test: object - fallback</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
diff --git a/third_party/blink/web_tests/external/wpt/html/user-activation/no-activation-thru-escape-key-manual.html b/third_party/blink/web_tests/external/wpt/html/user-activation/no-activation-thru-escape-key-manual.html
new file mode 100644
index 0000000..4f03195f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/user-activation/no-activation-thru-escape-key-manual.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>No user activation through 'Escape' key</title>
+    <meta name="timeout" content="long">
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+    <link rel="author" title="Google" href="http://www.google.com "/>
+    <link rel="help" href="https://html.spec.whatwg.org/#triggered-by-user-activation">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <style>
+      #target {
+        width: 40ex;
+        background-color: yellow;
+      }
+    </style>
+    <script type="text/javascript">
+      let keydown_event_fired = false;
+
+      function run() {
+        let textbox_elem = document.getElementById("target");
+        let test_esc_key = async_test("'Escape' key doesn't activate a page.");
+
+        test_esc_key.step(() => {
+          assert_true(!!navigator.userActivation, "This test requires user activation query API");
+        });
+
+        textbox_elem.focus();
+
+        on_event(textbox_elem, "keydown", () => {
+          test_esc_key.step(() => {
+            keydown_event_fired = true;
+            assert_false(navigator.userActivation.isActive, "No user activation on keydown");
+          });
+        });
+
+        on_event(textbox_elem, "keyup", () => {
+          test_esc_key.step(() => {
+            assert_true(keydown_event_fired, "keydown event fired before keyup");
+            assert_false(navigator.userActivation.isActive, "No user activation on keyup");
+          });
+          test_esc_key.done();
+        });
+      }
+    </script>
+  </head>
+  <body onload="run()">
+    <h1>No user activation through 'Escape' key</h1>
+    <h4>Tests that pressing/releasing 'Escape' key is not treated as a user activation.</h4>
+    <input id="target" value="Press and release the 'Esc' key." />
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/fully_active_document.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/fully_active_document.window-expected.txt
new file mode 100644
index 0000000..771e58e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/fully_active_document.window-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Tasks for documents that are not fully active are stored, and run when the documents becomes fully-active assert_equals: expected (string) "true" but got (object) null
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/fully_active_document.window.js b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/fully_active_document.window.js
new file mode 100644
index 0000000..950a8a2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/fully_active_document.window.js
@@ -0,0 +1,29 @@
+async_test(t => {
+  const frame = document.body.appendChild(document.createElement("iframe"));
+  t.add_cleanup(() => frame.remove());
+
+  frame.onload = t.step_func(() => {
+    // Right now the doc of the iframe inside "frame" is still "fully-active".
+    // Navigate parent away, making the child iframe's doc "active", not "fully-active".
+    frame.contentWindow.location = "/common/blank.html";
+
+    frame.onload = t.step_func(() => {
+      // The child iframe's doc is "active", not "fully-active", and should not receive the storage notification.
+      sessionStorage.setItem('myCat', 'Tom');
+      t.step_timeout(() => {
+        // The child iframe's hasn't received the storage notification.
+        assert_equals(sessionStorage.getItem("Received storage event"), null);
+        frame.contentWindow.history.go(-1);
+        t.step_timeout(() => {
+          // Now The child iframe's doc is "fully-active" again,
+          // the previously not run storage task should now have been run.
+          assert_equals(sessionStorage.getItem("Received storage event"), "true");
+          t.done();
+        }, 1000);
+      }, 1000);
+    });
+  });
+
+  frame.src = "resources/page-with-frame.html";
+}, "Tasks for documents that are not fully active are stored, and run when the documents becomes fully-active");
+
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/resources/iframe.html b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/resources/iframe.html
new file mode 100644
index 0000000..32e48623
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/resources/iframe.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>Childframe</title>
+<script>
+  window.addEventListener('storage', () => {
+    sessionStorage.setItem("Received storage event", true);
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/resources/page-with-frame.html b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/resources/page-with-frame.html
new file mode 100644
index 0000000..f131705
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/resources/page-with-frame.html
@@ -0,0 +1 @@
+<iframe src="iframe.html"></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.window.js b/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.window.js
index cc844423..bc5cfd1 100644
--- a/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.window.js
@@ -44,6 +44,66 @@
 }, 'write() called with an invalid offset');
 
 promise_test(async t => {
+  const handle = await createEmptyFile(t, 'empty_string');
+  const writer = await handle.createWriter();
+
+  await writer.write(0, '');
+  assert_equals(await getFileContents(handle), '');
+  assert_equals(await getFileSize(handle), 0);
+}, 'write() with an empty string to an empty file');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'valid_utf8_string');
+  const writer = await handle.createWriter();
+
+  await writer.write(0, 'foo🤘');
+  assert_equals(await getFileContents(handle), 'foo🤘');
+  assert_equals(await getFileSize(handle), 7);
+}, 'write() with a valid utf-8 string');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'string_with_unix_line_ending');
+  const writer = await handle.createWriter();
+
+  await writer.write(0, 'foo\n');
+  assert_equals(await getFileContents(handle), 'foo\n');
+  assert_equals(await getFileSize(handle), 4);
+}, 'write() with a string with unix line ending preserved');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'string_with_windows_line_ending');
+  const writer = await handle.createWriter();
+
+  await writer.write(0, 'foo\r\n');
+  assert_equals(await getFileContents(handle), 'foo\r\n');
+  assert_equals(await getFileSize(handle), 5);
+}, 'write() with a string with windows line ending preserved');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'empty_array_buffer');
+  const writer = await handle.createWriter();
+
+  let buf = new ArrayBuffer(0);
+  await writer.write(0, buf);
+  assert_equals(await getFileContents(handle), '');
+  assert_equals(await getFileSize(handle), 0);
+}, 'write() with an empty array buffer to an empty file');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'valid_string_typed_byte_array');
+  const writer = await handle.createWriter();
+
+  let buf = new ArrayBuffer(3);
+  let intView = new Uint8Array(buf);
+  intView[0] = 0x66;
+  intView[1] = 0x6f;
+  intView[2] = 0x6f;
+  await writer.write(0, buf);
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+}, 'write() with a valid typed array buffer');
+
+promise_test(async t => {
     const handle = await createEmptyFile(t, 'trunc_shrink');
     const writer = await handle.createWriter();
 
@@ -64,33 +124,3 @@
     assert_equals(await getFileContents(handle), 'abc\0\0');
     assert_equals(await getFileSize(handle), 5);
 }, 'truncate() to grow a file');
-
-promise_test(async t => {
-    const handle = await createEmptyFile(t, 'write_stream');
-    const writer = await handle.createWriter();
-
-    const stream = new Response('1234567890').body;
-    await writer.write(0, stream);
-
-    assert_equals(await getFileContents(handle), '1234567890');
-    assert_equals(await getFileSize(handle), 10);
-}, 'write() called with a ReadableStream');
-
-promise_test(async t => {
-    const handle = await createEmptyFile(t, 'write_stream');
-    const handle_writer = await handle.createWriter();
-
-    const { writable, readable } = new TransformStream();
-    const write_result = handle_writer.write(0, readable);
-
-    const stream_writer = writable.getWriter();
-    stream_writer.write(new Uint8Array([0x73, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x73, 0x21]));
-    garbageCollect();
-    stream_writer.write(new Uint8Array([0x21, 0x21]));
-    stream_writer.close();
-
-    await write_result;
-
-    assert_equals(await getFileContents(handle), 'streams!!!');
-    assert_equals(await getFileSize(handle), 10);
-}, 'Using a WritableStream writer to write');
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawmove-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawmove-manual.html
deleted file mode 100644
index 0c4ccf9a..0000000
--- a/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawmove-manual.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!doctype html>
-<html>
-    <head>
-        <title>pointerrawmove</title>
-        <meta name="viewport" content="width=device-width">
-        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
-        <script src="/resources/testharness.js"></script>
-        <script src="/resources/testharnessreport.js"></script>
-        <!-- Additional helper script for common checks across event types -->
-        <script type="text/javascript" src="../pointerevent_support.js"></script>
-    </head>
-    <body onload="run()">
-        <h2>pointerrawmove</h2>
-        <h4>Test Description: This test checks if pointerrawmove is dispatched correctly. </h4>
-        <p>Move your mouse within the black box.</p>
-        <p>Press left button down and then press middle button while holding down left button. Then release the buttons</p>
-        <div id="target0"></div>
-        <script>
-            var test_pointerrawmove = async_test("pointerrawmove event received");
-
-            var pointerrawmoveReceived = false;
-            var pointerdownReceived = false;
-            var pointerrawmoveFromButtonChangeReceived = false;
-
-            function run() {
-                var target0 = document.getElementById("target0");
-
-                on_event(target0, "pointerrawmove", function (event) {
-                    pointerrawmoveReceived = true;
-                    if (pointerdownReceived && event.button != -1)
-                      pointerrawmoveFromButtonChangeReceived = true;
-                });
-                on_event(target0, "pointermove", function (event) {
-                    test_pointerrawmove.step(function() {
-                        assert_true(pointerrawmoveReceived,
-                                    "Pointerrawmove event should have been received before pointermove.");
-                        }, "Pointerrawmove event should have been received before pointermove.");
-                });
-                on_event(target0, "pointerdown", function (event) {
-                    pointerdownReceived = true;
-                });
-                on_event(target0, "pointerup", function (event) {
-                    test_pointerrawmove.step(function() {
-                        assert_true(pointerrawmoveFromButtonChangeReceived,
-                                    "Pointerrawmove event should have been received from chorded button changes.");
-                        }, "Pointerrawmove event should have been received from chorded button changes.");
-                    test_pointerrawmove.done();
-                });
-            }
-
-        </script>
-        <div id="complete-notice">
-        </div>
-    </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawmove_in_pointerlock-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawmove_in_pointerlock-manual.html
deleted file mode 100644
index 9703558..0000000
--- a/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawmove_in_pointerlock-manual.html
+++ /dev/null
@@ -1,88 +0,0 @@
-<!doctype html>
-<html>
-    <head>
-        <title>pointerrawmove</title>
-        <meta name="viewport" content="width=device-width">
-        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
-        <script src="/resources/testharness.js"></script>
-        <script src="/resources/testharnessreport.js"></script>
-        <!-- Additional helper script for common checks across event types -->
-        <script type="text/javascript" src="../pointerevent_support.js"></script>
-    </head>
-    <body onload="run()">
-        <h2>pointerrawmove</h2>
-        <h4>Test Description: This test checks if pointerrawmove is dispatched correctly while in pointerlock mode.
-            <ol>
-                <li>Click in the black box (and accept the pointerlock permission if asked).</li>
-                <li>Move your mouse.</li>
-                <li>Click in the purple box inside the iframe</li>
-                <li>Move your mouse.</li>
-            </ol>
-        </h4>
-        <div id="target0"></div>
-        <iframe id="innerframe" src="../resources/pointerevent_pointerrawmove_in_pointerlock-iframe.html"></iframe>
-        <script>
-            window.name="outerframe";
-            var test_pointerrawmove = async_test("pointerrawmove event received");
-
-            var outerframe_pointerrawmoveReceived = false;
-            var innerframe_pointerrawmoveReceived = false;
-
-            function run() {
-                var target0 = document.getElementById("target0");
-                var innerframe = document.getElementById('innerframe');
-                var target1 = innerframe.contentDocument.getElementById('target1');
-                innerframe.contentWindow.name = "innerframe";
-
-                on_event(document, "pointerlockchange", function(event) {
-                  if (document.pointerLockElement == target0) {
-                    on_event(target0, "pointerrawmove", function (event) {
-                      outerframe_pointerrawmoveReceived = true;
-                      test_pointerrawmove.step(function() {
-                        assert_equals(event.view.name, "outerframe", "View attribute of pointerrawmove should be the target frame.");
-                      }, "View attribute of pointerrawmove should be the target frame.");
-                    });
-                    on_event(target0, "pointermove", function (event) {
-                      test_pointerrawmove.step(function() {
-                        assert_true(outerframe_pointerrawmoveReceived,
-                                    "Pointerrawmove event should have been received before pointermove while in pointerlock mode.");
-                        assert_equals(event.view.name, "outerframe", "View attribute of pointerrawmove should be the target frame.");
-                      }, "Pointerrawmove event should have been received before pointermove while in pointerlock mode.");
-                      document.exitPointerLock();
-
-                      on_event(target1, "click", function(event) {
-                        target1.requestPointerLock();
-                      });
-
-                      on_event(innerframe.contentDocument, "pointerlockchange", function(event) {
-                        if (innerframe.contentDocument.pointerLockElement == target1) {
-                          on_event(target1, "pointerrawmove", function (event) {
-                            innerframe_pointerrawmoveReceived = true;
-                            test_pointerrawmove.step(function() {
-                              assert_equals(event.view.name, "innerframe", "View attribute of pointerrawmove should be the target frame.");
-                            }, "View attribute of pointerrawmove should be the target frame.");
-                          });
-                          on_event(target1, "pointermove", function (event) {
-                            test_pointerrawmove.step(function() {
-                              assert_true(innerframe_pointerrawmoveReceived,
-                                    "Pointerrawmove event should have been received before pointermove while in pointerlock mode.");
-                            }, "Pointerrawmove event should have been received before pointermove while in pointerlock mode.");
-                            innerframe.contentDocument.exitPointerLock();
-                            test_pointerrawmove.done();
-                          });
-                        }
-                      });
-
-                    });
-                  }
-                });
-                on_event(target0, "click", function(event) {
-                  target0.requestPointerLock();
-                });
-            }
-
-        </script>
-        <div id="complete-notice">
-        </div>
-    </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate.html b/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate.html
new file mode 100644
index 0000000..0d31701
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<html>
+    <head>
+        <title>pointerrawupdate</title>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="/resources/testdriver.js"></script>
+        <script src="/resources/testdriver-actions.js"></script>
+        <script src="/resources/testdriver-vendor.js"></script>
+        <!-- Additional helper script for common checks across event types -->
+        <script type="text/javascript" src="../pointerevent_support.js"></script>
+    </head>
+    <body onload="run()">
+        <h2>pointerrawupdate</h2>
+        <h4>Test Description: This test checks if pointerrawupdate is dispatched correctly. </h4>
+        <p>Move your mouse within the black box.</p>
+        <p>Press left button down and then press middle button while holding down left button. Then release the buttons</p>
+        <div id="target0"></div>
+        <script>
+            var test_pointerrawupdate = async_test("pointerrawupdate event received");
+
+            var pointerrawupdateReceived = false;
+            var pointerdownReceived = false;
+            var pointerrawupdateFromButtonChangeReceived = false;
+
+            function run() {
+                var target0 = document.getElementById("target0");
+
+                on_event(target0, "pointerrawupdate", function (event) {
+                    pointerrawupdateReceived = true;
+                    if (pointerdownReceived && event.button != -1)
+                      pointerrawupdateFromButtonChangeReceived = true;
+                });
+                on_event(target0, "pointermove", function (event) {
+                    test_pointerrawupdate.step(function() {
+                        assert_true(pointerrawupdateReceived,
+                                    "Pointerrawupdate event should have been received before pointermove.");
+                        }, "Pointerrawupdate event should have been received before pointermove.");
+                });
+                on_event(target0, "pointerdown", function (event) {
+                    pointerdownReceived = true;
+                });
+                on_event(target0, "pointerup", function (event) {
+                    test_pointerrawupdate.step(function() {
+                        assert_true(pointerrawupdateFromButtonChangeReceived,
+                                    "Pointerrawupdate event should have been received from chorded button changes.");
+                        }, "Pointerrawupdate event should have been received from chorded button changes.");
+                    test_pointerrawupdate.done();
+                });
+                var actions = new test_driver.Actions();
+                actions.pointerMove(0, 0, {origin: target0, button: actions.ButtonType.LEFT})
+                    .pointerDown({button: actions.ButtonType.LEFT})
+                    .pointerDown({button: actions.ButtonType.MIDDLE})
+                    .pointerUp({button: actions.ButtonType.MIDDLE})
+                    .pointerUp({button: actions.ButtonType.LEFT})
+                    .send();
+            }
+
+        </script>
+        <div id="complete-notice">
+        </div>
+    </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate_in_pointerlock-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate_in_pointerlock-manual.html
new file mode 100644
index 0000000..704e4419
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate_in_pointerlock-manual.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<html>
+    <head>
+        <title>pointerrawupdate</title>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <!-- Additional helper script for common checks across event types -->
+        <script type="text/javascript" src="../pointerevent_support.js"></script>
+    </head>
+    <body onload="run()">
+        <h2>pointerrawupdate</h2>
+        <h4>Test Description: This test checks if pointerrawupdate is dispatched correctly while in pointerlock mode.
+            <ol>
+                <li>Click in the black box (and accept the pointerlock permission if asked).</li>
+                <li>Move your mouse.</li>
+                <li>Click in the purple box inside the iframe</li>
+                <li>Move your mouse.</li>
+            </ol>
+        </h4>
+        <div id="target0"></div>
+        <iframe id="innerframe" src="../resources/pointerevent_pointerrawupdate_in_pointerlock-iframe.html"></iframe>
+        <script>
+            window.name="outerframe";
+            var test_pointerrawupdate = async_test("pointerrawupdate event received");
+
+            var outerframe_pointerrawupdateReceived = false;
+            var innerframe_pointerrawupdateReceived = false;
+
+            function run() {
+                var target0 = document.getElementById("target0");
+                var innerframe = document.getElementById('innerframe');
+                var target1 = innerframe.contentDocument.getElementById('target1');
+                innerframe.contentWindow.name = "innerframe";
+
+                on_event(document, "pointerlockchange", function(event) {
+                  if (document.pointerLockElement == target0) {
+                    on_event(target0, "pointerrawupdate", function (event) {
+                      outerframe_pointerrawupdateReceived = true;
+                      test_pointerrawupdate.step(function() {
+                        assert_equals(event.view.name, "outerframe", "View attribute of pointerrawupdate should be the target frame.");
+                      }, "View attribute of pointerrawupdate should be the target frame.");
+                    });
+                    on_event(target0, "pointermove", function (event) {
+                      test_pointerrawupdate.step(function() {
+                        assert_true(outerframe_pointerrawupdateReceived,
+                                    "Pointerrawupdate event should have been received before pointermove while in pointerlock mode.");
+                        assert_equals(event.view.name, "outerframe", "View attribute of pointerrawupdate should be the target frame.");
+                      }, "Pointerrawupdate event should have been received before pointermove while in pointerlock mode.");
+                      document.exitPointerLock();
+
+                      on_event(target1, "click", function(event) {
+                        target1.requestPointerLock();
+                      });
+
+                      on_event(innerframe.contentDocument, "pointerlockchange", function(event) {
+                        if (innerframe.contentDocument.pointerLockElement == target1) {
+                          on_event(target1, "pointerrawupdate", function (event) {
+                            innerframe_pointerrawupdateReceived = true;
+                            test_pointerrawupdate.step(function() {
+                              assert_equals(event.view.name, "innerframe", "View attribute of pointerrawupdate should be the target frame.");
+                            }, "View attribute of pointerrawupdate should be the target frame.");
+                          });
+                          on_event(target1, "pointermove", function (event) {
+                            test_pointerrawupdate.step(function() {
+                              assert_true(innerframe_pointerrawupdateReceived,
+                                    "Pointerrawupdate event should have been received before pointermove while in pointerlock mode.");
+                            }, "Pointerrawupdate event should have been received before pointermove while in pointerlock mode.");
+                            innerframe.contentDocument.exitPointerLock();
+                            test_pointerrawupdate.done();
+                          });
+                        }
+                      });
+
+                    });
+                  }
+                });
+                on_event(target0, "click", function(event) {
+                  target0.requestPointerLock();
+                });
+            }
+
+        </script>
+        <div id="complete-notice">
+        </div>
+    </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js
index e8c847b..dc35ea2 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js
@@ -285,3 +285,12 @@
                    .pointerUp()
                    .send();
 }
+
+function touchTapInTarget(target) {
+    return new test_driver.Actions()
+                   .addPointer("pointer1", "touch")
+                   .pointerMove(0, 0, {origin: target})
+                   .pointerDown()
+                   .pointerUp()
+                   .send();
+}
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/resources/pointerevent_pointerrawmove_in_pointerlock-iframe.html b/third_party/blink/web_tests/external/wpt/pointerevents/resources/pointerevent_pointerrawupdate_in_pointerlock-iframe.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/pointerevents/resources/pointerevent_pointerrawmove_in_pointerlock-iframe.html
rename to third_party/blink/web_tests/external/wpt/pointerevents/resources/pointerevent_pointerrawupdate_in_pointerlock-iframe.html
diff --git a/third_party/blink/web_tests/external/wpt/portals/htmlportalelement-event-handler-content-attributes.html b/third_party/blink/web_tests/external/wpt/portals/htmlportalelement-event-handler-content-attributes.html
new file mode 100644
index 0000000..8fc26386
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/portals/htmlportalelement-event-handler-content-attributes.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// Dispatch of these events is tested elsewhere.
+// This test merely ensures that the event handler content attributes work.
+let eventNames = ["load", "message", "messageerror"];
+test(() => {
+  try {
+    let portal = document.createElement("portal");
+    for (let eventName of eventNames) {
+      window.testValue = "not fired";
+      portal.setAttribute("on" + eventName, "window.testValue = 'fired'");
+      portal.dispatchEvent(new Event(eventName));
+      assert_equals(window.testValue, "fired", `${eventName} should have fired`);
+
+      window.testValue = "not fired";
+      portal.removeAttribute("on" + eventName);
+      portal.dispatchEvent(new Event(eventName));
+      assert_equals(window.testValue, "not fired", `${eventName} should not have fired`);
+    }
+  } finally {
+    delete window.testValue;
+  }
+}, "Tests that event handler content attributes for supported event names work.");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-cross-origin-load.sub.html b/third_party/blink/web_tests/external/wpt/portals/portals-cross-origin-load.sub.html
index f860ac5..0d837b99 100644
--- a/third_party/blink/web_tests/external/wpt/portals/portals-cross-origin-load.sub.html
+++ b/third_party/blink/web_tests/external/wpt/portals/portals-cross-origin-load.sub.html
@@ -4,17 +4,14 @@
 <body>
 <script>
   promise_test(async () => {
-    var bc = new BroadcastChannel("portals-cross-origin-load");
-    var receiveMessage = new Promise((resolve, reject) => {
-      bc.onmessage = e => {
-        bc.close();
-        resolve();
-      }
-    });
     var portal = document.createElement("portal");
     portal.src = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-cross-origin.sub.html";
+    var receiveMessage = new Promise((resolve, reject) => {
+      portal.onmessage = e => { resolve(e.data) };
+    });
     document.body.appendChild(portal);
-    return receiveMessage;
+    var message = await receiveMessage;
+    assert_equals(message, "loaded");
   });
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-host-exposure.sub.html b/third_party/blink/web_tests/external/wpt/portals/portals-host-exposure.sub.html
index 83e31bd4..36fc2b4 100644
--- a/third_party/blink/web_tests/external/wpt/portals/portals-host-exposure.sub.html
+++ b/third_party/blink/web_tests/external/wpt/portals/portals-host-exposure.sub.html
@@ -3,41 +3,28 @@
 <script src="/resources/testharnessreport.js"></script>
 <body>
 <script>
-  let channelIndex = 0;
-  async function openPortalAndReceiveMessage(portalSrc) {
-    let channelName = `portals-host-exposure-${channelIndex++}`
-    let broadcastChannel = new BroadcastChannel(channelName);
-    try {
-      let received = new Promise((resolve, reject) => {
-        broadcastChannel.addEventListener('message', e => {
-          resolve(e.data);
-        }, {once: true})
-      });
-      let portal = document.createElement('portal');
-      portal.src = `${portalSrc}?broadcastchannel=${channelName}`;
+  function openPortalAndReceiveMessage(portalSrc) {
+    let portal = document.createElement('portal');
+    portal.src = portalSrc;
+    let received = new Promise((resolve, reject) => {
+      portal.onmessage = resolve;
       document.body.appendChild(portal);
-      return await received;
-    } finally {
-      broadcastChannel.close();
-    }
+    });
+    return received;
   }
 
-  promise_test(async t => {
-    let {hasHost} = await openPortalAndReceiveMessage(
-        'resources/portal-host.html');
-    assert_true(hasHost, "window.portalHost should be defined");
+  promise_test(() => {
+    return openPortalAndReceiveMessage("resources/portal-host.html");
   }, "window.portalHost should be exposed in same-origin portal");
 
-  promise_test(async t => {
-    let {hasHost} = await openPortalAndReceiveMessage(
-        'http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-host-cross-origin.sub.html');
-    assert_true(hasHost, "window.portalHost should be defined");
+  promise_test(() => {
+    return openPortalAndReceiveMessage(
+        "http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-host.html");
   }, "window.portalHost should be exposed in cross-origin portal");
 
-  promise_test(async t => {
-    let {hasHost} = await openPortalAndReceiveMessage(
+  promise_test(() => {
+    return openPortalAndReceiveMessage(
         'resources/portal-host-cross-origin-navigate.sub.html');
-    assert_true(hasHost, "window.portalHost should be defined");
   }, "window.portalHost should be exposed in portal after cross-origin navigation");
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-rendering.html b/third_party/blink/web_tests/external/wpt/portals/portals-rendering.html
index 8683a38..0eae0dd 100644
--- a/third_party/blink/web_tests/external/wpt/portals/portals-rendering.html
+++ b/third_party/blink/web_tests/external/wpt/portals/portals-rendering.html
@@ -3,14 +3,15 @@
 <title>Portals rendering test</title>
 <link rel="match" href="references/portals-rendering.html">
 <body>
-  <portal src="resources/portals-rendering-portal.html" style="background-color: red; width: 100px; height: 100px"></portal>
   <script>
-    var bc = new BroadcastChannel('portal');
-    bc.onmessage = function(e) {
+    var portal = document.createElement('portal');
+    portal.src = 'resources/portals-rendering-portal.html';
+    portal.style = 'background-color: red; width: 100px; height: 100px';
+    portal.onmessage = e => {
       window.requestAnimationFrame(function(ts) {
         document.documentElement.classList.remove('reftest-wait');
       });
-      bc.close();
     }
+    document.body.appendChild(portal);
   </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-cross-origin.sub.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-cross-origin.sub.html
index 145ab5a..d4710c0 100644
--- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-cross-origin.sub.html
+++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-cross-origin.sub.html
@@ -1,11 +1,6 @@
 <!DOCTYPE html>
 <body>
   <script>
-    var iframe = document.createElement("iframe");
-    iframe.src = "http://{{host}}:{{ports[http][0]}}/portals/resources/portal-forward-with-broadcast.html?broadcastchannel=portals-cross-origin-load";
-    iframe.onload = e => {
-      iframe.contentWindow.postMessage("loaded", "*");
-    }
-    document.body.appendChild(iframe);
+    window.portalHost.postMessage("loaded", "*");
   </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-cross-origin-navigate.sub.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-cross-origin-navigate.sub.html
index 44c6c16..ce7aaf8 100644
--- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-cross-origin-navigate.sub.html
+++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-cross-origin-navigate.sub.html
@@ -2,6 +2,6 @@
 <body>
   <script>
     let channelName = new URL(location).searchParams.get('broadcastchannel');
-    window.location.href = `http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-host-cross-origin.sub.html?broadcastchannel=${channelName}`;
+    window.location.href = `http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-host.html`;
   </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-cross-origin.sub.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-cross-origin.sub.html
deleted file mode 100644
index dc4e9e7b..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-cross-origin.sub.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<body>
-  <script>
-    let forwardingIframe = document.createElement('iframe');
-    let channelName = new URL(location).searchParams.get('broadcastchannel');
-    forwardingIframe.src = `http://{{host}}:{{ports[http][0]}}/portals/resources/portal-forward-with-broadcast.html?broadcastchannel=${channelName}`;
-    forwardingIframe.onload = () => {
-      let message = {
-        hasHost: !!window.portalHost
-      };
-      forwardingIframe.contentWindow.postMessage(message, '*');
-    }
-    document.body.appendChild(forwardingIframe);
-  </script>
-</body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host.html
index 5043a158e..3a407d8 100644
--- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host.html
+++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host.html
@@ -1,14 +1,7 @@
 <!DOCTYPE html>
 <body>
   <script>
-    let message = {
-      hasHost: !!window.portalHost
-    };
-    let broadcastChannel = new BroadcastChannel(new URL(location).searchParams.get('broadcastchannel'));
-    try {
-      broadcastChannel.postMessage(message);
-    } finally {
-      broadcastChannel.close();
-    }
+    if (window.portalHost)
+      window.portalHost.postMessage("has host", "*");
   </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portals-rendering-portal.html b/third_party/blink/web_tests/external/wpt/portals/resources/portals-rendering-portal.html
index 1b6f23f..c3fe18ef 100644
--- a/third_party/blink/web_tests/external/wpt/portals/resources/portals-rendering-portal.html
+++ b/third_party/blink/web_tests/external/wpt/portals/resources/portals-rendering-portal.html
@@ -2,9 +2,7 @@
 <body style="background-color: green">
   <script>
     window.requestAnimationFrame(function(ts) {
-      var bc = new BroadcastChannel('portal');
-      bc.postMessage('loaded');
-      bc.close();
+      window.portalHost.postMessage("loaded", "*");
     });
   </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-quic/RTCQuicTransport.https.html b/third_party/blink/web_tests/external/wpt/webrtc-quic/RTCQuicTransport.https.html
index 12c2371f..b84d90f 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-quic/RTCQuicTransport.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc-quic/RTCQuicTransport.https.html
@@ -4,6 +4,7 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../webrtc/RTCIceTransport-extension-helper.js"></script>
+<script src="../webrtc/RTCPeerConnection-helper.js"></script>
 <script src="RTCQuicTransport-helper.js"></script>
 <script src="../webrtc/dictionary-helper.js"></script>
 <script>
@@ -48,6 +49,21 @@
 }, 'RTCQuicTransport constructor throws if passed an RTCIceTransport that ' +
     'already has an active RTCQuicTransport.');
 
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+
+  pc1.createDataChannel('test');
+  await doSignalingHandshake(pc1, pc2);
+  const iceTransport = pc1.sctp.transport.iceTransport;
+
+  assert_throws('InvalidStateError',
+      () => makeQuicTransport(t, iceTransport));
+}, 'RTCQuicTransport constructor throws if passed an RTCIceTransport that ' +
+    'came from an RTCPeerConnection.');
+
 test(t => {
   const quicTransport = makeStandaloneQuicTransport(t);
   quicTransport.stop();
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCTrackEvent-fire.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCTrackEvent-fire.html
index 2e226c3..eca8644 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCTrackEvent-fire.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCTrackEvent-fire.html
@@ -36,6 +36,17 @@
 a=ssrc:3 msid:1 2
 `;
 
+const sdp2 = sdpBase + `
+a=ssrc:3 cname:4
+a=ssrc:3 msid:1 2
+`;
+
+const sdp3 = sdpBase + `
+a=msid:1 2
+a=ssrc:3 cname:4
+a=ssrc:3 msid:3 2
+`;
+
 async function applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp)
 {
     const testTrackPromise = new Promise(resolve  => {
@@ -52,6 +63,39 @@
     const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
     assert_equals(streams.length, 1, "track event has a stream");
     assert_equals(streams[0].id, "1", "msid should match");
+}, "Source-level msid should be ignored if media-level msid is present");
+
+promise_test(async test => {
+    const pc = new RTCPeerConnection();
+    test.add_cleanup(() => pc.close());
+
+    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp2);
+    assert_equals(streams.length, 1, "track event has a stream");
+    assert_equals(streams[0].id, "1", "msid should match");
+}, "Source-level msid should be parsed if media-level msid is absent");
+
+promise_test(async test => {
+    const pc = new RTCPeerConnection();
+    test.add_cleanup(() => pc.close());
+
+    let track;
+    let streams;
+    try {
+      [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp3);
+    } catch (e) {
+      return;
+    }
+    assert_equals(streams.length, 1, "track event has a stream");
+    assert_equals(streams[0].id, "1", "msid should match");
+}, "Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present");
+
+promise_test(async test => {
+    const pc = new RTCPeerConnection();
+    test.add_cleanup(() => pc.close());
+
+    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
+    assert_equals(streams.length, 1, "track event has a stream");
+    assert_equals(streams[0].id, "1", "msid should match");
     const stream = streams[0];
 
     await pc.setLocalDescription(await pc.createAnswer());
diff --git a/third_party/blink/web_tests/external/wpt_automation/html/user-activation/no-activation-thru-escape-key-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/html/user-activation/no-activation-thru-escape-key-manual-automation.js
new file mode 100644
index 0000000..12f0c5d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt_automation/html/user-activation/no-activation-thru-escape-key-manual-automation.js
@@ -0,0 +1,5 @@
+importAutomationScript('/input-events/inputevent_common_input.js');
+
+function inject_input() {
+  return keyDown("Escape");
+}
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
index 6e9e725..624fdfa 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -146,7 +146,7 @@
 PASS oldChildWindow.onpointermove is newChildWindow.onpointermove
 PASS oldChildWindow.onpointerout is newChildWindow.onpointerout
 PASS oldChildWindow.onpointerover is newChildWindow.onpointerover
-PASS oldChildWindow.onpointerrawmove is newChildWindow.onpointerrawmove
+PASS oldChildWindow.onpointerrawupdate is newChildWindow.onpointerrawupdate
 PASS oldChildWindow.onpointerup is newChildWindow.onpointerup
 PASS oldChildWindow.onpopstate is newChildWindow.onpopstate
 PASS oldChildWindow.onportalactivate is newChildWindow.onportalactivate
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
index cf33b11..458db22 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -108,7 +108,7 @@
 PASS childWindow.onpointermove is null
 PASS childWindow.onpointerout is null
 PASS childWindow.onpointerover is null
-PASS childWindow.onpointerrawmove is null
+PASS childWindow.onpointerrawupdate is null
 PASS childWindow.onpointerup is null
 PASS childWindow.onpopstate is null
 PASS childWindow.onportalactivate is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
index fbf0fb7b48..c0e50e2f 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -108,7 +108,7 @@
 PASS childWindow.onpointermove is null
 PASS childWindow.onpointerout is null
 PASS childWindow.onpointerover is null
-PASS childWindow.onpointerrawmove is null
+PASS childWindow.onpointerrawupdate is null
 PASS childWindow.onpointerup is null
 PASS childWindow.onpopstate is null
 PASS childWindow.onportalactivate is null
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
index 8e687b7..143eb8e 100644
--- a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
+++ b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
@@ -10,8 +10,8 @@
   overflow: scroll;
   border: 1px solid black;
   position: absolute;
-  top: 0px;
-  left: 0px;
+  top: 100px;
+  left: 100px;
 }
 .fast {
   will-change: transform;
diff --git a/third_party/blink/web_tests/fast/shapes/parsing/parsing-shape-outside-expected.txt b/third_party/blink/web_tests/fast/shapes/parsing/parsing-shape-outside-expected.txt
index 4e6cfc83..3a310a4 100644
--- a/third_party/blink/web_tests/fast/shapes/parsing/parsing-shape-outside-expected.txt
+++ b/third_party/blink/web_tests/fast/shapes/parsing/parsing-shape-outside-expected.txt
@@ -104,16 +104,10 @@
 PASS getComputedStyleValue("shape-outside", "circle(10px at right 10px bottom 10px)") is "circle(10px at right 10px bottom 10px)"
 PASS getCSSText("shape-outside", "ellipse()") is "ellipse(at 50% 50%)"
 PASS getComputedStyleValue("shape-outside", "ellipse()") is "ellipse(at 50% 50%)"
-PASS getCSSText("shape-outside", "ellipse(10px)") is "ellipse(10px at 50% 50%)"
-PASS getComputedStyleValue("shape-outside", "ellipse(10px)") is "ellipse(10px at 50% 50%)"
 PASS getCSSText("shape-outside", "ellipse(10px 20px)") is "ellipse(10px 20px at 50% 50%)"
 PASS getComputedStyleValue("shape-outside", "ellipse(10px 20px)") is "ellipse(10px 20px at 50% 50%)"
-PASS getCSSText("shape-outside", "ellipse(10px at 10px)") is "ellipse(10px at 10px 50%)"
-PASS getComputedStyleValue("shape-outside", "ellipse(10px at 10px)") is "ellipse(10px at 10px 50%)"
 PASS getCSSText("shape-outside", "ellipse(10px 20px at 10px)") is "ellipse(10px 20px at 10px 50%)"
 PASS getComputedStyleValue("shape-outside", "ellipse(10px 20px at 10px)") is "ellipse(10px 20px at 10px 50%)"
-PASS getCSSText("shape-outside", "ellipse(10px at 10px 10px)") is "ellipse(10px at 10px 10px)"
-PASS getComputedStyleValue("shape-outside", "ellipse(10px at 10px 10px)") is "ellipse(10px at 10px 10px)"
 PASS getCSSText("shape-outside", "ellipse(at 10px)") is "ellipse(at 10px 50%)"
 PASS getComputedStyleValue("shape-outside", "ellipse(at 10px)") is "ellipse(at 10px 50%)"
 PASS getCSSText("shape-outside", "ellipse(at 10px 10px)") is "ellipse(at 10px 10px)"
@@ -122,12 +116,6 @@
 PASS getComputedStyleValue("shape-outside", "ellipse(at top left)") is "ellipse(at 0% 0%)"
 PASS getCSSText("shape-outside", "ellipse(at right bottom)") is "ellipse(at 100% 100%)"
 PASS getComputedStyleValue("shape-outside", "ellipse(at right bottom)") is "ellipse(at 100% 100%)"
-PASS getCSSText("shape-outside", "ellipse(10px at left 0% top 10px)") is "ellipse(10px at 0% 10px)"
-PASS getComputedStyleValue("shape-outside", "ellipse(10px at left 0% top 10px)") is "ellipse(10px at 0% 10px)"
-PASS getCSSText("shape-outside", "ellipse(10px at top 10px left 10px)") is "ellipse(10px at 10px 10px)"
-PASS getComputedStyleValue("shape-outside", "ellipse(10px at top 10px left 10px)") is "ellipse(10px at 10px 10px)"
-PASS getCSSText("shape-outside", "ellipse(10px at right 10px bottom 10px)") is "ellipse(10px at right 10px bottom 10px)"
-PASS getComputedStyleValue("shape-outside", "ellipse(10px at right 10px bottom 10px)") is "ellipse(10px at right 10px bottom 10px)"
 PASS getCSSText("shape-outside", "ellipse(10px 20px at left 0% top 10px)") is "ellipse(10px 20px at 0% 10px)"
 PASS getComputedStyleValue("shape-outside", "ellipse(10px 20px at left 0% top 10px)") is "ellipse(10px 20px at 0% 10px)"
 PASS getCSSText("shape-outside", "ellipse(10px 20px at top 10px left 10px)") is "ellipse(10px 20px at 10px 10px)"
@@ -140,8 +128,8 @@
 PASS getComputedStyleValue("shape-outside", "ellipse(farthest-side farthest-side at 50px 50px)") is "ellipse(farthest-side farthest-side at 50px 50px)"
 PASS getCSSText("shape-outside", "ellipse(closest-side farthest-side at 50px 50px)") is "ellipse(closest-side farthest-side at 50px 50px)"
 PASS getComputedStyleValue("shape-outside", "ellipse(closest-side farthest-side at 50px 50px)") is "ellipse(closest-side farthest-side at 50px 50px)"
-PASS getCSSText("shape-outside", "ellipse(farthest-side closest-side at 50px 50px)") is "ellipse(farthest-side at 50px 50px)"
-PASS getComputedStyleValue("shape-outside", "ellipse(farthest-side closest-side at 50px 50px)") is "ellipse(farthest-side at 50px 50px)"
+PASS getCSSText("shape-outside", "ellipse(farthest-side closest-side at 50px 50px)") is "ellipse(farthest-side closest-side at 50px 50px)"
+PASS getComputedStyleValue("shape-outside", "ellipse(farthest-side closest-side at 50px 50px)") is "ellipse(farthest-side closest-side at 50px 50px)"
 PASS getCSSText("shape-outside", "polygon(10px 20px, 30px 40px, 40px 50px)") is "polygon(10px 20px, 30px 40px, 40px 50px)"
 PASS getComputedStyleValue("shape-outside", "polygon(10px 20px, 30px 40px, 40px 50px)") is "polygon(10px 20px, 30px 40px, 40px 50px)"
 PASS getCSSText("shape-outside", "polygon(evenodd, 10px 20px, 30px 40px, 40px 50px)") is "polygon(evenodd, 10px 20px, 30px 40px, 40px 50px)"
@@ -258,6 +246,18 @@
 PASS getComputedStyleValue("shape-outside", "ellipse(10px 20px at)") is "none"
 PASS getCSSText("shape-outside", "ellipse(at)") is ""
 PASS getComputedStyleValue("shape-outside", "ellipse(at)") is "none"
+PASS getCSSText("shape-outside", "ellipse(10px)") is ""
+PASS getComputedStyleValue("shape-outside", "ellipse(10px)") is "none"
+PASS getCSSText("shape-outside", "ellipse(10px at 10px)") is ""
+PASS getComputedStyleValue("shape-outside", "ellipse(10px at 10px)") is "none"
+PASS getCSSText("shape-outside", "ellipse(10px at 10px 10px)") is ""
+PASS getComputedStyleValue("shape-outside", "ellipse(10px at 10px 10px)") is "none"
+PASS getCSSText("shape-outside", "ellipse(10px at left 0% top 10px)") is ""
+PASS getComputedStyleValue("shape-outside", "ellipse(10px at left 0% top 10px)") is "none"
+PASS getCSSText("shape-outside", "ellipse(10px at top 10px left 10px)") is ""
+PASS getComputedStyleValue("shape-outside", "ellipse(10px at top 10px left 10px)") is "none"
+PASS getCSSText("shape-outside", "ellipse(10px at right 10px bottom 10px)") is ""
+PASS getComputedStyleValue("shape-outside", "ellipse(10px at right 10px bottom 10px)") is "none"
 PASS getCSSText("shape-outside", "polygon()") is ""
 PASS getComputedStyleValue("shape-outside", "polygon()") is "none"
 PASS getCSSText("shape-outside", "polygon(evenodd 10px 20px, 30px 40px, 40px 50px)") is ""
diff --git a/third_party/blink/web_tests/fast/shapes/parsing/parsing-test-utils.js b/third_party/blink/web_tests/fast/shapes/parsing/parsing-test-utils.js
index fb187643..5a6e3ac 100644
--- a/third_party/blink/web_tests/fast/shapes/parsing/parsing-test-utils.js
+++ b/third_party/blink/web_tests/fast/shapes/parsing/parsing-test-utils.js
@@ -60,25 +60,19 @@
     ["circle(10px at right 10px bottom 10px)", "circle(10px at right 10px bottom 10px)"],
 
     ["ellipse()", "ellipse(at 50% 50%)", "ellipse(at 50% 50%)"],
-    ["ellipse(10px)", "ellipse(10px at 50% 50%)", "ellipse(10px at 50% 50%)"],
     ["ellipse(10px 20px)", "ellipse(10px 20px at 50% 50%)"],
-    ["ellipse(10px at 10px)", "ellipse(10px at 10px 50%)", "ellipse(10px at 10px 50%)"],
     ["ellipse(10px 20px at 10px)", "ellipse(10px 20px at 10px 50%)"],
-    ["ellipse(10px at 10px 10px)", "ellipse(10px at 10px 10px)", "ellipse(10px at 10px 10px)"],
     ["ellipse(at 10px)", "ellipse(at 10px 50%)", "ellipse(at 10px 50%)"],
     ["ellipse(at 10px 10px)", "ellipse(at 10px 10px)", "ellipse(at 10px 10px)"],
     ["ellipse(at top left)", "ellipse(at 0% 0%)", "ellipse(at 0% 0%)"],
     ["ellipse(at right bottom)", "ellipse(at 100% 100%)", "ellipse(at 100% 100%)"],
-    ["ellipse(10px at left 0% top 10px)", "ellipse(10px at 0% 10px)", "ellipse(10px at 0% 10px)"],
-    ["ellipse(10px at top 10px left 10px)", "ellipse(10px at 10px 10px)", "ellipse(10px at 10px 10px)"],
-    ["ellipse(10px at right 10px bottom 10px)", "ellipse(10px at right 10px bottom 10px)", "ellipse(10px at right 10px bottom 10px)"],
     ["ellipse(10px 20px at left 0% top 10px)", "ellipse(10px 20px at 0% 10px)"],
     ["ellipse(10px 20px at top 10px left 10px)", "ellipse(10px 20px at 10px 10px)"],
     ["ellipse(10px 20px at right 10px bottom 10px)", "ellipse(10px 20px at right 10px bottom 10px)"],
     ["ellipse(closest-side closest-side at 50px 50px)", "ellipse(at 50px 50px)", "ellipse(at 50px 50px)"],
     ["ellipse(farthest-side farthest-side at 50px 50px)", "ellipse(farthest-side farthest-side at 50px 50px)", "ellipse(farthest-side farthest-side at 50px 50px)"],
     ["ellipse(closest-side farthest-side at 50px 50px)", "ellipse(closest-side farthest-side at 50px 50px)", "ellipse(closest-side farthest-side at 50px 50px)"],
-    ["ellipse(farthest-side closest-side at 50px 50px)", "ellipse(farthest-side at 50px 50px)", "ellipse(farthest-side at 50px 50px)"],
+    ["ellipse(farthest-side closest-side at 50px 50px)", "ellipse(farthest-side closest-side at 50px 50px)", "ellipse(farthest-side closest-side at 50px 50px)"],
 
     ["polygon(10px 20px, 30px 40px, 40px 50px)", "polygon(10px 20px, 30px 40px, 40px 50px)"],
     ["polygon(evenodd, 10px 20px, 30px 40px, 40px 50px)", "polygon(evenodd, 10px 20px, 30px 40px, 40px 50px)"],
@@ -150,6 +144,12 @@
     "ellipse(at center center 10px)",
     "ellipse(10px 20px at)",
     "ellipse(at)",
+    "ellipse(10px)",
+    "ellipse(10px at 10px)",
+    "ellipse(10px at 10px 10px)",
+    "ellipse(10px at left 0% top 10px)",
+    "ellipse(10px at top 10px left 10px)",
+    "ellipse(10px at right 10px bottom 10px)",
 
     "polygon()",
     "polygon(evenodd 10px 20px, 30px 40px, 40px 50px)",
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 45207881..cab535d 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -549,6 +549,7 @@
     getter direction
     getter key
     getter primaryKey
+    getter request
     getter source
     method advance
     method constructor
diff --git a/third_party/blink/web_tests/media/autoplay/muted-volume-0.html b/third_party/blink/web_tests/media/autoplay/muted-volume-0.html
new file mode 100644
index 0000000..24479b80
--- /dev/null
+++ b/third_party/blink/web_tests/media/autoplay/muted-volume-0.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<title>Test that the autoplay muted applies for volume=0</title>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+<body></body>
+<script>
+async_test(t => {
+  t.add_cleanup(() => {
+    internals.settings.setAutoplayPolicy('no-user-gesture-required');
+    internals.runtimeFlags.autoplayMutedVideosEnabled = false;
+  });
+  internals.settings.setAutoplayPolicy('document-user-activation-required');
+  internals.runtimeFlags.autoplayMutedVideosEnabled = true;
+
+  var video = document.createElement('video');
+  video.autoplay = true;
+  video.volume = 0;
+  video.src = '../content/test.ogv';
+  document.body.appendChild(video);
+
+  video.addEventListener('play', t.step_func(e => {
+    video.volume = 0.1;
+    video.addEventListener('pause', t.step_func_done());
+  }), { once: true });
+}, "volume=0 allows muted autoplay, volume!=0 pauses");
+
+async_test(t => {
+  t.add_cleanup(() => {
+    internals.settings.setAutoplayPolicy('no-user-gesture-required');
+    internals.runtimeFlags.autoplayMutedVideosEnabled = false;
+  });
+  internals.settings.setAutoplayPolicy('document-user-activation-required');
+  internals.runtimeFlags.autoplayMutedVideosEnabled = true;
+
+  var video = document.createElement('video');
+  video.autoplay = true;
+  video.volume = 0;
+  video.src = '../content/test.ogv';
+  document.body.appendChild(video);
+
+  video.addEventListener('play', t.step_func(e => {
+    video.muted = true;
+    video.volume = 0.1;
+    var timeUpdateCount = 0;
+    video.addEventListener('timeupdate', t.step_func(e => {
+      timeUpdateCount++;
+      if (timeUpdateCount == 3) t.done();
+    }));
+  }), { once: true });
+}, "muted after volume=0 will not pause if volume!=0");
+
+
+async_test(t => {
+  t.add_cleanup(() => {
+    internals.settings.setAutoplayPolicy('no-user-gesture-required');
+    internals.runtimeFlags.autoplayMutedVideosEnabled = false;
+  });
+  internals.settings.setAutoplayPolicy('document-user-activation-required');
+  internals.runtimeFlags.autoplayMutedVideosEnabled = true;
+
+  var video = document.createElement('video');
+  video.autoplay = true;
+  video.muted = true;
+  video.src = '../content/test.ogv';
+  document.body.appendChild(video);
+
+  video.addEventListener('play', t.step_func(e => {
+    video.volume = 0;
+    video.muted = false;
+    var timeUpdateCount = 0;
+    video.addEventListener('timeupdate', t.step_func(e => {
+      timeUpdateCount++;
+      if (timeUpdateCount == 3) t.done();
+    }));
+  }), { once: true });
+}, "unmuted after setting volume to 0 does not pause");
+</script>
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
index 0e3e22f0..01ebc1d 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
index 310a6f2..6fed243 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
index 8dd35947..93d2d69 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
index e133a9e9..82a894c 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
index 5b4aadf..42bb074 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-mode/paint/dark-mode/native-theme-off/text-input-elements-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
index 8257781..b0b264b5 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-mode/paint/dark-mode/native-theme-on/text-input-elements-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/bidi-caret-affinity/editing/selection/modify_move/README.txt b/third_party/blink/web_tests/virtual/bidi-caret-affinity/editing/selection/modify_move/README.txt
deleted file mode 100644
index e65859c3..0000000
--- a/third_party/blink/web_tests/virtual/bidi-caret-affinity/editing/selection/modify_move/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-# This suite runs the tests  with
-# --enable-blink-features=BidiCaretAffinity
-# See design doc for more details: http://bit.ly/2xVMjdc
diff --git a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 8c21bdc..e354a28 100644
--- a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -526,6 +526,7 @@
     getter direction
     getter key
     getter primaryKey
+    getter request
     getter source
     method advance
     method constructor
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 73de57d2d..ae16471e9 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -487,6 +487,7 @@
 [Worker]     getter direction
 [Worker]     getter key
 [Worker]     getter primaryKey
+[Worker]     getter request
 [Worker]     getter source
 [Worker]     method advance
 [Worker]     method constructor
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index a9e5eb63..3ba70a9 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1335,6 +1335,7 @@
     getter onresume
     getter onscroll
     getter onsearch
+    getter onsecuritypolicyviolation
     getter onseeked
     getter onseeking
     getter onselect
@@ -1516,6 +1517,7 @@
     setter onresume
     setter onscroll
     setter onsearch
+    setter onsecuritypolicyviolation
     setter onseeked
     setter onseeking
     setter onselect
@@ -3453,6 +3455,7 @@
     getter direction
     getter key
     getter primaryKey
+    getter request
     getter source
     method advance
     method constructor
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index 43d43de..ba3e073 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -482,6 +482,7 @@
 [Worker]     getter direction
 [Worker]     getter key
 [Worker]     getter primaryKey
+[Worker]     getter request
 [Worker]     getter source
 [Worker]     method advance
 [Worker]     method constructor
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
index f53002f0..ce383ee 100644
--- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -227,7 +227,7 @@
     property onpointermove
     property onpointerout
     property onpointerover
-    property onpointerrawmove
+    property onpointerrawupdate
     property onpointerup
     property onprogress
     property onratechange
@@ -1396,7 +1396,7 @@
     property onpointermove
     property onpointerout
     property onpointerover
-    property onpointerrawmove
+    property onpointerrawupdate
     property onpointerup
     property onprogress
     property onratechange
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 528fc1d0..c28fa7a5 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -496,6 +496,7 @@
 [Worker]     getter direction
 [Worker]     getter key
 [Worker]     getter primaryKey
+[Worker]     getter request
 [Worker]     getter source
 [Worker]     method advance
 [Worker]     method constructor
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 7d34dff..fa6b72f 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1638,7 +1638,7 @@
     getter onpointermove
     getter onpointerout
     getter onpointerover
-    getter onpointerrawmove
+    getter onpointerrawupdate
     getter onpointerup
     getter onprogress
     getter onratechange
@@ -1828,7 +1828,7 @@
     setter onpointermove
     setter onpointerout
     setter onpointerover
-    setter onpointerrawmove
+    setter onpointerrawupdate
     setter onpointerup
     setter onprogress
     setter onratechange
@@ -2785,7 +2785,7 @@
     getter onpointermove
     getter onpointerout
     getter onpointerover
-    getter onpointerrawmove
+    getter onpointerrawupdate
     getter onpointerup
     getter onprogress
     getter onratechange
@@ -2891,7 +2891,7 @@
     setter onpointermove
     setter onpointerout
     setter onpointerover
-    setter onpointerrawmove
+    setter onpointerrawupdate
     setter onpointerup
     setter onprogress
     setter onratechange
@@ -4044,6 +4044,7 @@
     getter direction
     getter key
     getter primaryKey
+    getter request
     getter source
     method advance
     method constructor
@@ -6314,7 +6315,7 @@
     getter onpointermove
     getter onpointerout
     getter onpointerover
-    getter onpointerrawmove
+    getter onpointerrawupdate
     getter onpointerup
     getter onprogress
     getter onratechange
@@ -6406,7 +6407,7 @@
     setter onpointermove
     setter onpointerout
     setter onpointerover
-    setter onpointerrawmove
+    setter onpointerrawupdate
     setter onpointerup
     setter onprogress
     setter onratechange
@@ -11014,7 +11015,7 @@
     getter onpointermove
     getter onpointerout
     getter onpointerover
-    getter onpointerrawmove
+    getter onpointerrawupdate
     getter onpointerup
     getter onpopstate
     getter onportalactivate
@@ -11211,7 +11212,7 @@
     setter onpointermove
     setter onpointerout
     setter onpointerover
-    setter onpointerrawmove
+    setter onpointerrawupdate
     setter onpointerup
     setter onpopstate
     setter onportalactivate
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index 23ff461e..ee7e65b 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -491,6 +491,7 @@
 [Worker]     getter direction
 [Worker]     getter key
 [Worker]     getter primaryKey
+[Worker]     getter request
 [Worker]     getter source
 [Worker]     method advance
 [Worker]     method constructor
diff --git a/third_party/breakpad/BUILD.gn b/third_party/breakpad/BUILD.gn
index d9d959d..27c3d0c 100644
--- a/third_party/breakpad/BUILD.gn
+++ b/third_party/breakpad/BUILD.gn
@@ -712,9 +712,9 @@
     deps = [
       ":client",
       ":processor_support",
+      "//base/test:run_all_unittests",
       "//testing/gmock",
       "//testing/gtest",
-      "//testing/gtest:gtest_main",
     ]
 
     data_deps = [
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index 9261544a..b84901b 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -133973,6 +133973,7 @@
   Vdbe *v = sqlite3GetVdbe(pParse);
   int iDb = 0;
   if( v==0 ) goto build_vacuum_end;
+  if( pParse->nErr ) goto build_vacuum_end;
   if( pNm ){
 #ifndef SQLITE_BUG_COMPATIBLE_20160819
     /* Default behavior:  Report an error if the argument to VACUUM is
@@ -135125,6 +135126,7 @@
     p = vtabDisconnectAll(db, pTab);
     xDestroy = p->pMod->pModule->xDestroy;
     assert( xDestroy!=0 );  /* Checked before the virtual table is created */
+    pTab->nTabRef++;
     rc = xDestroy(p->pVtab);
     /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
     if( rc==SQLITE_OK ){
@@ -135133,6 +135135,7 @@
       pTab->pVTable = 0;
       sqlite3VtabUnlock(p);
     }
+    sqlite3DeleteTable(db, pTab);
   }
 
   return rc;
@@ -222365,7 +222368,7 @@
 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
 
 /************** End of stmt.c ************************************************/
-#if __LINE__!=222368
+#if __LINE__!=222371
 #undef SQLITE_SOURCE_ID
 #define SQLITE_SOURCE_ID      "2019-04-16 19:49:53 884b4b7e502b4e991677b53971277adfaf0a04a284f8e483e2553d0f8315alt2"
 #endif
diff --git a/third_party/sqlite/patched/src/vacuum.c b/third_party/sqlite/patched/src/vacuum.c
index 4cf91f8d..3ec765d 100644
--- a/third_party/sqlite/patched/src/vacuum.c
+++ b/third_party/sqlite/patched/src/vacuum.c
@@ -106,6 +106,7 @@
   Vdbe *v = sqlite3GetVdbe(pParse);
   int iDb = 0;
   if( v==0 ) goto build_vacuum_end;
+  if( pParse->nErr ) goto build_vacuum_end;
   if( pNm ){
 #ifndef SQLITE_BUG_COMPATIBLE_20160819
     /* Default behavior:  Report an error if the argument to VACUUM is
diff --git a/third_party/sqlite/patched/src/vtab.c b/third_party/sqlite/patched/src/vtab.c
index 34ee6c5..a25c066 100644
--- a/third_party/sqlite/patched/src/vtab.c
+++ b/third_party/sqlite/patched/src/vtab.c
@@ -841,6 +841,7 @@
     p = vtabDisconnectAll(db, pTab);
     xDestroy = p->pMod->pModule->xDestroy;
     assert( xDestroy!=0 );  /* Checked before the virtual table is created */
+    pTab->nTabRef++;
     rc = xDestroy(p->pVtab);
     /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
     if( rc==SQLITE_OK ){
@@ -849,6 +850,7 @@
       pTab->pVTable = 0;
       sqlite3VtabUnlock(p);
     }
+    sqlite3DeleteTable(db, pTab);
   }
 
   return rc;
diff --git a/third_party/sqlite/patched/test/fts4rename.test b/third_party/sqlite/patched/test/fts4rename.test
new file mode 100644
index 0000000..289ede9
--- /dev/null
+++ b/third_party/sqlite/patched/test/fts4rename.test
@@ -0,0 +1,43 @@
+ 2019 April 30
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#*************************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/fts3_common.tcl
+set ::testprefix fts4rename
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+  finish_test
+  return
+}
+
+do_execsql_test 1.0 {
+  CREATE VIRTUAL TABLE temp.t1 USING fts3(a);
+  BEGIN;
+  CREATE TABLE t2(x);
+} {}
+
+do_catchsql_test 1.1 {
+  ALTER TABLE t1_content RENAME c0a TO docid;
+} {1 {duplicate column name: docid}}
+
+do_catchsql_test 1.2 {
+  UPDATE t1 SET Col0 = 1 ;
+} {1 {no such column: Col0}}
+
+do_catchsql_test 1.3 {
+  ROLLBACK;
+  DROP TABLE t1;
+} {0 {}}
+
+finish_test
diff --git a/third_party/sqlite/patches/0001-Virtual-table-supporting-recovery-of-corrupted-datab.patch b/third_party/sqlite/patches/0001-Virtual-table-supporting-recovery-of-corrupted-datab.patch
index 4e8f9b6d..74daf68b 100644
--- a/third_party/sqlite/patches/0001-Virtual-table-supporting-recovery-of-corrupted-datab.patch
+++ b/third_party/sqlite/patches/0001-Virtual-table-supporting-recovery-of-corrupted-datab.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Scott Hess <shess@chromium.org>
 Date: Sat, 20 Jul 2013 11:42:21 -0700
-Subject: [PATCH 1/2] Virtual table supporting recovery of corrupted databases.
+Subject: [PATCH 1/4] Virtual table supporting recovery of corrupted databases.
 
 "recover" implements a virtual table which uses the SQLite pager layer
 to read table pages and pull out the data which is structurally sound
@@ -3900,5 +3900,5 @@
 +
 +finish_test
 -- 
-2.21.0
+2.21.0.1020.gf2820cf01a-goog
 
diff --git a/third_party/sqlite/patches/0002-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch b/third_party/sqlite/patches/0002-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
index 3187dca..5ee7e840 100644
--- a/third_party/sqlite/patches/0002-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
+++ b/third_party/sqlite/patches/0002-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: "tc@google.com" <tc@google.com>
 Date: Tue, 6 Jan 2009 22:39:41 +0000
-Subject: [PATCH 2/2] Custom shell.c helpers to load Chromium's ICU data.
+Subject: [PATCH 2/4] Custom shell.c helpers to load Chromium's ICU data.
 
 History uses fts3 with an icu-based segmenter.  These changes allow building a
 sqlite3 binary for Linux or Windows which can read those files.
@@ -141,5 +141,5 @@
 +  return 1;
 +}
 -- 
-2.21.0
+2.21.0.1020.gf2820cf01a-goog
 
diff --git a/third_party/sqlite/patches/0003-Don-t-generate-VDBE-code-for-VACUUM-after-a-syntax-e.patch b/third_party/sqlite/patches/0003-Don-t-generate-VDBE-code-for-VACUUM-after-a-syntax-e.patch
new file mode 100644
index 0000000..dd4d18ea
--- /dev/null
+++ b/third_party/sqlite/patches/0003-Don-t-generate-VDBE-code-for-VACUUM-after-a-syntax-e.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Darwin Huang <huangdarwin@chromium.org>
+Date: Wed, 1 May 2019 14:44:32 -0700
+Subject: [PATCH 3/4] Don't generate VDBE code for VACUUM after a syntax error
+
+This backports https://www.sqlite.org/src/info/930842470da27d72
+
+Bug: https://crbug.com/954777
+---
+ third_party/sqlite/patched/src/vacuum.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/third_party/sqlite/patched/src/vacuum.c b/third_party/sqlite/patched/src/vacuum.c
+index 4cf91f8d0ada..3ec765df8a49 100644
+--- a/third_party/sqlite/patched/src/vacuum.c
++++ b/third_party/sqlite/patched/src/vacuum.c
+@@ -106,6 +106,7 @@ void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
+   Vdbe *v = sqlite3GetVdbe(pParse);
+   int iDb = 0;
+   if( v==0 ) goto build_vacuum_end;
++  if( pParse->nErr ) goto build_vacuum_end;
+   if( pNm ){
+ #ifndef SQLITE_BUG_COMPATIBLE_20160819
+     /* Default behavior:  Report an error if the argument to VACUUM is
+-- 
+2.21.0.1020.gf2820cf01a-goog
+
diff --git a/third_party/sqlite/patches/0004-Fix-use-after-free-xDestroy-error.patch b/third_party/sqlite/patches/0004-Fix-use-after-free-xDestroy-error.patch
new file mode 100644
index 0000000..83387ed
--- /dev/null
+++ b/third_party/sqlite/patches/0004-Fix-use-after-free-xDestroy-error.patch
@@ -0,0 +1,86 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Darwin Huang <huangdarwin@chromium.org>
+Date: Wed, 1 May 2019 14:47:06 -0700
+Subject: [PATCH 4/4] Fix use-after-free xDestroy error
+
+This backports https://www.sqlite.org/src/info/1dbbb0101e8213b9
+
+Bug: https://crbug.com/956851
+---
+ third_party/sqlite/patched/src/vtab.c         |  2 +
+ .../sqlite/patched/test/fts4rename.test       | 43 +++++++++++++++++++
+ 2 files changed, 45 insertions(+)
+ create mode 100644 third_party/sqlite/patched/test/fts4rename.test
+
+diff --git a/third_party/sqlite/patched/src/vtab.c b/third_party/sqlite/patched/src/vtab.c
+index 34ee6c5554e9..a25c06653666 100644
+--- a/third_party/sqlite/patched/src/vtab.c
++++ b/third_party/sqlite/patched/src/vtab.c
+@@ -841,6 +841,7 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
+     p = vtabDisconnectAll(db, pTab);
+     xDestroy = p->pMod->pModule->xDestroy;
+     assert( xDestroy!=0 );  /* Checked before the virtual table is created */
++    pTab->nTabRef++;
+     rc = xDestroy(p->pVtab);
+     /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
+     if( rc==SQLITE_OK ){
+@@ -849,6 +850,7 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
+       pTab->pVTable = 0;
+       sqlite3VtabUnlock(p);
+     }
++    sqlite3DeleteTable(db, pTab);
+   }
+ 
+   return rc;
+diff --git a/third_party/sqlite/patched/test/fts4rename.test b/third_party/sqlite/patched/test/fts4rename.test
+new file mode 100644
+index 000000000000..289ede9bfe73
+--- /dev/null
++++ b/third_party/sqlite/patched/test/fts4rename.test
+@@ -0,0 +1,43 @@
++ 2019 April 30
++#
++# The author disclaims copyright to this source code.  In place of
++# a legal notice, here is a blessing:
++#
++#    May you do good and not evil.
++#    May you find forgiveness for yourself and forgive others.
++#    May you share freely, never taking more than you give.
++#
++#*************************************************************************
++#
++
++set testdir [file dirname $argv0]
++source $testdir/tester.tcl
++source $testdir/fts3_common.tcl
++set ::testprefix fts4rename
++
++# If SQLITE_ENABLE_FTS3 is defined, omit this file.
++ifcapable !fts3 {
++  finish_test
++  return
++}
++
++do_execsql_test 1.0 {
++  CREATE VIRTUAL TABLE temp.t1 USING fts3(a);
++  BEGIN;
++  CREATE TABLE t2(x);
++} {}
++
++do_catchsql_test 1.1 {
++  ALTER TABLE t1_content RENAME c0a TO docid;
++} {1 {duplicate column name: docid}}
++
++do_catchsql_test 1.2 {
++  UPDATE t1 SET Col0 = 1 ;
++} {1 {no such column: Col0}}
++
++do_catchsql_test 1.3 {
++  ROLLBACK;
++  DROP TABLE t1;
++} {0 {}}
++
++finish_test
+-- 
+2.21.0.1020.gf2820cf01a-goog
+
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py
index 09cc0aa..2a5f6ab4 100644
--- a/tools/chrome_proxy/webdriver/common.py
+++ b/tools/chrome_proxy/webdriver/common.py
@@ -318,10 +318,12 @@
         chrome_options.add_experimental_option('mobileEmulation',
           {'deviceName': 'Pixel 2'})
 
-    self._chrome_args.add(
-      '--enable-features=%s' % ','.join(self._enable_features))
-    self._chrome_args.add(
-      '--disable-features=%s' % ','.join(self._disable_features))
+    if len(self._enable_features) > 0:
+      self._chrome_args.add(
+        '--enable-features=%s' % ','.join(self._enable_features))
+    if len(self._disable_features) > 0:
+      self._chrome_args.add(
+        '--disable-features=%s' % ','.join(self._disable_features))
     for arg in self._chrome_args:
       chrome_options.add_argument(arg)
     self._logger.info('Starting Chrome with these flags: %s',
@@ -599,6 +601,21 @@
     self._logger.debug('Got %s histogram=%s', histogram, string_response)
     return json.loads(string_response)
 
+  def GetBrowserHistogram(self, histogram, timeout=30):
+    """Gets a Chrome histogram as a dictionary object from browser process.
+
+    Args:
+      histogram: the name of the histogram to fetch
+      timeout: timeout for the underlying Javascript query.
+
+    Returns:
+      A dictionary object containing information about the histogram.
+    """
+    js_query = 'statsCollectionController.getBrowserHistogram("%s")' % histogram
+    string_response = self.ExecuteJavascriptStatement(js_query, timeout)
+    self._logger.debug('Got %s histogram=%s', histogram, string_response)
+    return json.loads(string_response)
+
   def WaitForJavascriptExpression(self, expression, timeout, min_poll=0.1,
       max_poll=1):
     """Waits for the given Javascript expression to evaluate to True within the
@@ -635,6 +652,7 @@
     if self._driver:
       self._StopDriver()
       # Give a moment for Chrome to close and finish writing the netlog.
+      time.sleep(5)
     if not self._net_log:
       raise Exception('GetParsedNetLog() cannot be called before UseNetLog()')
     temp_file = self._net_log
@@ -688,19 +706,18 @@
 
     Args:
       histogram_name: The name of the histogram to wait for
-      sleep_intervals: The number of polling intervals, each polling cycle takes
-      no more than 6 seconds.
+      sleep_intervals: The number of polling intervals, each polling cycle is 1s
     Returns:
       Whether the histogram exists
     """
-    histogram = {}
-    while(not histogram and sleep_intervals > 0):
-      histogram = self.GetHistogram(histogram_name, 5)
-      if (not histogram):
-        time.sleep(1)
-        sleep_intervals -= 1
+    while (sleep_intervals > 0):
+      if (self.GetHistogram(histogram_name, 3) or
+          self.GetBrowserHistogram(histogram_name, 3)):
+        return True
+      time.sleep(1)
+      sleep_intervals -= 1
 
-    return bool(histogram)
+    return False
 
   def GetHTTPResponses(self, include_favicon=False, skip_domainless_pages=True,
       override_has_logs=False):
@@ -933,8 +950,10 @@
     infobar_histogram_name = 'Previews.InfoBarAction.%s' % preview_type
     android_histogram_name = 'Previews.OmniboxAction.%s' % preview_type
 
-    infobar_histogram = test_driver.GetHistogram(infobar_histogram_name, 5)
-    android_histogram = test_driver.GetHistogram(android_histogram_name, 5)
+    infobar_histogram = test_driver.GetBrowserHistogram(
+      infobar_histogram_name, 5)
+    android_histogram = test_driver.GetBrowserHistogram(
+      android_histogram_name, 5)
 
     count = (infobar_histogram.get('count', 0)
              + android_histogram.get('count', 0))
diff --git a/tools/chrome_proxy/webdriver/fallback.py b/tools/chrome_proxy/webdriver/fallback.py
index b4b11212..c50d266 100644
--- a/tools/chrome_proxy/webdriver/fallback.py
+++ b/tools/chrome_proxy/webdriver/fallback.py
@@ -34,7 +34,7 @@
       self.assertNotEqual(0, len(responses))
       # Verify that DataReductionProxy.ProbeURL histogram has one entry in
       # FAILED_PROXY_DISABLED, which is bucket=1.
-      histogram = test_driver.GetHistogram('DataReductionProxy.ProbeURL')
+      histogram = test_driver.GetBrowserHistogram('DataReductionProxy.ProbeURL')
       self.assertEqual(histogram['count'], 1)
       self.assertEqual(histogram['buckets'][0]['low'], 1)
       for response in responses:
diff --git a/tools/chrome_proxy/webdriver/https_previews.py b/tools/chrome_proxy/webdriver/https_previews.py
index d8a1d03..db756d0 100644
--- a/tools/chrome_proxy/webdriver/https_previews.py
+++ b/tools/chrome_proxy/webdriver/https_previews.py
@@ -34,6 +34,10 @@
     t.EnableChromeFeature('Previews')
     t.EnableChromeFeature('LitePageServerPreviews')
 
+    # RLH and NoScript may disable use of LitePageRedirect Previews.
+    t.DisableChromeFeature('ResourceLoadingHints')
+    t.DisableChromeFeature('NoScriptPreviews')
+
     if version == NAV_THROTTLE_VERSION:
       # No additional flags here, but explicitly check it given the else below.
       pass
@@ -44,16 +48,11 @@
 
     t.AddChromeArg('--enable-spdy-proxy-auth')
     t.AddChromeArg('--dont-require-litepage-redirect-infobar')
-    t.AddChromeArg('--ignore-previews-blocklist')
+    t.AddChromeArg('--ignore-previews-blacklist')
     t.AddChromeArg('--force-effective-connection-type=2G')
     t.AddChromeArg('--ignore-litepage-redirect-optimization-blacklist')
     t.SetExperiment('external_chrome_integration_test')
 
-    # Start Chrome and wait for initialization.
-    t.LoadURL('data:,')
-    t.SleepUntilHistogramHasEntry(
-        'DataReductionProxy.ConfigService.FetchResponseCode')
-
   def _AssertShowingLitePage(self, t, expectedText, expectedImages):
     """Asserts that Chrome has loaded a Lite Page from the litepages server.
 
@@ -103,7 +102,8 @@
         self.assertEqual(expectedStatus, response.status)
         html_responses += 1
 
-    bypass_count = t.GetHistogram('Previews.ServerLitePage.ServerResponse', 2)
+    bypass_count = t.GetBrowserHistogram(
+      'Previews.ServerLitePage.ServerResponse', 2)
     self.assertEqual(1, html_responses)
     self.assertEqual(expectedBypassCount, bypass_count['count'])
     self.assertPreviewNotShownViaHistogram(t, 'LitePageRedirect')
@@ -168,9 +168,9 @@
 
       t.SleepUntilHistogramHasEntry("DataReductionProxy.Pingback.Succeeded")
       # Verify one pingback attempt that was successful.
-      attempted = t.GetHistogram('DataReductionProxy.Pingback.Attempted')
+      attempted = t.GetBrowserHistogram('DataReductionProxy.Pingback.Attempted')
       self.assertEqual(1, attempted['count'])
-      succeeded = t.GetHistogram('DataReductionProxy.Pingback.Succeeded')
+      succeeded = t.GetBrowserHistogram('DataReductionProxy.Pingback.Succeeded')
       self.assertEqual(1, succeeded['count'])
 
   # Verifies that a Lite Page is served when the main frame response is a
@@ -194,8 +194,8 @@
       # BadSSL onterstitials are not actually shown in webdriver tests (they
       # seem to be clicked through automatically). This histogram is incremented
       # after an interstitial has been clicked.
-      histogram = t.GetHistogram('interstitial.ssl.visited_site_after_warning',
-                                 1)
+      histogram = t.GetBrowserHistogram(
+        'interstitial.ssl.visited_site_after_warning', 1)
       self.assertEqual(1, histogram['count'])
 
   # Verifies that a safebrowsing interstitial is shown (instead of a Lite Page)
@@ -210,7 +210,7 @@
         t.LoadURL('https://testsafebrowsing.appspot.com/s/malware.html')
         self.fail('expected timeout')
       except TimeoutException:
-        histogram = t.GetHistogram('SB2.ResourceTypes2.Unsafe')
+        histogram = t.GetBrowserHistogram('SB2.ResourceTypes2.Unsafe')
         self.assertEqual(1, histogram['count'])
 
 
@@ -241,7 +241,11 @@
       # Collect IDs of expected reporting requests.
       report_request_id = []
       for event in events:
-        if not "params" in event or not "headers" in event["params"]:
+        if "params" not in event:
+          continue
+        if event.get("params") is None:
+          continue
+        if "headers" not in event.get("params"):
           continue
 
         header = event["params"]["headers"]
diff --git a/tools/chrome_proxy/webdriver/lite_page.py b/tools/chrome_proxy/webdriver/lite_page.py
index 4cdc384..4c90731 100644
--- a/tools/chrome_proxy/webdriver/lite_page.py
+++ b/tools/chrome_proxy/webdriver/lite_page.py
@@ -27,21 +27,11 @@
         in common.ParseFlags().browser_args):
       self.skipTest('This test cannot be run with other experiments.')
     with TestDriver() as test_driver:
-      test_driver.AddChromeArg('--enable-spdy-proxy-auth')
-      test_driver.EnableChromeFeature(
-        'NetworkQualityEstimator<NetworkQualityEstimator')
       test_driver.EnableChromeFeature('Previews')
       test_driver.EnableChromeFeature('DataReductionProxyDecidesTransform')
-      test_driver.AddChromeArg(
-          '--force-fieldtrial-params=NetworkQualityEstimator.Enabled:'
-          'force_effective_connection_type/2G,'
-          'DataReductionProxyServerExperiments.IgnoreCountryBlacklist:'
-          'exp/ignore_preview_blacklist')
-      # The previous argument implicitly sets the experiment.
-      test_driver.SetExperiment(None)
-      test_driver.AddChromeArg(
-          '--force-fieldtrials=NetworkQualityEstimator/Enabled/'
-          'DataReductionProxyServerExperiments/IgnoreCountryBlacklist')
+      test_driver.SetExperiment('ignore_preview_blacklist')
+      test_driver.AddChromeArg('--enable-spdy-proxy-auth')
+      test_driver.AddChromeArg('--force-effective-connection-type=2G')
 
       test_driver.LoadURL('http://check.googlezip.net/test.html')
 
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index 972a83ac..29e2345 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -768,7 +768,7 @@
                fuchsia_lib_dst_dir)
 
   # Run tests.
-  if args.run_tests or args.force_head_revision:
+  if args.run_tests or args.llvm_force_head_revision:
     os.chdir(LLVM_BUILD_DIR)
     RunCommand(['ninja', 'cr-check-all'], msvc_arch='x64')
   if args.run_tests:
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index a1610f3..30f7e24 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -145,6 +145,9 @@
   "chrome/browser/vr/testapp/vr_testapp_resources.grd": {
     "includes": [13990],
   },
+  "chrome/browser/resources/kiosk_next_internal_resources.grd": {
+    "includes": [14040],
+  },
   # END chrome/browser section.
 
   # START chrome/ miscellaneous section.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 5a2c406..a796f52 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -9912,30 +9912,91 @@
   <int value="1094926916" label="ACBD (Sand)"/>
   <int value="1094926917" label="ACBE (Santa)"/>
   <int value="1094926918" label="ACBF (Bruce)"/>
+  <int value="1094993739" label="ADGK (Laser14)"/>
+  <int value="1095520840" label="ALRH (Sion)"/>
+  <int value="1095716933" label="AOPE (Jax)"/>
+  <int value="1095784537" label="APXY (Wukong)"/>
   <int value="1095909961" label="ARBI (Soraka)"/>
   <int value="1095980364" label="ASUL (Cave)"/>
   <int value="1095980366" label="ASUN (Basking)"/>
   <int value="1095980367" label="ASUO (Bob)"/>
+  <int value="1111707468" label="BCOL (Ampton)"/>
+  <int value="1111771479" label="BDIW (Sparky360)"/>
+  <int value="1128420697" label="CBUY (Pantheon)"/>
+  <int value="1129075526" label="CLSF (Alan)"/>
   <int value="1129336916" label="CPPT (Nasher)"/>
   <int value="1129597253" label="CTIE (Astronaut)"/>
+  <int value="1129927505" label="CYSQ (Phaser360)"/>
+  <int value="1145193796" label="DBED (Wukong)"/>
   <int value="1145389384" label="DEAH (Asuka)"/>
   <int value="1146640980" label="DXZT (Scarlet)"/>
+  <int value="1162826827" label="EOTK (Wukong)"/>
+  <int value="1178752080" label="FBTP (Blacktip360)"/>
+  <int value="1179734090" label="FQPJ (Karma)"/>
+  <int value="1179736649" label="FQZI (Bigdaddy)"/>
+  <int value="1179862873" label="FSGY (Meep)"/>
+  <int value="1180128843" label="FWVK (Bobba360)"/>
+  <int value="1196055126" label="GJZV (Syndra)"/>
+  <int value="1196378965" label="GOKU (Babymega)"/>
+  <int value="1212568135" label="HFRG (Sona)"/>
+  <int value="1212699214" label="HHRN (Careena)"/>
+  <int value="1213156680" label="HOMH (Sparky)"/>
+  <int value="1213159245" label="HOWM (Nospike)"/>
   <int value="1213225551" label="HPZO (Snappy)"/>
   <int value="1213225554" label="HPZR (Chell)"/>
   <int value="1213352282" label="HRIZ (Whitetip)"/>
+  <int value="1229478471" label="IHZG (Mimrock)"/>
   <int value="1229870420" label="INUT (Nasher360)"/>
+  <int value="1230326865" label="IULQ (Whitetip)"/>
+  <int value="1246124610" label="JFZB (Liara)"/>
+  <int value="1247369291" label="JYXK (Bluebird)"/>
   <int value="1262568010" label="KABJ (Robo360)"/>
+  <int value="1263291223" label="KLKW (Fleex)"/>
+  <int value="1279349582" label="LASN (Phaser)"/>
   <int value="1279607114" label="LEAJ (Sentry)"/>
   <int value="1279607118" label="LEAN (Pyro)"/>
   <int value="1280264001" label="LOGA (Gru)"/>
   <int value="1280264007" label="LOGG (Poppy)"/>
+  <int value="1280264008" label="LOGH (Whitetip)"/>
+  <int value="1296254030" label="MCDN (Dumo)"/>
+  <int value="1296256847" label="MCOO (Sarien)"/>
+  <int value="1297634649" label="MXUY (Aleena)"/>
+  <int value="1312969043" label="NBQS (Nocturne)"/>
+  <int value="1313819972" label="NOMD (Shyvana)"/>
+  <int value="1313883459" label="NPEC (Vayne)"/>
   <int value="1314212940" label="NULL (not yet assigned)"/>
+  <int value="1330008133" label="OFPE (Kasumi360)"/>
+  <int value="1346851142" label="PGQF (Grabbiter)"/>
+  <int value="1346918722" label="PHYB (Teemo)"/>
+  <int value="1347961935" label="PXDO (Barla)"/>
   <int value="1364874584" label="QZUX (Robo)"/>
+  <int value="1380535111" label="RIKG (Blacktip)"/>
+  <int value="1381388877" label="RVRM (Abra)"/>
   <int value="1397244238" label="SHAN (Lava)"/>
   <int value="1397571914" label="SMAJ (Kevin)"/>
+  <int value="1397571916" label="SMAL (NautilusLTE)"/>
+  <int value="1397703489" label="SOCA (Akali360)"/>
+  <int value="1413829460" label="TEST (testing label)"/>
+  <int value="1414219090" label="TKER (Orbatrix)"/>
+  <int value="1414353733" label="TMSE (Wukong)"/>
+  <int value="1414547534" label="TPHN (Whitetip)"/>
+  <int value="1414943322" label="TVRZ (Blacktip360)"/>
+  <int value="1430733145" label="UGAY (Kasumi)"/>
+  <int value="1431460420" label="URZD (Whitetip)"/>
+  <int value="1447581000" label="VHUH (Bobba)"/>
   <int value="1448498499" label="VVUC (blue)"/>
+  <int value="1464686165" label="WMVU (Epaulette)"/>
+  <int value="1465408071" label="WXZG (Blacktip)"/>
+  <int value="1482053969" label="XVYQ (Apel)"/>
+  <int value="1482115653" label="XWJE (atlas)"/>
+  <int value="1497913685" label="YHYU (Arcada)"/>
+  <int value="1498238293" label="YMMU (DruWL)"/>
+  <int value="1498432325" label="YPCE (Rabbid)"/>
+  <int value="1498956363" label="YXBK (Kench)"/>
+  <int value="1498957124" label="YXED (Babytiger)"/>
   <int value="1515408205" label="ZSKM (Nautilus)"/>
   <int value="1515864390" label="ZZAF (Eve)"/>
+  <int value="1515864914" label="ZZCR (Early prod samples)"/>
 </enum>
 
 <enum name="CrashExitCodes">
@@ -22387,7 +22448,7 @@
   <int value="2324" label="InputTypeFileSecureOriginOpenChooser"/>
   <int value="2325" label="InputTypeFileInsecureOriginOpenChooser"/>
   <int value="2326" label="BasicShapeEllipseNoRadius"/>
-  <int value="2327" label="BasicShapeEllipseOneRadius"/>
+  <int value="2327" label="OBSOLETE_BasicShapeEllipseOneRadius"/>
   <int value="2328" label="BasicShapeEllipseTwoRadius"/>
   <int value="2329" label="TemporalInputTypeChooserByTrustedClick"/>
   <int value="2330" label="TemporalInputTypeChooserByUntrustedClick"/>
@@ -24386,6 +24447,79 @@
   <int value="642" label="NSFileWriteVolumeReadOnlyError"/>
 </enum>
 
+<enum name="FoundationPopularErrorCode">
+  <int value="-3007" label="NSURLErrorDownloadDecodingFailedToComplete"/>
+  <int value="-3006" label="NSURLErrorDownloadDecodingFailedMidStream"/>
+  <int value="-3005" label="NSURLErrorCannotMoveFile"/>
+  <int value="-3004" label="NSURLErrorCannotRemoveFile"/>
+  <int value="-3003" label="NSURLErrorCannotWriteToFile"/>
+  <int value="-3002" label="NSURLErrorCannotCloseFile"/>
+  <int value="-3001" label="NSURLErrorCannotOpenFile"/>
+  <int value="-3000" label="NSURLErrorCannotCreateFile"/>
+  <int value="-2000" label="NSURLErrorCannotLoadFromNetwork"/>
+  <int value="-1206" label="NSURLErrorClientCertificateRequired"/>
+  <int value="-1205" label="NSURLErrorClientCertificateRejected"/>
+  <int value="-1204" label="NSURLErrorServerCertificateNotYetValid"/>
+  <int value="-1203" label="NSURLErrorServerCertificateHasUnknownRoot"/>
+  <int value="-1202" label="NSURLErrorServerCertificateUntrusted"/>
+  <int value="-1201" label="NSURLErrorServerCertificateHasBadDate"/>
+  <int value="-1200" label="NSURLErrorSecureConnectionFailed"/>
+  <int value="-1104" label="NSURLErrorFileOutsideSafeArea"/>
+  <int value="-1103" label="NSURLErrorDataLengthExceedsMaximum"/>
+  <int value="-1102" label="NSURLErrorNoPermissionsToReadFile"/>
+  <int value="-1101" label="NSURLErrorFileIsDirectory"/>
+  <int value="-1100" label="NSURLErrorFileDoesNotExist"/>
+  <int value="-1022"
+      label="NSURLErrorAppTransportSecurityRequiresSecureConnection"/>
+  <int value="-1021" label="NSURLErrorRequestBodyStreamExhausted"/>
+  <int value="-1020" label="NSURLErrorDataNotAllowed"/>
+  <int value="-1019" label="NSURLErrorCallIsActive"/>
+  <int value="-1018" label="NSURLErrorInternationalRoamingOff"/>
+  <int value="-1017" label="NSURLErrorCannotParseResponse"/>
+  <int value="-1016" label="NSURLErrorCannotDecodeContentData"/>
+  <int value="-1015" label="NSURLErrorCannotDecodeRawData"/>
+  <int value="-1014" label="NSURLErrorZeroByteResource"/>
+  <int value="-1013" label="NSURLErrorUserAuthenticationRequired"/>
+  <int value="-1012" label="NSURLErrorUserCancelledAuthentication"/>
+  <int value="-1011" label="NSURLErrorBadServerResponse"/>
+  <int value="-1010" label="NSURLErrorRedirectToNonExistentLocation"/>
+  <int value="-1009" label="NSURLErrorNotConnectedToInternet"/>
+  <int value="-1008" label="NSURLErrorResourceUnavailable"/>
+  <int value="-1007" label="NSURLErrorHTTPTooManyRedirects"/>
+  <int value="-1006" label="NSURLErrorDNSLookupFailed"/>
+  <int value="-1005" label="NSURLErrorNetworkConnectionLost"/>
+  <int value="-1004" label="NSURLErrorCannotConnectToHost"/>
+  <int value="-1003" label="NSURLErrorCannotFindHost"/>
+  <int value="-1002" label="NSURLErrorUnsupportedURL"/>
+  <int value="-1001" label="NSURLErrorTimedOut"/>
+  <int value="-1000" label="NSURLErrorBadURL"/>
+  <int value="-999" label="NSURLErrorCancelled"/>
+  <int value="-997" label="NSURLErrorBackgroundSessionWasDisconnected"/>
+  <int value="-996" label="NSURLErrorBackgroundSessionInUseByAnotherProcess"/>
+  <int value="-995" label="NSURLErrorBackgroundSessionRequiresSharedContainer"/>
+  <int value="-1" label="NSURLErrorUnknown"/>
+  <int value="0" label="NSNoError"/>
+  <int value="4" label="NSFileNoSuchFileError"/>
+  <int value="255" label="NSFileLockingError"/>
+  <int value="256" label="NSFileReadUnknownError"/>
+  <int value="257" label="NSFileReadNoPermissionError"/>
+  <int value="258" label="NSFileReadInvalidFileNameError"/>
+  <int value="259" label="NSFileReadCorruptFileError"/>
+  <int value="260" label="NSFileReadNoSuchFileError"/>
+  <int value="261" label="NSFileReadInapplicableStringEncodingError"/>
+  <int value="262" label="NSFileReadUnsupportedSchemeError"/>
+  <int value="263" label="NSFileReadTooLargeError"/>
+  <int value="264" label="NSFileReadUnknownStringEncodingError"/>
+  <int value="512" label="NSFileWriteUnknownError"/>
+  <int value="513" label="NSFileWriteNoPermissionError"/>
+  <int value="514" label="NSFileWriteInvalidFileNameError"/>
+  <int value="516" label="NSFileWriteFileExistsError"/>
+  <int value="517" label="NSFileWriteInapplicableStringEncodingError"/>
+  <int value="518" label="NSFileWriteUnsupportedSchemeError"/>
+  <int value="640" label="NSFileWriteOutOfSpaceError"/>
+  <int value="642" label="NSFileWriteVolumeReadOnlyError"/>
+</enum>
+
 <enum name="FramebustInterventionOutcome">
   <int value="0" label="Accepted"/>
   <int value="1" label="Declined and navigated"/>
@@ -34274,6 +34408,7 @@
   <int value="846951416" label="CopylessPaste:enabled"/>
   <int value="848324390" label="enable-lock-screen-apps"/>
   <int value="849980462" label="RemoveNtpFakebox:disabled"/>
+  <int value="850779988" label="allow-popups-during-page-unload"/>
   <int value="851085848" label="enable-settings-window"/>
   <int value="851616920" label="EnableTLS13EarlyData:disabled"/>
   <int value="852313529" label="RTCUnifiedPlanByDefault:disabled"/>
@@ -55383,6 +55518,7 @@
   <int value="91664959" label="CROS Cr50 0.0.16"/>
   <int value="113099773" label="CROS Cr50 0.0.23 Eve Flags 0x7f00(prod)"/>
   <int value="157181839" label="IFX 9655 rev 41 fw 4.34 build 03f2"/>
+  <int value="228456405" label="CROS Cr50 0.3.11"/>
   <int value="230386903" label="CROS Cr50 0.0.24 Eve Flags 0x7f00(prod)"/>
   <int value="276176597" label="CROS Cr50 0.1.0 Flags 0x10(pre-pvt)"/>
   <int value="305524852" label="IFX 9655 rev 41 fw 4.32 build 036f"/>
@@ -55399,25 +55535,35 @@
   <int value="847042924" label="IFX 9645 rev 78 fw 133.33 build 00e3"/>
   <int value="893364096" label="CROS Cr50 0.3.3"/>
   <int value="928190862" label="CROS Cr50 0.0.17"/>
+  <int value="969849518" label="CROS Cr50 0.4.9 Flags 0x10(pre-pvt)"/>
   <int value="987235505" label="CROS Cr50 0.0.20"/>
   <int value="987973414" label="IFX 9670 rev 15 fw 6.40 build 00be"/>
+  <int value="1001367086" label="CROS Cr50 0.3.15"/>
   <int value="1013730596" label="CROS Cr50 0.0.26 Flags 0x10(pre-pvt)"/>
+  <int value="1039624416" label="CROS Cr50 0.3.10"/>
   <int value="1065916186" label="CROS Cr50 0.0.19"/>
   <int value="1123680979" label="CROS Cr50 0.3.4"/>
   <int value="1190683265" label="CROS Cr50 0.0.14"/>
+  <int value="1290177221" label="CROS Cr50 0.4.6 Flags 0x10(pre-pvt)"/>
   <int value="1311411160" label="WEC 345"/>
   <int value="1353576267" label="IFX 9635 fw 3.18 build 0009"/>
+  <int value="1395572841" label="CROS Cr50 0.4.15 Flags 0x10(pre-pvt)"/>
   <int value="1437720528" label="IFX 9645 rev 78 fw 133.32 build 0050"/>
   <int value="1451134301" label="IFX 9635 147.18 build 000f"/>
   <int value="1490841853" label="IFX 9645 rev 49 fw 133.32 build 0050"/>
+  <int value="1521866659" label="CROS Cr50 0.4.13 Flags 0x10(pre-pvt)"/>
+  <int value="1607230944" label="CROS Cr50 0.4.5 Flags 0x10(pre-pvt)"/>
   <int value="1632371059" label="CROS Cr50 0.0.22"/>
   <int value="1716634300" label="IFX 9645 rev 45 fw 133.32 build 0050"/>
+  <int value="1717226620" label="CROS Cr50 0.4.14 Flags 0x10(pre-pvt)"/>
   <int value="1733077393" label="IFX 9645 rev 49 fw 133.33 build 00e3"/>
   <int value="1774347833" label="CROS Cr50 0.0.15"/>
   <int value="1828625721" label="IFX 9655 rev 32 fw 4.31 build 02c2"/>
+  <int value="1848357394" label="CROS Cr50 0.4.11 Flags 0x10(pre-pvt)"/>
   <int value="1861735666" label="CROS Cr50 0.2.1 Flags 0x10(pre-pvt)"/>
   <int value="1865292977" label="CROS Cr50 0.0.24 aka 0.3.0"/>
   <int value="1887455524" label="CROS Cr50 0.0.21"/>
+  <int value="1903933708" label="CROS Cr50 0.4.3 Flags 0x10(pre-pvt)"/>
   <int value="1941011596" label="IFX 9655 rev 35 fw 4.34 build 03f2"/>
   <int value="1953654937" label="IFX 9645 rev 45 fw 133.33 build 00e3"/>
   <int value="2024714959" label="IFX 9655 rev 32 fw 4.34 build 03f2"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 20fdf4d..85b9aec 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -20892,6 +20892,15 @@
   </summary>
 </histogram>
 
+<histogram name="CrashReport.BreakpadIOSUploadOutcome"
+    enum="FoundationPopularErrorCode">
+  <owner>olivierrobin@chromium.org</owner>
+  <summary>
+    Reports the Foundation error code of an attempt to upload a breakpad crash
+    report. &quot;NSNoError&quot; if the upload was successful.
+  </summary>
+</histogram>
+
 <histogram name="CrashReport.CrashBackgroundUploadDelay" units="ms"
     expires_after="2018-11-05">
   <obsolete>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 5d3478f..2eaeb96 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -164,10 +164,6 @@
 crbug.com/865400 [ Pixel_2 Android_Webview ] loading.mobile/VoiceMemos_cold_3g [ Skip ]
 crbug.com/919191 [ Nexus5X_Webview ] loading.mobile/OLX_3g [ Skip ]
 
-# Benchmark: media.desktop
-crbug.com/957977 [ Win ] media.desktop/video.html?src=crowd1080.mp4 [ Skip ]
-crbug.com/957977 [ Win ] media.desktop/video.html?src=crowd1080.webm [ Skip ]
-
 # Benchmark: oilpan_gc_times.key_silk_cases
 crbug.com/446332 [ All ] oilpan_gc_times.key_silk_cases/slide_drawer [ Skip ]
 crbug.com/507865 [ All ] oilpan_gc_times.key_silk_cases/polymer_topeka [ Skip ]
@@ -242,6 +238,7 @@
 crbug.com/911214 [ Win ] system_health.common_desktop/multitab:misc:typical24 [ Skip ]
 crbug.com/934270 [ Win ] system_health.common_desktop/multitab:misc:typical24:2018 [ Skip ]
 crbug.com/931185 [ Win_7 ] system_health.common_desktop/browse:media:youtubetv:2019 [ Skip ]
+crbug.com/958422 [ Win_7 ] system_health.common_desktop/browse:social:tumblr_infinite_scroll:2018 [ Skip ]
 
 # Benchmark: system_health.common_mobile
 crbug.com/914390 [ Nexus_5 ] system_health.common_mobile/browse:chrome:newtab [ Skip ]
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index ecf30ed..d1f31f3 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -325,16 +325,3 @@
 
   seed_corpus = "fuzz_corpus"
 }
-
-source_set("ax_host_manifest") {
-  sources = [
-    "ax_host_manifest.cc",
-    "ax_host_manifest.h",
-  ]
-
-  deps = [
-    "//base",
-    "//services/service_manager/public/cpp",
-    "//ui/accessibility/mojom",
-  ]
-}
diff --git a/ui/accessibility/OWNERS b/ui/accessibility/OWNERS
index c375e05..1b66e1d2 100644
--- a/ui/accessibility/OWNERS
+++ b/ui/accessibility/OWNERS
@@ -9,10 +9,5 @@
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 
-per-file ax_host_manifest.cc=set noparent
-per-file ax_host_manifest.cc=file://ipc/SECURITY_OWNERS
-per-file ax_host_manifest.h=set noparent
-per-file ax_host_manifest.h=file://ipc/SECURITY_OWNERS
-
 # TEAM: chromium-accessibility@chromium.org
 # COMPONENT: Internals>Accessibility
diff --git a/ui/accessibility/ax_host_manifest.cc b/ui/accessibility/ax_host_manifest.cc
deleted file mode 100644
index a189ced..0000000
--- a/ui/accessibility/ax_host_manifest.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/accessibility/ax_host_manifest.h"
-
-#include "base/no_destructor.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-#include "ui/accessibility/mojom/ax_host.mojom.h"
-
-namespace ui {
-
-const service_manager::Manifest& GetAXHostManifest() {
-  static base::NoDestructor<service_manager::Manifest> manifest{
-      service_manager::ManifestBuilder()
-          .WithServiceName(ax::mojom::kAXHostServiceName)
-          .WithDisplayName("Accessibility Host Service")
-          .WithOptions(service_manager::ManifestOptionsBuilder().Build())
-          .ExposeCapability(
-              "app",
-              service_manager::Manifest::InterfaceList<ax::mojom::AXHost>())
-          .Build()};
-  return *manifest;
-}
-
-}  // namespace ui
diff --git a/ui/accessibility/ax_host_manifest.h b/ui/accessibility/ax_host_manifest.h
deleted file mode 100644
index 335b983..0000000
--- a/ui/accessibility/ax_host_manifest.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_ACCESSIBILITY_AX_HOST_MANIFEST_H_
-#define UI_ACCESSIBILITY_AX_HOST_MANIFEST_H_
-
-#include "services/service_manager/public/cpp/manifest.h"
-
-namespace ui {
-
-const service_manager::Manifest& GetAXHostManifest();
-
-}  // namespace ui
-
-#endif  // UI_ACCESSIBILITY_AX_HOST_MANIFEST_H_
diff --git a/ui/accessibility/mojom/BUILD.gn b/ui/accessibility/mojom/BUILD.gn
index 1f67d5a..7f86d55f 100644
--- a/ui/accessibility/mojom/BUILD.gn
+++ b/ui/accessibility/mojom/BUILD.gn
@@ -9,7 +9,6 @@
     "ax_action_data.mojom",
     "ax_assistant_structure.mojom",
     "ax_event.mojom",
-    "ax_host.mojom",
     "ax_node_data.mojom",
     "ax_relative_bounds.mojom",
     "ax_tree_data.mojom",
diff --git a/ui/accessibility/mojom/ax_host.mojom b/ui/accessibility/mojom/ax_host.mojom
deleted file mode 100644
index 10c300b8..0000000
--- a/ui/accessibility/mojom/ax_host.mojom
+++ /dev/null
@@ -1,44 +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.
-
-module ax.mojom;
-
-import "ui/accessibility/ax_enums.mojom";
-import "ui/accessibility/mojom/ax_action_data.mojom";
-import "ui/accessibility/mojom/ax_event.mojom";
-import "ui/accessibility/mojom/ax_tree_id.mojom";
-import "ui/accessibility/mojom/ax_tree_update.mojom";
-
-const string kAXHostServiceName = "ax_host_service";
-
-// Accessibility host service for remote processes that use views UI. Not used
-// for web content, PDF, or ARC++.
-// * Receives accessibility node trees and events (e.g. focus changes) from the
-//   remote process. Forwards the events to accessibility extensions in the
-//   browser.
-// * Sends requests for actions (e.g. click a button) to the remote process.
-interface AXHost {
-  // Registers a host in a remote process. |tree_id| is the ID to use as the
-  // root of the AX node tree. If |automation_enabled| is true then the remote
-  // process must send its initial AX node tree immediately (because a feature
-  // like ChromeVox is enabled).
-  RegisterRemoteHost(AXRemoteHost remote) =>
-      (ax.mojom.AXTreeID tree_id, bool automation_enabled);
-
-  // Handles an accessibility |event| (e.g. focus change) for |tree_id| in the
-  // remote process. Includes |updates| to child nodes.
-  HandleAccessibilityEvent(
-      ax.mojom.AXTreeID tree_id, array<AXTreeUpdate> updates, AXEvent event);
-};
-
-// Remote hosts run outside the browser process, for example in a mojo app like
-// shortcut_viewer.
-interface AXRemoteHost {
-  // Remotes must send the initial accessibility tree when automation is
-  // enabled.
-  OnAutomationEnabled(bool enabled);
-
-  // Performs an accessibility action inside the remote app.
-  PerformAction(AXActionData data);
-};
diff --git a/ui/android/display_android_manager.cc b/ui/android/display_android_manager.cc
index 8509bd7b..53cd4aa 100644
--- a/ui/android/display_android_manager.cc
+++ b/ui/android/display_android_manager.cc
@@ -79,7 +79,7 @@
                                             int bitsPerComponent,
                                             bool isWideColorGamut) {
   if (!Display::HasForceDeviceScaleFactor())
-    display->set_device_scale_factor(dipScale);
+    display->SetDeviceScaleFactor(dipScale);
   if (!Display::HasForceDisplayColorProfile()) {
     if (isWideColorGamut) {
       display->set_color_space(gfx::ColorSpace::CreateDisplayP3D65());
diff --git a/ui/android/java/res/values-v17/styles.xml b/ui/android/java/res/values-v17/styles.xml
index 6a9e151a..863c97c8 100644
--- a/ui/android/java/res/values-v17/styles.xml
+++ b/ui/android/java/res/values-v17/styles.xml
@@ -193,6 +193,10 @@
     <style name="TextAppearance.Body.Inverse" parent="TextAppearance.WhiteBody" tools:ignore="UnusedResources">
         <item name="android:textColor">@color/default_text_color_inverse</item>
     </style>
+    <style name="TextAppearance.Title2.Inverse" parent="TextAppearance.WhiteTitle2"
+        tools:ignore="UnusedResources">
+        <item name="android:textColor">@color/default_text_color_inverse</item>
+    </style>
 
     <!-- Blue Text Styles -->
     <style name="TextAppearance.BlueTitle2" parent="TextAppearance.RobotoMediumStyle" tools:ignore="UnusedResources">
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 9fdcf7f3..9f5b0e6 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -28,7 +28,6 @@
 #include "ui/compositor/compositor_switches.h"
 #include "ui/compositor/dip_util.h"
 #include "ui/compositor/layer.h"
-#include "ui/display/display.h"
 #include "ui/display/screen.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/gfx/geometry/insets.h"
@@ -108,9 +107,7 @@
 }
 
 void WindowTreeHost::InitHost() {
-  display::Display display =
-      display::Screen::GetScreen()->GetDisplayNearestWindow(window());
-  device_scale_factor_ = display.device_scale_factor();
+  device_scale_factor_ = GetDisplay().device_scale_factor();
 
   UpdateRootWindowSizeInPixels();
   InitCompositor();
@@ -278,7 +275,7 @@
 }
 
 int64_t WindowTreeHost::GetDisplayId() {
-  return display::Screen::GetScreen()->GetDisplayNearestWindow(window()).id();
+  return GetDisplay().id();
 }
 
 void WindowTreeHost::Show() {
@@ -351,8 +348,11 @@
   if (!window_)
     window_ = new Window(nullptr);
   display::Screen::GetScreen()->AddObserver(this);
-  auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
-  device_scale_factor_ = display.device_scale_factor();
+  device_scale_factor_ = GetDisplay().device_scale_factor();
+}
+
+display::Display WindowTreeHost::GetDisplay() const {
+  return display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
 }
 
 void WindowTreeHost::IntializeDeviceScaleFactor(float device_scale_factor) {
@@ -379,7 +379,7 @@
   // ~Window, but by that time any calls to virtual methods overriden here (such
   // as GetRootWindow()) result in Window's implementation. By destroying here
   // we ensure GetRootWindow() still returns this.
-  //window()->RemoveOrDestroyChildren();
+  // window()->RemoveOrDestroyChildren();
 }
 
 void WindowTreeHost::CreateCompositor(
@@ -420,8 +420,7 @@
                                window()->GetLocalSurfaceIdAllocation());
   compositor_->SetRootLayer(window()->layer());
 
-  display::Display display =
-      display::Screen::GetScreen()->GetDisplayNearestWindow(window());
+  display::Display display = GetDisplay();
   compositor_->SetDisplayColorSpace(display.color_space(),
                                     display.sdr_white_level());
 }
@@ -446,9 +445,7 @@
     const viz::LocalSurfaceIdAllocation& new_local_surface_id_allocation) {
   // TODO(jonross) Unify all OnHostResizedInPixels to have both
   // viz::LocalSurfaceId and allocation time as optional parameters.
-  display::Display display =
-      display::Screen::GetScreen()->GetDisplayNearestWindow(window());
-  device_scale_factor_ = display.device_scale_factor();
+  device_scale_factor_ = GetDisplay().device_scale_factor();
   UpdateRootWindowSizeInPixels();
 
   // Allocate a new LocalSurfaceId for the new state.
@@ -479,8 +476,7 @@
 void WindowTreeHost::OnHostDisplayChanged() {
   if (!compositor_)
     return;
-  display::Display display =
-      display::Screen::GetScreen()->GetDisplayNearestWindow(window());
+  display::Display display = GetDisplay();
   compositor_->SetDisplayColorSpace(display.color_space(),
                                     display.sdr_white_level());
 }
@@ -535,11 +531,8 @@
   last_cursor_request_position_in_host_ = host_location;
   MoveCursorToScreenLocationInPixels(host_location);
   client::CursorClient* cursor_client = client::GetCursorClient(window());
-  if (cursor_client) {
-    const display::Display& display =
-        display::Screen::GetScreen()->GetDisplayNearestWindow(window());
-    cursor_client->SetDisplay(display);
-  }
+  if (cursor_client)
+    cursor_client->SetDisplay(GetDisplay());
   dispatcher()->OnCursorMovedToRootLocation(root_location);
 }
 
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index 70e3f69..9da1be8 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -24,6 +24,7 @@
 #include "ui/base/cursor/cursor.h"
 #include "ui/base/ime/input_method_delegate.h"
 #include "ui/compositor/compositor_observer.h"
+#include "ui/display/display.h"
 #include "ui/display/display_observer.h"
 #include "ui/events/event_source.h"
 #include "ui/events/platform_event.h"
@@ -34,7 +35,7 @@
 class Rect;
 class Size;
 class Transform;
-}
+}  // namespace gfx
 
 namespace ui {
 class Compositor;
@@ -43,7 +44,7 @@
 class InputMethod;
 class ViewProp;
 struct PlatformWindowInitProperties;
-}
+}  // namespace ui
 
 namespace aura {
 
@@ -256,6 +257,9 @@
 
   explicit WindowTreeHost(std::unique_ptr<Window> window = nullptr);
 
+  // Gets the display that this window tree host resides at.
+  display::Display GetDisplay() const;
+
   // Set the cached display device scale factor. This should only be called
   // during subclass initialization, when the value is needed before InitHost().
   void IntializeDeviceScaleFactor(float device_scale_factor);
diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc
index dbc486a..926c888 100644
--- a/ui/aura/window_tree_host_platform.cc
+++ b/ui/aura/window_tree_host_platform.cc
@@ -290,7 +290,6 @@
   widget_ = gfx::kNullAcceleratedWidget;
 }
 
-void WindowTreeHostPlatform::OnActivationChanged(bool active) {
-}
+void WindowTreeHostPlatform::OnActivationChanged(bool active) {}
 
 }  // namespace aura
diff --git a/ui/display/display.cc b/ui/display/display.cc
index 18cef1b9a..975e83c3 100644
--- a/ui/display/display.cc
+++ b/ui/display/display.cc
@@ -228,6 +228,12 @@
   return Display(kDefaultDisplayId, gfx::Rect(0, 0, 1920, 1080));
 }
 
+void Display::SetDeviceScaleFactor(float scale) {
+  if (HasForceDeviceScaleFactor())
+    return;
+  device_scale_factor_ = scale;
+}
+
 int Display::RotationAsDegree() const {
   switch (rotation_) {
     case ROTATE_0:
diff --git a/ui/display/display.h b/ui/display/display.h
index d38e37f..a3e1966 100644
--- a/ui/display/display.h
+++ b/ui/display/display.h
@@ -148,12 +148,12 @@
   const gfx::Rect& work_area() const { return work_area_; }
   void set_work_area(const gfx::Rect& work_area) { work_area_ = work_area; }
 
-  // Output device's pixel scale factor. This specifies how much the
-  // UI should be scaled when the actual output has more pixels than
-  // standard displays (which is around 100~120dpi.) The potential return
-  // values depend on each platforms.
+  // Pixel scale factor.  This specifies how much the UI should be scaled when
+  // rendering on the actual output.  This is needed when the latter has more
+  // pixels than standard displays (which is around 100~120dpi).  The potential
+  // return values depend on each platforms.
   float device_scale_factor() const { return device_scale_factor_; }
-  void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
+  void SetDeviceScaleFactor(float scale);
 
   Rotation rotation() const { return rotation_; }
   void set_rotation(Rotation rotation) { rotation_ = rotation; }
@@ -178,7 +178,7 @@
   gfx::Insets GetWorkAreaInsets() const;
 
   // Sets the device scale factor and display bounds in pixel. This
-  // updates the work are using the same insets between old bounds and
+  // updates the work area using the same insets between old bounds and
   // work area.
   void SetScaleAndBounds(float device_scale_factor,
                          const gfx::Rect& bounds_in_pixel);
@@ -187,7 +187,7 @@
   // between old bounds and work area.
   void SetSize(const gfx::Size& size_in_pixel);
 
-  // Computes and updates the display's work are using
+  // Computes and updates the display's work area using
   // |work_area_insets| and the bounds.
   void UpdateWorkAreaFromInsets(const gfx::Insets& work_area_insets);
 
@@ -239,9 +239,7 @@
 
   // The number of bits per pixel. Used by media query APIs.
   int color_depth() const { return color_depth_; }
-  void set_color_depth(int color_depth) {
-    color_depth_ = color_depth;
-  }
+  void set_color_depth(int color_depth) { color_depth_ = color_depth; }
 
   // The number of bits per color component (all color components are assumed to
   // have the same number of bits). Used by media query APIs.
diff --git a/ui/display/display_change_notifier_unittest.cc b/ui/display/display_change_notifier_unittest.cc
index af69515..3468929 100644
--- a/ui/display/display_change_notifier_unittest.cc
+++ b/ui/display/display_change_notifier_unittest.cc
@@ -412,9 +412,9 @@
 
   std::vector<Display> old_displays, new_displays;
   old_displays.push_back(Display(1));
-  old_displays[0].set_device_scale_factor(1.f);
+  old_displays[0].SetDeviceScaleFactor(1.f);
   new_displays.push_back(Display(1));
-  new_displays[0].set_device_scale_factor(2.f);
+  new_displays[0].SetDeviceScaleFactor(2.f);
 
   change_notifier.NotifyDisplaysChanged(old_displays, new_displays);
   EXPECT_EQ(1, observer.display_changed());
@@ -436,8 +436,8 @@
   new_displays.push_back(Display(2));
   new_displays.push_back(Display(3));
 
-  old_displays[0].set_device_scale_factor(1.f);
-  new_displays[0].set_device_scale_factor(2.f);
+  old_displays[0].SetDeviceScaleFactor(1.f);
+  new_displays[0].SetDeviceScaleFactor(2.f);
 
   old_displays[1].set_bounds(gfx::Rect(0, 0, 200, 200));
   new_displays[1].set_bounds(gfx::Rect(0, 0, 400, 400));
@@ -456,11 +456,11 @@
 
   std::vector<Display> old_displays, new_displays;
   old_displays.push_back(Display(1, gfx::Rect(0, 0, 200, 200)));
-  old_displays[0].set_device_scale_factor(1.f);
+  old_displays[0].SetDeviceScaleFactor(1.f);
   old_displays[0].SetRotationAsDegree(0);
 
   new_displays.push_back(Display(1, gfx::Rect(100, 100, 200, 200)));
-  new_displays[0].set_device_scale_factor(2.f);
+  new_displays[0].SetDeviceScaleFactor(2.f);
   new_displays[0].SetRotationAsDegree(90);
 
   change_notifier.NotifyDisplaysChanged(old_displays, new_displays);
diff --git a/ui/display/display_list.cc b/ui/display/display_list.cc
index 177aa33..4982432 100644
--- a/ui/display/display_list.cc
+++ b/ui/display/display_list.cc
@@ -90,7 +90,7 @@
     changed_values |= DisplayObserver::DISPLAY_METRIC_ROTATION;
   }
   if (local_display->device_scale_factor() != display.device_scale_factor()) {
-    local_display->set_device_scale_factor(display.device_scale_factor());
+    local_display->SetDeviceScaleFactor(display.device_scale_factor());
     changed_values |= DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
   }
   if (local_display->color_space() != display.color_space() ||
diff --git a/ui/display/ios/screen_ios.mm b/ui/display/ios/screen_ios.mm
index cb3c47b..7f26be4d 100644
--- a/ui/display/ios/screen_ios.mm
+++ b/ui/display/ios/screen_ios.mm
@@ -17,7 +17,7 @@
     UIScreen* mainScreen = [UIScreen mainScreen];
     CHECK(mainScreen);
     Display display(0, gfx::Rect(mainScreen.bounds));
-    display.set_device_scale_factor([mainScreen scale]);
+    display.SetDeviceScaleFactor([mainScreen scale]);
     ProcessDisplayChanged(display, true /* is_primary */);
   }
 
diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm
index 4d5b83a..130abcc7 100644
--- a/ui/display/mac/screen_mac.mm
+++ b/ui/display/mac/screen_mac.mm
@@ -79,7 +79,7 @@
   CGFloat scale = [screen backingScaleFactor];
   if (Display::HasForceDeviceScaleFactor())
     scale = Display::GetForcedDeviceScaleFactor();
-  display.set_device_scale_factor(scale);
+  display.SetDeviceScaleFactor(scale);
 
   // Compute the color profile.
   gfx::ICCProfile icc_profile;
diff --git a/ui/display/mojo/display_struct_traits.cc b/ui/display/mojo/display_struct_traits.cc
index 2603ede..6bfba6a4 100644
--- a/ui/display/mojo/display_struct_traits.cc
+++ b/ui/display/mojo/display_struct_traits.cc
@@ -126,7 +126,7 @@
   if (!data.ReadWorkArea(&out->work_area_))
     return false;
 
-  out->set_device_scale_factor(data.device_scale_factor());
+  out->SetDeviceScaleFactor(data.device_scale_factor());
 
   if (!data.ReadRotation(&out->rotation_))
     return false;
diff --git a/ui/display/mojo/display_struct_traits_unittest.cc b/ui/display/mojo/display_struct_traits_unittest.cc
index d9b2cee..b7d71e4 100644
--- a/ui/display/mojo/display_struct_traits_unittest.cc
+++ b/ui/display/mojo/display_struct_traits_unittest.cc
@@ -132,7 +132,7 @@
 
   Display input(246345234, bounds);
   input.set_work_area(work_area);
-  input.set_device_scale_factor(2.0f);
+  input.SetDeviceScaleFactor(2.0f);
   input.set_rotation(Display::ROTATE_270);
   input.set_touch_support(Display::TouchSupport::AVAILABLE);
   input.set_accelerometer_support(Display::AccelerometerSupport::UNAVAILABLE);
diff --git a/ui/display/win/screen_win.cc b/ui/display/win/screen_win.cc
index cf47db2..8c55f290 100644
--- a/ui/display/win/screen_win.cc
+++ b/ui/display/win/screen_win.cc
@@ -172,7 +172,7 @@
                                      bool hdr_enabled) {
   Display display(display_info.id());
   float scale_factor = display_info.device_scale_factor();
-  display.set_device_scale_factor(scale_factor);
+  display.SetDeviceScaleFactor(scale_factor);
   display.set_work_area(
       gfx::ScaleToEnclosingRect(display_info.screen_work_rect(),
                                 1.0f / scale_factor));
diff --git a/ui/display/win/screen_win_display.cc b/ui/display/win/screen_win_display.cc
index 5a000b5..cdb36cc 100644
--- a/ui/display/win/screen_win_display.cc
+++ b/ui/display/win/screen_win_display.cc
@@ -14,7 +14,7 @@
 Display CreateDisplayFromDisplayInfo(const DisplayInfo& display_info) {
   Display display(display_info.id());
   float scale_factor = display_info.device_scale_factor();
-  display.set_device_scale_factor(scale_factor);
+  display.SetDeviceScaleFactor(scale_factor);
   display.set_work_area(
       gfx::ScaleToEnclosingRect(display_info.screen_work_rect(),
                                 1.0f / scale_factor));
diff --git a/ui/events/blink/blink_event_util.cc b/ui/events/blink/blink_event_util.cc
index b8b92f19..5d5b1135 100644
--- a/ui/events/blink/blink_event_util.cc
+++ b/ui/events/blink/blink_event_util.cc
@@ -266,7 +266,7 @@
 bool CanCoalesce(const WebPointerEvent& event_to_coalesce,
                  const WebPointerEvent& event) {
   return (event.GetType() == WebInputEvent::kPointerMove ||
-          event.GetType() == WebInputEvent::kPointerRawMove) &&
+          event.GetType() == WebInputEvent::kPointerRawUpdate) &&
          event.GetType() == event_to_coalesce.GetType() &&
          event.id == event_to_coalesce.id &&
          event.pointer_type == event_to_coalesce.pointer_type;
diff --git a/ui/gfx/font_fallback_win.cc b/ui/gfx/font_fallback_win.cc
index f4ded19..a37f809 100644
--- a/ui/gfx/font_fallback_win.cc
+++ b/ui/gfx/font_fallback_win.cc
@@ -189,34 +189,127 @@
 CachedFontLinkSettings::~CachedFontLinkSettings() {
 }
 
+struct MetaFileEnumState {
+  DWORD current_font_handle = 0;
+  std::map<DWORD, std::string> font_handle_map;
+  base::StringPiece16 expected_text;
+  std::string fallback_font_name;
+  bool found_fallback = false;
+};
+
 // Callback to |EnumEnhMetaFile()| to intercept font creation.
 int CALLBACK MetaFileEnumProc(HDC hdc,
                               HANDLETABLE* table,
                               CONST ENHMETARECORD* record,
                               int table_entries,
-                              LPARAM log_font) {
+                              LPARAM param_state) {
+  // The MetaFileEnumProc() is called for every record produced in the metafile.
+  // The following code is processing the records and keep track of active
+  // objects in MetaFileEnumState struct. The state machine recognizes fonts
+  // creation, select object, delete object and text output. The fallback font
+  // is the active font when the expected text is outputted.
+  MetaFileEnumState* state = reinterpret_cast<MetaFileEnumState*>(param_state);
   if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
     const EMREXTCREATEFONTINDIRECTW* create_font_record =
         reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
-    *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
+    DWORD handle = create_font_record->ihFont;
+    if (create_font_record->elfw.elfLogFont.lfFaceName[0]) {
+      state->font_handle_map[handle] =
+          base::UTF16ToUTF8(create_font_record->elfw.elfLogFont.lfFaceName);
+    } else {
+      // The font has no name. Removing the object from the set of known
+      // objects to avoid reporting the previous object has the fallback font.
+      DCHECK(!create_font_record->elfw.elfFullName[0]);
+      state->font_handle_map.erase(handle);
+    }
+  } else if (record->iType == EMR_SELECTOBJECT) {
+    const EMRSELECTOBJECT* select_record =
+        reinterpret_cast<const EMRSELECTOBJECT*>(record);
+    state->current_font_handle = select_record->ihObject;
+  } else if (record->iType == EMR_DELETEOBJECT) {
+    const EMRSELECTOBJECT* delete_record =
+        reinterpret_cast<const EMRDELETEOBJECT*>(record);
+    state->font_handle_map.erase(delete_record->ihObject);
+  } else if (record->iType == EMR_EXTTEXTOUTW) {
+    const EMREXTTEXTOUTW* textout_record =
+        reinterpret_cast<const EMREXTTEXTOUTW*>(record);
+
+    // Retrieve the text displayed. The outputted text can be retrieved after
+    // the record structure; the record contains a bytes offset to the beginning
+    // of the text.
+    const wchar_t* raw_chars = reinterpret_cast<const wchar_t*>(
+        reinterpret_cast<const uint8_t*>(textout_record) +
+        textout_record->emrtext.offString);
+    const int text_length = textout_record->emrtext.nChars;
+    base::StringPiece16 text(raw_chars, text_length);
+
+    if (text == state->expected_text) {
+      // The expected text is displayed. Collect the current font information.
+      auto it = state->font_handle_map.find(state->current_font_handle);
+      if (it != state->font_handle_map.end())
+        state->fallback_font_name = it->second;
+      state->found_fallback = !state->fallback_font_name.empty();
+    } else if (text != L" ") {
+      // Output of a space may be used for text alignment. If any other text is
+      // outputted, the code returns a failure and stop processing records.
+      return 0;
+    }
   }
+
+  // This function must return a nonzero value to continue enumeration; to stop
+  // enumeration, it must return zero.
   return 1;
 }
 
+}  // namespace
+
+namespace internal {
+
+// The |GetUniscribeFallbackFont| try to find fallback font by using the Windows
+// uniscribe API.
+//
+// Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
+// Uniscribe doesn't expose a method to query fallback fonts, so this works by
+// drawing the text to an EMF object with Uniscribe's ScriptStringOut and then
+// inspecting the EMF object to figure out which font Uniscribe used.
+//
+// DirectWrite in Windows 8.1 provides a cleaner alternative:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx
+//
+// Example of a EMR script:
+//   EMR_HEADER
+//   EMR_EXTCREATEFONTINDIRECTW ID:1 (Set Font Segoe UI)
+//   EMR_SELECTOBJECT ID:1
+//   EMR_EXTCREATEFONTINDIRECTW ID:2  (Set Font Gadugi)
+//   EMR_SELECTOBJECT ID:2
+//   EMR_SELECTOBJECT ID:1
+//   EMR_DELETEOBJECT ID:2
+//   EMR_EXTCREATEFONTINDIRECTW ID:2 (Set Font Gadugi)
+//   EMR_SELECTOBJECT ID:2
+//   EMR_SELECTOBJECT ID:1
+//   EMR_EXTTEXTOUTW " "
+//   EMR_SETTEXTALIGN
+//   EMR_SETBKMODE
+//   EMR_MOVETOEX
+//   EMR_SETTEXTALIGN
+//   EMR_SELECTOBJECT ID:2
+//   EMR_EXTTEXTOUTW "..."
+//   EMR_SELECTOBJECT ID:1
+//   EMR_MOVETOEX
+//   EMR_SETTEXTALIGN
+//   MR_SETBKMODE
+//   EMR_DELETEOBJECT ID:2
+//   EMR_EOF
 bool GetUniscribeFallbackFont(const Font& font,
                               const wchar_t* text,
                               int text_length,
                               Font* result) {
-  // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
-  // Uniscribe doesn't expose a method to query fallback fonts, so this works by
-  // drawing the text to an EMF object with Uniscribe's ScriptStringOut and then
-  // inspecting the EMF object to figure out which font Uniscribe used.
-  //
-  // DirectWrite in Windows 8.1 provides a cleaner alternative:
-  // http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx
-
   static HDC hdc = CreateCompatibleDC(NULL);
 
+  // The length passed to |ScriptStringAnalyse| must be at least 1.
+  if (text_length <= 0)
+    return false;
+
   // Use a meta file to intercept the fallback font chosen by Uniscribe.
   HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
   if (!meta_file_dc)
@@ -249,27 +342,42 @@
     ScriptStringFree(&script_analysis);
   }
 
-  bool found_fallback = false;
+  MetaFileEnumState state;
+  state.expected_text = base::StringPiece16(text, text_length);
+
   HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
   if (SUCCEEDED(hresult)) {
-    LOGFONT log_font;
-    log_font.lfFaceName[0] = 0;
-    EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
-    if (log_font.lfFaceName[0]) {
-      *result =
-          Font(base::UTF16ToUTF8(log_font.lfFaceName), font.GetFontSize());
-      found_fallback = true;
+    BOOL eumeration_success =
+        EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &state, NULL);
+    // If the enumeration didn't succeed, we are assuming there are unknown
+    // command and the fallback font can't be determined.
+    if (eumeration_success != TRUE) {
+      state.fallback_font_name = "";
+      state.found_fallback = false;
     }
   }
   DeleteEnhMetaFile(meta_file);
 
-  return found_fallback;
+  // Same font, no fallback font required.
+  if (state.fallback_font_name == font.GetFontName()) {
+    state.fallback_font_name.clear();
+    state.found_fallback = false;
+  }
+
+  // The uniscribe code is selecting the 'Microsoft Sans Serif' as a last-resort
+  // font when it's unable to determine a valid fallback font.
+  if (state.fallback_font_name == "Microsoft Sans Serif") {
+    state.fallback_font_name.clear();
+    state.found_fallback = false;
+  }
+
+  // Create the resulting fallback font.
+  if (state.found_fallback)
+    *result = Font(state.fallback_font_name, font.GetFontSize());
+
+  return state.found_fallback;
 }
 
-}  // namespace
-
-namespace internal {
-
 void ParseFontLinkEntry(const std::string& entry,
                         std::string* filename,
                         std::string* font_name) {
@@ -292,8 +400,8 @@
   // followed optionally by the font family name and a pair of integer scaling
   // factors.
   // TODO(asvitkine): Should we support these scaling factors?
-  *font_names = base::SplitString(
-      family, "&", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  *font_names = base::SplitString(family, "&", base::TRIM_WHITESPACE,
+                                  base::SPLIT_WANT_ALL);
   if (!font_names->empty()) {
     const size_t index = font_names->back().find('(');
     if (index != std::string::npos) {
@@ -337,7 +445,7 @@
   factory.CopyTo(factory2.GetAddressOf());
   if (!factory2) {
     // IDWriteFactory2 is not available before Win8.1
-    return GetUniscribeFallbackFont(font, text, text_length, result);
+    return internal::GetUniscribeFallbackFont(font, text, text_length, result);
   }
 
   Microsoft::WRL::ComPtr<IDWriteFontFallback> fallback;
diff --git a/ui/gfx/font_fallback_win.h b/ui/gfx/font_fallback_win.h
index 083eb10..1ba7a8a 100644
--- a/ui/gfx/font_fallback_win.h
+++ b/ui/gfx/font_fallback_win.h
@@ -33,6 +33,11 @@
 void GFX_EXPORT ParseFontFamilyString(const std::string& family,
                                      std::vector<std::string>* font_names);
 
+// Exposed for unittest.
+bool GFX_EXPORT GetUniscribeFallbackFont(const Font& font,
+                                         const wchar_t* text,
+                                         int text_length,
+                                         Font* result);
 }  // namespace internal
 
 }  // namespace gfx
diff --git a/ui/gfx/font_fallback_win_unittest.cc b/ui/gfx/font_fallback_win_unittest.cc
index e4faf0c2..6864189 100644
--- a/ui/gfx/font_fallback_win_unittest.cc
+++ b/ui/gfx/font_fallback_win_unittest.cc
@@ -3,14 +3,157 @@
 // found in the LICENSE file.
 
 #include "ui/gfx/font_fallback_win.h"
+
+#include <tuple>
+
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/win/windows_version.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
+#include "third_party/icu/source/common/unicode/utf16.h"
+#include "third_party/skia/include/core/SkTypeface.h"
 
 namespace gfx {
 
-TEST(FontFallbackWinTest, ParseFontLinkEntry) {
+namespace {
+
+class FontFallbackWinTest : public testing::Test {
+ public:
+  FontFallbackWinTest() = default;
+
+ private:
+  // Needed to bypass DCHECK in GetFallbackFont.
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::UI};
+
+  DISALLOW_COPY_AND_ASSIGN(FontFallbackWinTest);
+};
+
+enum class FallbackFontFn { DEFAULT, UNISCRIBE };
+
+// Options to parameterized unittests.
+struct FallbackFontTestOption {
+  FallbackFontFn fallback_font = FallbackFontFn::DEFAULT;
+  bool ignore_get_fallback_failure = false;
+  bool skip_code_point_validation = false;
+  bool skip_fallback_fonts_validation = false;
+};
+
+// Options for tests that fully validate the GetFallbackFont(...) parameters.
+const FallbackFontTestOption default_fallback_option = {
+    FallbackFontFn::DEFAULT};
+const FallbackFontTestOption uniscribe_fallback_option = {
+    FallbackFontFn::UNISCRIBE};
+// Options for tests that does not validate the GetFallbackFont(...) parameters.
+const FallbackFontTestOption untested_default_fallback_option = {
+    FallbackFontFn::DEFAULT, true, true, true};
+const FallbackFontTestOption untested_uniscribe_fallback_option = {
+    FallbackFontFn::UNISCRIBE, true, true, true};
+
+// A font test case for the parameterized unittests.
+struct FallbackFontTestCase {
+  UScriptCode script;
+  base::string16 text;
+  std::vector<std::string> fallback_fonts;
+  bool is_win10 = false;
+};
+
+using FallbackFontTestParamInfo =
+    std::tuple<FallbackFontTestCase, FallbackFontTestOption>;
+
+class GetFallbackFontTest
+    : public ::testing::TestWithParam<FallbackFontTestParamInfo> {
+ public:
+  GetFallbackFontTest() = default;
+
+  static std::string ParamInfoToString(
+      ::testing::TestParamInfo<FallbackFontTestParamInfo> param_info) {
+    const FallbackFontTestCase& test_case = std::get<0>(param_info.param);
+    const FallbackFontTestOption& options = std::get<1>(param_info.param);
+
+    std::string script_name = uscript_getName(test_case.script);
+
+    std::string fallback_fn;
+    if (options.fallback_font == FallbackFontFn::DEFAULT)
+      fallback_fn = "DEFAULT";
+    else if (options.fallback_font == FallbackFontFn::UNISCRIBE)
+      fallback_fn = "UNISCRIBE";
+
+    return base::StringPrintf("%s_%s", script_name.c_str(),
+                              fallback_fn.c_str());
+  }
+
+  void SetUp() override { std::tie(test_case_, test_option_) = GetParam(); }
+
+ protected:
+  bool GetFallbackFont(const Font& font, Font* result) {
+    if (test_option_.fallback_font == FallbackFontFn::DEFAULT) {
+      return gfx::GetFallbackFont(font, test_case_.text.c_str(),
+                                  test_case_.text.size(), result);
+    } else if (test_option_.fallback_font == FallbackFontFn::UNISCRIBE) {
+      return internal::GetUniscribeFallbackFont(font, test_case_.text.c_str(),
+                                                test_case_.text.size(), result);
+    }
+    return false;
+  }
+
+  bool EnsuresScriptSupportCodePoints(const base::string16& text,
+                                      UScriptCode script,
+                                      const std::string& script_name) {
+    size_t i = 0;
+    while (i < text.length()) {
+      UChar32 code_point;
+      U16_NEXT(text.c_str(), i, text.size(), code_point);
+      if (!uscript_hasScript(code_point, script)) {
+        // Retrieve the appropriate script
+        UErrorCode script_error;
+        UScriptCode codepoint_script =
+            uscript_getScript(code_point, &script_error);
+
+        ADD_FAILURE() << "CodePoint '" << code_point
+                      << "' is not part of the script '" << script_name
+                      << "'. Script '" << uscript_getName(codepoint_script)
+                      << "' detected.";
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool DoesFontSupportCodePoints(Font font, const base::string16& text) {
+    sk_sp<SkTypeface> skia_face =
+        SkTypeface::MakeFromName(font.GetFontName().c_str(), SkFontStyle());
+
+    size_t i = 0;
+    const SkGlyphID kUnsupportedGlyph = 0;
+    while (i < text.length()) {
+      UChar32 code_point;
+      U16_NEXT(text.c_str(), i, text.size(), code_point);
+      SkGlyphID glyph_id = skia_face->unicharToGlyph(code_point);
+      if (glyph_id == kUnsupportedGlyph)
+        return false;
+    }
+    return true;
+  }
+
+  FallbackFontTestCase test_case_;
+  FallbackFontTestOption test_option_;
+  std::string script_name_;
+
+ private:
+  // Needed to bypass DCHECK in GetFallbackFont.
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::UI};
+
+  DISALLOW_COPY_AND_ASSIGN(GetFallbackFontTest);
+};
+
+}  // namespace
+
+TEST_F(FontFallbackWinTest, ParseFontLinkEntry) {
   std::string file;
   std::string font;
 
@@ -31,7 +174,7 @@
   EXPECT_EQ("Meiryo", font);
 }
 
-TEST(FontFallbackWinTest, ParseFontFamilyString) {
+TEST_F(FontFallbackWinTest, ParseFontFamilyString) {
   std::vector<std::string> font_names;
 
   internal::ParseFontFamilyString("Times New Roman (TrueType)", &font_names);
@@ -56,25 +199,277 @@
   EXPECT_EQ("Meiryo UI Italic", font_names[3]);
 }
 
-TEST(FontFallbackWinTest, FontFallback) {
-  // Needed to bypass DCHECK in GetFallbackFont.
-  base::MessageLoopForUI message_loop;
-
-  Font base_font("Segoe UI", 14);
+TEST_F(FontFallbackWinTest, EmptyStringUniscribeFallback) {
+  Font base_font;
   Font fallback_font;
-  bool result = GetFallbackFont(base_font, L"abc", 3, &fallback_font);
-  EXPECT_TRUE(result);
-  EXPECT_STREQ("Segoe UI", fallback_font.GetFontName().c_str());
+  bool result =
+      internal::GetUniscribeFallbackFont(base_font, L"", 0, &fallback_font);
+  EXPECT_FALSE(result);
 }
 
-TEST(FontFallbackWinTest, EmptyStringFallback) {
-  // Needed to bypass DCHECK in GetFallbackFont.
-  base::MessageLoopForUI message_loop;
-
+TEST_F(FontFallbackWinTest, EmptyStringFallback) {
   Font base_font;
   Font fallback_font;
   bool result = GetFallbackFont(base_font, L"", 0, &fallback_font);
   EXPECT_FALSE(result);
 }
 
+// This test ensures the font fallback work correctly. It will ensures that
+//   1) The script supports the text
+//   2) The input font does not already support the text
+//   3) The call to GetFallbackFont() succeed
+//   4) The fallback font has a glyph for every character of the text
+//
+// The previous checks can be activated or deactivated through the class
+// FallbackFontTestOption (e.g. test_option_).
+TEST_P(GetFallbackFontTest, GetFallbackFont) {
+  // Default system font on Windows.
+  const Font base_font("Segoe UI", 14);
+
+  // Skip testing this call to GetFallbackFont on older windows versions. Some
+  // fonts only got introduced on windows 10 and the test will fail on previous
+  // versions.
+  const bool is_win10 = base::win::GetVersion() >= base::win::Version::WIN10;
+  if (test_case_.is_win10 && !is_win10)
+    return;
+
+  // Retrieve the name of the current script.
+  script_name_ = uscript_getName(test_case_.script);
+
+  // Validate that tested characters are part of the script.
+  if (!test_option_.skip_code_point_validation &&
+      !EnsuresScriptSupportCodePoints(test_case_.text, test_case_.script,
+                                      script_name_)) {
+    return;
+  }
+
+  // The default font already support it, do not try to find a fallback font.
+  if (DoesFontSupportCodePoints(base_font, test_case_.text))
+    return;
+
+  // Retrieve the fallback font.
+  Font fallback_font;
+  bool result = GetFallbackFont(base_font, &fallback_font);
+  if (!result) {
+    if (!test_option_.ignore_get_fallback_failure)
+      ADD_FAILURE() << "GetFallbackFont failed for '" << script_name_ << "'";
+    return;
+  }
+
+  // Ensure the fallback font is a part of the validation fallback fonts list.
+  if (!test_option_.skip_fallback_fonts_validation) {
+    bool valid = std::find(test_case_.fallback_fonts.begin(),
+                           test_case_.fallback_fonts.end(),
+                           fallback_font.GetFontName()) !=
+                 test_case_.fallback_fonts.end();
+    if (!valid) {
+      ADD_FAILURE() << "GetFallbackFont failed for '" << script_name_
+                    << "' invalid fallback font: "
+                    << fallback_font.GetFontName();
+      return;
+    }
+  }
+
+  // Ensure that glyphs exists in the fallback font.
+  if (!DoesFontSupportCodePoints(fallback_font, test_case_.text)) {
+    ADD_FAILURE() << "Font '" << fallback_font.GetFontName()
+                  << "' does not matched every CodePoints.";
+    return;
+  }
+}
+
+FallbackFontTestCase kGetUniscribeFontFallbackTests[] = {
+    {USCRIPT_ARABIC, L"\u062A\u062D", {"Segoe UI", "Tahoma"}},
+    {USCRIPT_DEVANAGARI, L"\u0905\u0906", {"Mangal", "Nirmala UI"}},
+    {USCRIPT_GURMUKHI, L"\u0A21\u0A22", {"Raavi", "Nirmala UI"}},
+    {USCRIPT_NEW_TAI_LUE, L"\u1981\u1982", {"Microsoft New Tai Lue"}},
+};
+
+// A list of script and the fallback font on a default windows installation.
+// This list may need to be updated if fonts or operating systems are
+// upgraded.
+constexpr bool kWin10Only = true;
+FallbackFontTestCase kGetFontFallbackTests[] = {
+    {USCRIPT_ARABIC, L"\u062A\u062D", {"Segoe UI", "Tahoma"}},
+    {USCRIPT_ARMENIAN, L"\u0540\u0541", {"Segoe UI", "Tahoma"}},
+    {USCRIPT_BRAILLE, L"\u2870\u2871", {"Segoe UI Symbol"}},
+    {USCRIPT_BUGINESE, L"\u1A00\u1A01", {"Leelawadee UI"}, kWin10Only},
+    {USCRIPT_CANADIAN_ABORIGINAL, L"\u1410\u1411", {"Gadugi", "Euphemia"}},
+
+    {USCRIPT_CARIAN,
+     L"\U000102A0\U000102A1",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_CHEROKEE,
+     L"\u13A1\u13A2",
+     {"Gadugi", "Plantagenet Cheroke"},
+     kWin10Only},
+
+    {USCRIPT_COPTIC, L"\u2C81\u2C82", {"Segoe UI Historic"}, kWin10Only},
+
+    {USCRIPT_CUNEIFORM,
+     L"\U00012000\U0001200C",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_CYPRIOT,
+     L"\U00010800\U00010801",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_DESERET, L"\U00010400\U00010401", {"Segoe UI Symbol"}, kWin10Only},
+
+    {USCRIPT_DEVANAGARI, L"\u0905\u0906", {"Mangal", "Nirmala UI"}},
+    {USCRIPT_ETHIOPIC, L"\u1201\u1202", {"Ebrima", "Nyala"}},
+    {USCRIPT_GURMUKHI, L"\u0A21\u0A22", {"Raavi", "Nirmala UI"}},
+    {USCRIPT_HEBREW, L"\u05D1\u05D2", {"Segoe UI", "Tahoma"}},
+
+    {USCRIPT_IMPERIAL_ARAMAIC,
+     L"\U00010841\U00010842",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_INSCRIPTIONAL_PAHLAVI,
+     L"\U00010B61\U00010B62",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_INSCRIPTIONAL_PARTHIAN,
+     L"\U00010B41\U00010B42",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_JAVANESE, L"\uA991\uA992", {"Javanese Text"}, kWin10Only},
+    {USCRIPT_KANNADA, L"\u0CA1\u0CA2", {"Nirmala UI", "Tunga"}},
+
+    {USCRIPT_KHAROSHTHI,
+     L"\U00010A10\U00010A11",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_LAO, L"\u0ED0\u0ED1", {"Lao UI", "Leelawadee UI"}},
+    {USCRIPT_LISU, L"\uA4D0\uA4D1", {"Segoe UI"}, kWin10Only},
+
+    {USCRIPT_LYCIAN,
+     L"\U00010281\U00010282",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_LYDIAN,
+     L"\U00010921\U00010922",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_MALAYALAM, L"\u0D21\u0D22", {"Kartika", "Nirmala UI"}},
+
+    {USCRIPT_MEROITIC_CURSIVE,
+     L"\U000109A1\U000109A2",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_MYANMAR, L"\u1000\u1001", {"Myanmar Text"}, kWin10Only},
+    {USCRIPT_NEW_TAI_LUE, L"\u1981\u1982", {"Microsoft New Tai Lue"}},
+    {USCRIPT_NKO, L"\u07C1\u07C2", {"Ebrima"}},
+
+    {USCRIPT_OGHAM, L"\u1680\u1681", {"Segoe UI Symbol", "Segoe UI Historic"}},
+
+    {USCRIPT_OL_CHIKI, L"\u1C51\u1C52", {"Nirmala UI"}, kWin10Only},
+
+    {USCRIPT_OLD_ITALIC,
+     L"\U00010301\U00010302",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_OLD_PERSIAN,
+     L"\U000103A1\U000103A2",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_OLD_SOUTH_ARABIAN,
+     L"\U00010A61\U00010A62",
+     {"Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_ORIYA, L"\u0B21\u0B22", {"Kalinga", "Nirmala UI"}},
+    {USCRIPT_PHAGS_PA, L"\uA841\uA842", {"Microsoft PhagsPa"}},
+
+    {USCRIPT_RUNIC, L"\u16A0\u16A1", {"Segoe UI Symbol", "Segoe UI Historic"}},
+
+    {USCRIPT_SHAVIAN,
+     L"\U00010451\U00010452",
+     {"Segoe UI", "Segoe UI Historic"},
+     kWin10Only},
+
+    {USCRIPT_SINHALA, L"\u0D91\u0D92", {"Iskoola Pota", "Nirmala UI"}},
+
+    {USCRIPT_SORA_SOMPENG, L"\U000110D1\U000110D2", {"Nirmala UI"}, kWin10Only},
+
+    {USCRIPT_SYRIAC,
+     L"\u0711\u0712",
+     {"Estrangelo Edessa", "Segoe UI Historic"}},
+
+    {USCRIPT_TAI_LE, L"\u1951\u1952", {"Microsoft Tai Le"}},
+    {USCRIPT_TAMIL, L"\u0BB1\u0BB2", {"Latha", "Nirmala UI"}},
+    {USCRIPT_TELUGU, L"\u0C21\u0C22", {"Gautami", "Nirmala UI"}},
+    {USCRIPT_THAANA, L"\u0781\u0782", {"Mv Boli", "MV Boli"}},
+    {USCRIPT_TIBETAN, L"\u0F01\u0F02", {"Microsoft Himalaya"}},
+    {USCRIPT_TIFINAGH, L"\u2D31\u2D32", {"Ebrima"}},
+    {USCRIPT_VAI, L"\uA501\uA502", {"Ebrima"}},
+    {USCRIPT_YI, L"\uA000\uA001", {"Microsoft Yi Baiti"}},
+};
+
+// Produces a font test case for every script.
+std::vector<FallbackFontTestCase> GetSampleFontTestCases() {
+  std::vector<FallbackFontTestCase> result;
+
+  const unsigned int script_max = u_getIntPropertyMaxValue(UCHAR_SCRIPT) + 1;
+  for (unsigned int i = 0; i < script_max; i++) {
+    const UScriptCode script = static_cast<UScriptCode>(i);
+
+    // Make a sample text to test the script.
+    UChar text[8];
+    UErrorCode errorCode = U_ZERO_ERROR;
+    int text_length =
+        uscript_getSampleString(script, text, ARRAYSIZE(text), &errorCode);
+    if (text_length <= 0 || errorCode != U_ZERO_ERROR)
+      continue;
+
+    FallbackFontTestCase test_case{script, text};
+    result.push_back(test_case);
+  }
+  return result;
+}
+
+// Ensures that Uniscribe fallback font gives known results. The uniscribe
+// fallback is only used on windows 7. For the purpose of tests coverage, we
+// are validating its behavior on every windows version.
+INSTANTIATE_TEST_SUITE_P(
+    Uniscribe,
+    GetFallbackFontTest,
+    testing::Combine(testing::ValuesIn(kGetUniscribeFontFallbackTests),
+                     testing::Values(uniscribe_fallback_option)),
+    GetFallbackFontTest::ParamInfoToString);
+
+// Ensures that the default fallback font gives known results. The test
+// is validating that a known fallback font is given for a given text and font.
+INSTANTIATE_TEST_SUITE_P(
+    Default,
+    GetFallbackFontTest,
+    testing::Combine(testing::ValuesIn(kGetFontFallbackTests),
+                     testing::Values(default_fallback_option)),
+    GetFallbackFontTest::ParamInfoToString);
+
+// Ensures that font fallback functions are working properly for any string
+// (strings from any script). The test doesn't enforce the functions to
+// give a fallback font. The accepted behaviors are:
+//    1) The fallback function failed and doesn't provide a fallback.
+//    2) The fallback function succeeded and the font supports every glyphs.
+INSTANTIATE_TEST_SUITE_P(
+    Glyphs,
+    GetFallbackFontTest,
+    testing::Combine(testing::ValuesIn(GetSampleFontTestCases()),
+                     testing::Values(untested_default_fallback_option,
+                                     untested_uniscribe_fallback_option)),
+    GetFallbackFontTest::ParamInfoToString);
 }  // namespace gfx
diff --git a/ui/gl/gl_image_dxgi_swap_chain.cc b/ui/gl/gl_image_dxgi_swap_chain.cc
index 2cea2808..08b1cc7 100644
--- a/ui/gl/gl_image_dxgi_swap_chain.cc
+++ b/ui/gl/gl_image_dxgi_swap_chain.cc
@@ -16,7 +16,7 @@
 
 namespace {
 
-bool SupportedBindFormat(gfx::BufferFormat format) {
+bool SwapChainSupportedBindFormat(gfx::BufferFormat format) {
   switch (format) {
     case gfx::BufferFormat::RGBA_8888:
     case gfx::BufferFormat::RGBX_8888:
@@ -27,8 +27,8 @@
   };
 }
 
-bool HasAlpha(gfx::BufferFormat format) {
-  DCHECK(SupportedBindFormat(format));
+bool SwapChainHasAlpha(gfx::BufferFormat format) {
+  DCHECK(SwapChainSupportedBindFormat(format));
   switch (format) {
     case gfx::BufferFormat::RGBA_8888:
     case gfx::BufferFormat::RGBA_F16:
@@ -42,13 +42,14 @@
 }
 
 EGLConfig ChooseCompatibleConfig(gfx::BufferFormat format, EGLDisplay display) {
-  DCHECK(SupportedBindFormat(format));
+  DCHECK(SwapChainSupportedBindFormat(format));
 
   const EGLint color_bits = format == gfx::BufferFormat::RGBA_F16 ? 16 : 8;
-  const EGLint buffer_bind_to_texture =
-      HasAlpha(format) ? EGL_BIND_TO_TEXTURE_RGBA : EGL_BIND_TO_TEXTURE_RGB;
+  const EGLint buffer_bind_to_texture = SwapChainHasAlpha(format)
+                                            ? EGL_BIND_TO_TEXTURE_RGBA
+                                            : EGL_BIND_TO_TEXTURE_RGB;
   const EGLint buffer_size =
-      color_bits * 3 + (HasAlpha(format) ? color_bits : 0);
+      color_bits * 3 + (SwapChainHasAlpha(format) ? color_bits : 0);
 
   std::vector<EGLint> attrib_list = {
       EGL_RED_SIZE,           color_bits, EGL_GREEN_SIZE,   color_bits,
@@ -90,7 +91,7 @@
       continue;
     }
 
-    if (HasAlpha(format) &&
+    if (SwapChainHasAlpha(format) &&
         (!eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &bits) ||
          bits != color_bits)) {
       continue;
@@ -106,7 +107,7 @@
                          EGLConfig config,
                          EGLDisplay display,
                          unsigned target) {
-  DCHECK(SupportedBindFormat(format));
+  DCHECK(SwapChainSupportedBindFormat(format));
 
   D3D11_TEXTURE2D_DESC desc;
   texture->GetDesc(&desc);
@@ -121,7 +122,7 @@
       EGL_TEXTURE_TARGET,
       EGL_TEXTURE_2D,
       EGL_TEXTURE_FORMAT,
-      HasAlpha(format) ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
+      SwapChainHasAlpha(format) ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
       EGL_NONE};
 
   return eglCreatePbufferFromClientBuffer(
@@ -180,7 +181,7 @@
 void GLImageDXGISwapChain::Flush() {}
 
 unsigned GLImageDXGISwapChain::GetInternalFormat() {
-  return HasAlpha(buffer_format_) ? GL_RGBA : GL_RGB;
+  return SwapChainHasAlpha(buffer_format_) ? GL_RGBA : GL_RGB;
 }
 
 gfx::Size GLImageDXGISwapChain::GetSize() {
diff --git a/ui/ozone/platform/scenic/scenic_screen.cc b/ui/ozone/platform/scenic/scenic_screen.cc
index 170db83..ece50d1 100644
--- a/ui/ozone/platform/scenic/scenic_screen.cc
+++ b/ui/ozone/platform/scenic/scenic_screen.cc
@@ -55,7 +55,7 @@
                                  });
   DCHECK(display_it != displays_.end());
 
-  display_it->set_device_scale_factor(device_pixel_ratio);
+  display_it->SetDeviceScaleFactor(device_pixel_ratio);
   for (auto& observer : observers_) {
     observer.OnDisplayMetricsChanged(
         *display_it,
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index 0c72f2d..fd7321ab 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -158,6 +158,16 @@
   return nullptr;
 }
 
+std::vector<WaylandWindow*> WaylandConnection::GetWindowsOnDisplay(
+    uint32_t display_id) {
+  std::vector<WaylandWindow*> result;
+  for (auto entry : window_map_) {
+    if (entry.second->GetEnteredOutputsIds().count(display_id) > 0)
+      result.push_back(entry.second);
+  }
+  return result;
+}
+
 void WaylandConnection::AddWindow(gfx::AcceleratedWidget widget,
                                   WaylandWindow* window) {
   window_map_[widget] = window;
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
index e38f5e1..5ccdfef 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -118,6 +118,9 @@
   WaylandWindow* GetWindowWithLargestBounds() const;
   WaylandWindow* GetCurrentFocusedWindow() const;
   WaylandWindow* GetCurrentKeyboardFocusedWindow() const;
+  // TODO(adunaev) remove this in favor of targeted subscription of windows to
+  // their displays.
+  std::vector<WaylandWindow*> GetWindowsOnDisplay(uint32_t display_id);
   void AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window);
   void RemoveWindow(gfx::AcceleratedWidget widget);
 
@@ -229,7 +232,7 @@
   // xdg_shell_listener
   static void Ping(void* data, xdg_shell* shell, uint32_t serial);
 
-  std::map<gfx::AcceleratedWidget, WaylandWindow*> window_map_;
+  base::flat_map<gfx::AcceleratedWidget, WaylandWindow*> window_map_;
 
   wl::Object<wl_display> display_;
   wl::Object<wl_registry> registry_;
diff --git a/ui/ozone/platform/wayland/host/wayland_output.cc b/ui/ozone/platform/wayland/host/wayland_output.cc
index 0b36d95..701f167 100644
--- a/ui/ozone/platform/wayland/host/wayland_output.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output.cc
@@ -11,14 +11,10 @@
 
 namespace ui {
 
-namespace {
-constexpr float kDefaultScaleFactor = 1.0f;
-}
-
 WaylandOutput::WaylandOutput(const uint32_t output_id, wl_output* output)
     : output_id_(output_id),
       output_(output),
-      device_scale_factor_(kDefaultScaleFactor),
+      scale_factor_(kDefaultScaleFactor),
       rect_in_physical_pixels_(gfx::Rect()) {}
 
 WaylandOutput::~WaylandOutput() = default;
@@ -38,7 +34,7 @@
 void WaylandOutput::TriggerDelegateNotification() const {
   DCHECK(!rect_in_physical_pixels_.IsEmpty());
   delegate_->OnOutputHandleMetrics(output_id_, rect_in_physical_pixels_,
-                                   device_scale_factor_);
+                                   scale_factor_);
 }
 
 // static
@@ -82,7 +78,7 @@
                                       int32_t factor) {
   WaylandOutput* wayland_output = static_cast<WaylandOutput*>(data);
   if (wayland_output)
-    wayland_output->device_scale_factor_ = factor;
+    wayland_output->scale_factor_ = factor;
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_output.h b/ui/ozone/platform/wayland/host/wayland_output.h
index 464689e..7b8e53e 100644
--- a/ui/ozone/platform/wayland/host/wayland_output.h
+++ b/ui/ozone/platform/wayland/host/wayland_output.h
@@ -36,12 +36,15 @@
 
   uint32_t output_id() const { return output_id_; }
   bool has_output(wl_output* output) const { return output_.get() == output; }
+  int32_t scale_factor() const { return scale_factor_; }
 
   // Tells if the output has already received physical screen dimensions in the
   // global compositor space.
   bool is_ready() const { return !rect_in_physical_pixels_.IsEmpty(); }
 
  private:
+  static constexpr int32_t kDefaultScaleFactor = 1;
+
   // Callback functions used for setting geometric properties of the output
   // and available modes.
   static void OutputHandleGeometry(void* data,
@@ -54,7 +57,6 @@
                                    const char* make,
                                    const char* model,
                                    int32_t output_transform);
-
   static void OutputHandleMode(void* data,
                                wl_output* wl_output,
                                uint32_t flags,
@@ -68,7 +70,7 @@
 
   const uint32_t output_id_ = 0;
   wl::Object<wl_output> output_;
-  float device_scale_factor_;
+  int32_t scale_factor_ = kDefaultScaleFactor;
   gfx::Rect rect_in_physical_pixels_;
 
   Delegate* delegate_ = nullptr;
diff --git a/ui/ozone/platform/wayland/host/wayland_output_manager.cc b/ui/ozone/platform/wayland/host/wayland_output_manager.cc
index 38dad07..1f403f4 100644
--- a/ui/ozone/platform/wayland/host/wayland_output_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output_manager.cc
@@ -26,10 +26,7 @@
   // Make sure an output with |output_id| has not been added yet. It's very
   // unlikely to happen, unless a compositor has a bug in the numeric names
   // representation of global objects.
-  auto output_it = std::find_if(output_list_.begin(), output_list_.end(),
-                                [output_id](const auto& output) {
-                                  return output->output_id() == output_id;
-                                });
+  auto output_it = GetOutputItById(output_id);
   DCHECK(output_it == output_list_.end());
   auto wayland_output = std::make_unique<WaylandOutput>(output_id, output);
   WaylandOutput* wayland_output_ptr = wayland_output.get();
@@ -44,10 +41,7 @@
 }
 
 void WaylandOutputManager::RemoveWaylandOutput(const uint32_t output_id) {
-  auto output_it = std::find_if(output_list_.begin(), output_list_.end(),
-                                [output_id](const auto& output) {
-                                  return output->output_id() == output_id;
-                                });
+  auto output_it = GetOutputItById(output_id);
 
   // Check the comment in the WaylandConnetion::GlobalRemove.
   if (output_it == output_list_.end())
@@ -89,6 +83,13 @@
   return output_it->get()->output_id();
 }
 
+WaylandOutput* WaylandOutputManager::GetOutput(uint32_t id) const {
+  auto output_it = GetOutputItById(id);
+  // This is unlikely to happen, but better to be explicit here.
+  DCHECK(output_it != output_list_.end());
+  return output_it->get();
+}
+
 void WaylandOutputManager::OnWaylandOutputAdded(uint32_t output_id) {
   if (wayland_screen_)
     wayland_screen_->OnOutputAdded(output_id);
@@ -107,4 +108,11 @@
                                             scale_factor);
 }
 
+WaylandOutputManager::OutputList::const_iterator
+WaylandOutputManager::GetOutputItById(uint32_t id) const {
+  return std::find_if(
+      output_list_.begin(), output_list_.end(),
+      [id](const auto& item) { return item->output_id() == id; });
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_output_manager.h b/ui/ozone/platform/wayland/host/wayland_output_manager.h
index 8123232..f05828a6 100644
--- a/ui/ozone/platform/wayland/host/wayland_output_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_output_manager.h
@@ -39,6 +39,9 @@
       WaylandConnection* connection);
 
   uint32_t GetIdForOutput(wl_output* output) const;
+  WaylandOutput* GetOutput(uint32_t id) const;
+
+  WaylandScreen* wayland_screen() const { return wayland_screen_.get(); }
 
  private:
   void OnWaylandOutputAdded(uint32_t output_id);
@@ -49,7 +52,11 @@
                              const gfx::Rect& new_bounds,
                              int32_t scale_factor) override;
 
-  std::vector<std::unique_ptr<WaylandOutput>> output_list_;
+  using OutputList = std::vector<std::unique_ptr<WaylandOutput>>;
+
+  OutputList::const_iterator GetOutputItById(uint32_t id) const;
+
+  OutputList output_list_;
 
   // Non-owned wayland screen instance.
   base::WeakPtr<WaylandScreen> wayland_screen_;
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
index e53a959..9ca9632 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -23,14 +23,12 @@
 WaylandScreen::~WaylandScreen() = default;
 
 void WaylandScreen::OnOutputAdded(uint32_t output_id) {
-  display::Display new_display(output_id);
-  display_list_.AddDisplay(std::move(new_display),
+  display_list_.AddDisplay(display::Display(output_id),
                            display::DisplayList::Type::NOT_PRIMARY);
 }
 
 void WaylandScreen::OnOutputRemoved(uint32_t output_id) {
-  display::Display primary_display = GetPrimaryDisplay();
-  if (primary_display.id() == output_id) {
+  if (output_id == GetPrimaryDisplay().id()) {
     // First, set a new primary display as required by the |display_list_|. It's
     // safe to set any of the displays to be a primary one. Once the output is
     // completely removed, Wayland updates geometry of other displays. And a
@@ -49,9 +47,9 @@
 
 void WaylandScreen::OnOutputMetricsChanged(uint32_t output_id,
                                            const gfx::Rect& new_bounds,
-                                           float device_pixel_ratio) {
+                                           int32_t output_scale) {
   display::Display changed_display(output_id);
-  changed_display.set_device_scale_factor(device_pixel_ratio);
+  changed_display.SetDeviceScaleFactor(output_scale);
   changed_display.set_bounds(new_bounds);
   changed_display.set_work_area(new_bounds);
 
@@ -81,6 +79,9 @@
   display_list_.UpdateDisplay(
       changed_display, is_primary ? display::DisplayList::Type::PRIMARY
                                   : display::DisplayList::Type::NOT_PRIMARY);
+
+  for (auto* window : connection_->GetWindowsOnDisplay(output_id))
+    window->UpdateBufferScale(true);
 }
 
 base::WeakPtr<WaylandScreen> WaylandScreen::GetWeakPtr() {
@@ -99,13 +100,14 @@
 
 display::Display WaylandScreen::GetDisplayForAcceleratedWidget(
     gfx::AcceleratedWidget widget) const {
-  auto* wayland_window = connection_->GetWindow(widget);
+  auto* window = connection_->GetWindow(widget);
   // A window might be destroyed by this time on shutting down the browser.
-  if (!wayland_window)
+  if (!window)
     return GetPrimaryDisplay();
 
-  const std::set<uint32_t> entered_outputs_ids =
-      wayland_window->GetEnteredOutputsIds();
+  const auto* parent_window = window->parent_window();
+
+  const std::set<uint32_t> entered_outputs_ids = window->GetEnteredOutputsIds();
   // Although spec says a surface receives enter/leave surface events on
   // create/move/resize actions, this might be called right after a window is
   // created, but it has not been configured by a Wayland compositor and it has
@@ -114,14 +116,19 @@
   // events immediately, which can result in empty container of entered ids
   // (check comments in WaylandWindow::RemoveEnteredOutputId). In this case,
   // it's also safe to return the primary display.
-  if (entered_outputs_ids.empty())
+  // A child window will most probably enter the same display than its parent
+  // so we return the parent's display if there is a parent.
+  if (entered_outputs_ids.empty()) {
+    if (parent_window)
+      return GetDisplayForAcceleratedWidget(parent_window->GetWidget());
     return GetPrimaryDisplay();
+  }
 
   DCHECK(!display_list_.displays().empty());
 
   // A widget can be located on two or more displays. It would be better if the
-  // most in pixels occupied display was returned, but it's impossible to do in
-  // Wayland. Thus, return the one, which was the very first used.
+  // most in DIP occupied display was returned, but it's impossible to do so in
+  // Wayland. Thus, return the one that was used the earliest.
   for (const auto& display : display_list_.displays()) {
     if (display.id() == *entered_outputs_ids.begin())
       return display;
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.h b/ui/ozone/platform/wayland/host/wayland_screen.h
index f395b9b..c81b47a3 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.h
+++ b/ui/ozone/platform/wayland/host/wayland_screen.h
@@ -29,7 +29,7 @@
   void OnOutputRemoved(uint32_t output_id);
   void OnOutputMetricsChanged(uint32_t output_id,
                               const gfx::Rect& bounds,
-                              float device_pixel_ratio);
+                              int32_t output_scale);
 
   base::WeakPtr<WaylandScreen> GetWeakPtr();
 
diff --git a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index 54e72fb5..f93ac20d 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -223,9 +223,8 @@
   EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
   EXPECT_EQ(observer.GetDisplay().bounds(), new_rect);
 
-  const float new_scale_value = 2.0f;
-  wl_output_send_scale(output_->resource(), new_scale_value);
-  wl_output_send_done(output_->resource());
+  const int32_t new_scale_value = 2;
+  output_->SetScale(new_scale_value);
 
   Sync();
 
@@ -580,6 +579,23 @@
   EXPECT_EQ(gfx::Point(1912, 1071), platform_screen_->GetCursorScreenPoint());
 }
 
+// Checks that the surface that backs the window receives new scale of the
+// output that it is in.
+TEST_P(WaylandScreenTest, SetBufferScale) {
+  // Place the window onto the output.
+  wl_surface_send_enter(surface_->resource(), output_->resource());
+
+  // Change the scale of the output.  Windows looking into that output must get
+  // the new scale and update scale of their buffers.
+  const int32_t kNewScale = 3;
+  EXPECT_CALL(*surface_, SetBufferScale(kNewScale));
+  output_->SetScale(kNewScale);
+
+  Sync();
+
+  EXPECT_EQ(window_->buffer_scale(), kNewScale);
+}
+
 INSTANTIATE_TEST_SUITE_P(XdgVersionV5Test,
                          WaylandScreenTest,
                          ::testing::Values(kXdgShellV5));
diff --git a/ui/ozone/platform/wayland/host/wayland_touch.cc b/ui/ozone/platform/wayland/host/wayland_touch.cc
index ce18b08..eaec157 100644
--- a/ui/ozone/platform/wayland/host/wayland_touch.cc
+++ b/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -72,7 +72,9 @@
   WaylandTouch* touch = static_cast<WaylandTouch*>(data);
   DCHECK(touch);
   touch->connection_->set_serial(serial);
-  WaylandWindow::FromSurface(surface)->set_touch_focus(true);
+  auto* window = WaylandWindow::FromSurface(surface);
+  DCHECK(window);
+  window->set_touch_focus(true);
 
   // Make sure this touch point wasn't present before.
   if (touch->current_points_.find(id) != touch->current_points_.end()) {
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index 4b0a990..7854c21 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -122,7 +122,11 @@
 bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
   DCHECK(xdg_shell_objects_factory_);
 
-  bounds_ = properties.bounds;
+  // Properties contain DIP bounds but the buffer scale is initially 1 so it's
+  // OK to assign.  The bounds will be recalculated when the buffer scale
+  // changes.
+  DCHECK_EQ(buffer_scale_, 1);
+  bounds_px_ = properties.bounds;
   opacity_ = properties.opacity;
 
   surface_.reset(wl_compositor_create_surface(connection_->compositor()));
@@ -130,15 +134,20 @@
     LOG(ERROR) << "Failed to create wl_surface";
     return false;
   }
-  wl_surface_set_user_data(surface_.get(), this);
+
+  wl_surface_set_user_data(surface(), this);
+
   AddSurfaceListener();
 
-  ui::PlatformWindowType ui_window_type = properties.type;
-  switch (ui_window_type) {
+  switch (properties.type) {
     case ui::PlatformWindowType::kMenu:
     case ui::PlatformWindowType::kPopup:
       parent_window_ = GetParentWindow(properties.parent_widget);
 
+      // Popups need to know their scale earlier to position themselves.
+      DCHECK(parent_window_);
+      SetBufferScale(parent_window_->buffer_scale_, false);
+
       // TODO(msisov, jkim): Handle notification windows, which are marked
       // as popup windows as well. Those are the windows that do not have
       // parents and pop up when the browser receives a notification.
@@ -159,10 +168,35 @@
   PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
   delegate_->OnAcceleratedWidgetAvailable(GetWidget());
 
+  // Will do nothing for popups because they have got their scale above.
+  UpdateBufferScale(false);
+
   MaybeUpdateOpaqueRegion();
   return true;
 }
 
+void WaylandWindow::UpdateBufferScale(bool update_bounds) {
+  DCHECK(connection_->wayland_output_manager());
+  const auto* screen = connection_->wayland_output_manager()->wayland_screen();
+  DCHECK(screen);
+  const auto widget = GetWidget();
+
+  int32_t new_scale = 0;
+  if (parent_window_) {
+    new_scale = parent_window_->buffer_scale_;
+  } else if (widget == gfx::kNullAcceleratedWidget) {
+    new_scale = screen->GetPrimaryDisplay().device_scale_factor();
+  } else {
+    // This is the main window that is fully set up so we can ask which display
+    // we are at currently.
+    current_display_ = screen->GetDisplayForAcceleratedWidget(widget);
+    new_scale = connection_->wayland_output_manager()
+                    ->GetOutput(current_display_.id())
+                    ->scale_factor();
+  }
+  SetBufferScale(new_scale, update_bounds);
+}
+
 gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
   if (!surface_)
     return gfx::kNullAcceleratedWidget;
@@ -174,7 +208,7 @@
 }
 
 void WaylandWindow::CreateXdgPopup() {
-  if (bounds_.IsEmpty())
+  if (bounds_px_.IsEmpty())
     return;
 
   // TODO(jkim): Consider how to support DropArrow window on tabstrip.
@@ -192,11 +226,11 @@
 
   DCHECK(parent_window_ && !xdg_popup_);
 
-  auto bounds = AdjustPopupWindowPosition();
+  auto bounds_px = AdjustPopupWindowPosition();
 
   xdg_popup_ = xdg_shell_objects_factory_->CreateXDGPopup(connection_, this);
-  if (!xdg_popup_ ||
-      !xdg_popup_->Initialize(connection_, surface(), parent_window_, bounds)) {
+  if (!xdg_popup_ || !xdg_popup_->Initialize(connection_, surface(),
+                                             parent_window_, bounds_px)) {
     CHECK(false) << "Failed to create xdg_popup";
   }
 
@@ -233,22 +267,24 @@
   }
 
   DCHECK(tooltip_subsurface_);
-  wl_subsurface_set_position(tooltip_subsurface_.get(), bounds_.x(),
-                             bounds_.y());
+  // Convert position to DIP.
+  wl_subsurface_set_position(tooltip_subsurface_.get(),
+                             bounds_px_.x() / buffer_scale_,
+                             bounds_px_.y() / buffer_scale_);
   wl_subsurface_set_desync(tooltip_subsurface_.get());
   wl_surface_commit(parent_window_->surface());
   connection_->ScheduleFlush();
 }
 
 void WaylandWindow::ApplyPendingBounds() {
-  if (pending_bounds_.IsEmpty())
+  if (pending_bounds_dip_.IsEmpty())
     return;
   DCHECK(xdg_surface_);
 
-  SetBounds(pending_bounds_);
-  xdg_surface_->SetWindowGeometry(bounds_);
+  SetBoundsDip(pending_bounds_dip_);
+  xdg_surface_->SetWindowGeometry(pending_bounds_dip_);
   xdg_surface_->AckConfigure();
-  pending_bounds_ = gfx::Rect();
+  pending_bounds_dip_ = gfx::Rect();
   connection_->ScheduleFlush();
 
   // Opaque region is based on the size of the window. Thus, update the region
@@ -292,9 +328,16 @@
   }
 
   if (!xdg_popup_) {
+    // When showing a sub-menu after it has been previously shown and hidden,
+    // Wayland sends SetBounds prior to Show, and |bounds_px| takes the pixel
+    // bounds.  This makes a difference against the normal flow when the
+    // window is created (see |Initialize|).  To equalize things, rescale
+    // |bounds_px_| to DIP.  It will be adjusted while creating the popup.
+    bounds_px_ = gfx::ScaleToRoundedRect(bounds_px_, 1.0 / buffer_scale_);
     CreateXdgPopup();
     connection_->ScheduleFlush();
   }
+  UpdateBufferScale(false);
 }
 
 void WaylandWindow::Hide() {
@@ -324,15 +367,23 @@
 
 void WaylandWindow::PrepareForShutdown() {}
 
-void WaylandWindow::SetBounds(const gfx::Rect& bounds) {
-  if (bounds == bounds_)
+void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) {
+  // TODO(adunaev): figure out if this return is legitimate, see
+  // https://crbug.com/958314
+  // The X11 implementation says that even if the pixel bounds
+  // didn't change, we still need to forward this call to the delegate, and that
+  // the device scale factor may have changed which effectively changes the
+  // bounds.  Perhaps we need to do the same here.
+  if (bounds_px_ == bounds_px)
     return;
-  bounds_ = bounds;
-  delegate_->OnBoundsChanged(bounds);
+
+  bounds_px_ = bounds_px;
+
+  delegate_->OnBoundsChanged(bounds_px_);
 }
 
 gfx::Rect WaylandWindow::GetBounds() {
-  return bounds_;
+  return bounds_px_;
 }
 
 void WaylandWindow::SetTitle(const base::string16& title) {
@@ -459,12 +510,12 @@
   return nullptr;
 }
 
-void WaylandWindow::SetRestoredBoundsInPixels(const gfx::Rect& bounds) {
-  restored_bounds_ = bounds;
+void WaylandWindow::SetRestoredBoundsInPixels(const gfx::Rect& bounds_px) {
+  restored_bounds_px_ = bounds_px;
 }
 
 gfx::Rect WaylandWindow::GetRestoredBoundsInPixels() const {
-  return restored_bounds_;
+  return restored_bounds_px_;
 }
 
 bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
@@ -495,6 +546,10 @@
   Event* event = static_cast<Event*>(native_event);
 
   if (event->IsLocatedEvent()) {
+    // Located events come in output scale and need to be translated to
+    // physical pixels.
+    event->AsLocatedEvent()->set_location_f(gfx::ScalePoint(
+        event->AsLocatedEvent()->location_f(), buffer_scale_, buffer_scale_));
     auto copied_event = Event::Clone(*event);
     UpdateCursorPositionFromEvent(std::move(copied_event));
   }
@@ -576,11 +631,12 @@
   // explicitly set the bounds to the current desired ones or the previous
   // bounds.
   if (width > 1 && height > 1) {
-    pending_bounds_ = gfx::Rect(0, 0, width, height);
+    pending_bounds_dip_ = gfx::Rect(0, 0, width, height);
   } else if (is_normal) {
-    pending_bounds_.set_size(restored_bounds_.IsEmpty()
-                                 ? GetBounds().size()
-                                 : restored_bounds_.size());
+    pending_bounds_dip_.set_size(gfx::ScaleToRoundedSize(
+        restored_bounds_px_.IsEmpty() ? GetBounds().size()
+                                      : restored_bounds_px_.size(),
+        1.0 / buffer_scale_));
   }
 
   if (state_changed) {
@@ -592,8 +648,8 @@
     if (is_normal) {
       SetRestoredBoundsInPixels({});
     } else if (old_state == PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL ||
-               restored_bounds_.IsEmpty()) {
-      SetRestoredBoundsInPixels(bounds_);
+               restored_bounds_px_.IsEmpty()) {
+      SetRestoredBoundsInPixels(bounds_px_);
     }
 
     delegate_->OnWindowStateChanged(state_);
@@ -602,12 +658,18 @@
   if (did_active_change)
     delegate_->OnActivationChanged(is_active_);
 
+  UpdateBufferScale(true);
+
   MaybeTriggerPendingStateChange();
 }
 
-void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds) {
+void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
   DCHECK(xdg_popup());
-  gfx::Rect new_bounds = bounds;
+  DCHECK(parent_window_);
+
+  SetBufferScale(parent_window_->buffer_scale_, true);
+
+  gfx::Rect new_bounds_dip = bounds_dip;
 
   // It's not enough to just set new bounds. If it is a menu window, whose
   // parent is a top level window aka browser window, it can be flipped
@@ -625,10 +687,10 @@
     gfx::Rect parent_bounds = parent_window_->GetBounds();
     // The menu window is flipped along y-axis and have x,-y origin. Shift the
     // parent top level window instead.
-    if (new_bounds.y() < 0) {
+    if (new_bounds_dip.y() < 0) {
       // Move parent bounds along y-axis.
-      parent_bounds.set_y(-(new_bounds.y()));
-      new_bounds.set_y(0);
+      parent_bounds.set_y(-(new_bounds_dip.y() * buffer_scale_));
+      new_bounds_dip.set_y(0);
     } else {
       // If the menu window is located at correct origin from the browser point
       // of view, return the top level window back to 0,0.
@@ -640,11 +702,16 @@
     // Thus, the location must be translated to be relative to the top level
     // window, which automatically becomes the same as relative to an origin of
     // a display.
-    new_bounds = TranslateBoundsToTopLevelCoordinates(
-        new_bounds, parent_window_->GetBounds());
-    DCHECK(new_bounds.y() >= 0);
+    new_bounds_dip = gfx::ScaleToRoundedRect(
+        TranslateBoundsToTopLevelCoordinates(
+            gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale_),
+            parent_window_->GetBounds()),
+        1.0 / buffer_scale_);
+    DCHECK(new_bounds_dip.y() >= 0);
   }
-  SetBounds(new_bounds);
+
+  // Finally, the menu bounds must be converted to physical pixels.
+  SetBoundsDip(new_bounds_dip);
 }
 
 void WaylandWindow::OnCloseRequest() {
@@ -692,6 +759,26 @@
   connection_->ResetPointerFlags();
 }
 
+void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) {
+  SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_));
+}
+
+void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) {
+  DCHECK_GT(new_scale, 0);
+
+  if (new_scale == buffer_scale_)
+    return;
+
+  auto old_scale = buffer_scale_;
+  buffer_scale_ = new_scale;
+  if (update_bounds)
+    SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / old_scale));
+
+  DCHECK(surface());
+  wl_surface_set_buffer_scale(surface(), buffer_scale_);
+  connection_->ScheduleFlush();
+}
+
 bool WaylandWindow::IsMinimized() const {
   return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED;
 }
@@ -747,14 +834,28 @@
 }
 
 void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
+  // Wayland does weird things for popups so instead of tracking outputs that
+  // we entered or left, we take that from the parent window and ignore this
+  // event.
+  if (xdg_popup())
+    return;
+
   const uint32_t entered_output_id =
       connection_->wayland_output_manager()->GetIdForOutput(output);
   DCHECK_NE(entered_output_id, 0u);
   auto result = entered_outputs_ids_.insert(entered_output_id);
   DCHECK(result.first != entered_outputs_ids_.end());
+
+  UpdateBufferScale(true);
 }
 
 void WaylandWindow::RemoveEnteredOutputId(struct wl_output* output) {
+  // Wayland does weird things for popups so instead of tracking outputs that
+  // we entered or left, we take that from the parent window and ignore this
+  // event.
+  if (xdg_popup())
+    return;
+
   const uint32_t left_output_id =
       connection_->wayland_output_manager()->GetIdForOutput(output);
   auto entered_output_id_it = entered_outputs_ids_.find(left_output_id);
@@ -764,8 +865,11 @@
   // displays in a single output mode results in leave events, but the surface
   // might not have received enter event before. Thus, remove the id of left
   // output only if it was stored before.
-  if (entered_output_id_it != entered_outputs_ids_.end())
+  if (entered_output_id_it != entered_outputs_ids_.end()) {
     entered_outputs_ids_.erase(entered_output_id_it);
+  }
+
+  UpdateBufferScale(true);
 }
 
 void WaylandWindow::UpdateCursorPositionFromEvent(
@@ -814,11 +918,15 @@
                             ? parent_window_->parent_window_
                             : parent_window_;
   DCHECK(parent_window);
+  DCHECK(buffer_scale_ == parent_window->buffer_scale_);
+
   // Chromium positions windows in screen coordinates, but Wayland requires them
   // to be in local surface coordinates aka relative to parent window.
-  const gfx::Rect parent_bounds = parent_window_->GetBounds();
+  const gfx::Rect parent_bounds_px =
+      gfx::ScaleToRoundedRect(parent_window_->GetBounds(), 1.0 / buffer_scale_);
+
   gfx::Rect new_bounds =
-      TranslateBoundsToParentCoordinates(bounds_, parent_bounds);
+      TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_px);
 
   // Chromium may decide to position nested menu windows on the left side
   // instead of the right side of parent menu windows when the size of the
@@ -842,7 +950,8 @@
       // Position the child menu window on the right side of the parent window
       // and let the Wayland compositor decide how to do constraint
       // adjustements.
-      int new_x = parent_bounds.width() - (new_bounds.width() + new_bounds.x());
+      int new_x =
+          parent_bounds_px.width() - (new_bounds.width() + new_bounds.x());
       new_bounds.set_x(new_x);
     }
   }
@@ -859,7 +968,7 @@
 
   wl::Object<wl_region> region(
       wl_compositor_create_region(connection_->compositor()));
-  wl_region_add(region.get(), 0, 0, bounds_.width(), bounds_.height());
+  wl_region_add(region.get(), 0, 0, bounds_px_.width(), bounds_px_.height());
   wl_surface_set_opaque_region(surface(), region.get());
 
   connection_->ScheduleFlush();
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 3d46ba1f..7ea2fa94 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
+#include "ui/display/display.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
@@ -51,10 +52,19 @@
 
   bool Initialize(PlatformWindowInitProperties properties);
 
+  // Updates the surface buffer scale of the window.  Top level windows take
+  // scale according to scale of their current display or the primary one if
+  // their widget is not yet created, children inherit scale from their parent.
+  // The method recalculates window bounds appropriately if asked to do so
+  // (this is not needed upon window initialization).
+  void UpdateBufferScale(bool update_bounds);
+
   wl_surface* surface() const { return surface_.get(); }
   XDGSurfaceWrapper* xdg_surface() const { return xdg_surface_.get(); }
   XDGPopupWrapper* xdg_popup() const { return xdg_popup_.get(); }
 
+  WaylandWindow* parent_window() const { return parent_window_; }
+
   gfx::AcceleratedWidget GetWidget() const;
 
   // Returns the list of wl_outputs aka displays, which this window occupies.
@@ -89,6 +99,8 @@
   void set_has_implicit_grab(bool value) { has_implicit_grab_ = value; }
   bool has_implicit_grab() const { return has_implicit_grab_; }
 
+  int32_t buffer_scale() const { return buffer_scale_; }
+
   bool is_active() const { return is_active_; }
 
   // WmMoveResizeHandler
@@ -129,6 +141,10 @@
   bool CanDispatchEvent(const PlatformEvent& event) override;
   uint32_t DispatchEvent(const PlatformEvent& event) override;
 
+  // Handles the configuration events coming from the surface (see
+  // |XDGSurfaceWrapperV5::Configure| and
+  // |XDGSurfaceWrapperV6::ConfigureTopLevel|.  The width and height come in
+  // DIP of the output that the surface is currently bound to.
   void HandleSurfaceConfigure(int32_t widht,
                               int32_t height,
                               bool is_maximized,
@@ -147,6 +163,9 @@
   void OnDragSessionClose(uint32_t dnd_action);
 
  private:
+  void SetBoundsDip(const gfx::Rect& bounds_dip);
+  void SetBufferScale(int32_t scale, bool update_bounds);
+
   bool IsMinimized() const;
   bool IsMaximized() const;
   bool IsFullscreen() const;
@@ -214,14 +233,28 @@
 
   base::OnceCallback<void(int)> drag_closed_callback_;
 
-  gfx::Rect bounds_;
-  gfx::Rect pending_bounds_;
+  // These bounds attributes below have suffices that indicate uints used.
+  // Values measured in physical pixels are used in calls to PlatformWindow
+  // and PlatformWindowDelegate that work with physical pixels.
+  //
+  // Current bounds of the window.
+  gfx::Rect bounds_px_;
+  // Bounds that will be applied when the window state is finalized.  The window
+  // may get several configuration events that update the pending bounds, and
+  // only upon finalizing the state is the latest value stored as the current
+  // bounds via |ApplyPendingBounds|.  Measured in DIP because updated in the
+  // handler that receives DIP.
+  gfx::Rect pending_bounds_dip_;
   // The bounds of the window before it went maximized or fullscreen.
-  gfx::Rect restored_bounds_;
+  gfx::Rect restored_bounds_px_;
+
+  display::Display current_display_;
+
   bool has_pointer_focus_ = false;
   bool has_keyboard_focus_ = false;
   bool has_touch_focus_ = false;
   bool has_implicit_grab_ = false;
+  int32_t buffer_scale_ = 1;
 
   // Stores current states of the window.
   ui::PlatformWindowState state_;
@@ -237,7 +270,14 @@
 
   bool is_tooltip_ = false;
 
-  // Stores the list of entered outputs that the window is currently in.
+  // For top level window, stores the list of entered outputs that the window
+  // is currently in.
+  //
+  // For a popup, not used.  Wayland 'repositions' sub-menus to wrong outputs
+  // (by sending them leave and enter events) when sub-menus are hidden and
+  // shown again so their list of entered outputs becomes meaningless after
+  // they have been hidden at least once.  To determine which output the popup
+  // belongs to, refer to its parent.
   std::set<uint32_t> entered_outputs_ids_;
 
   DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.cc
index a17719e..0f04fcd 100644
--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.cc
+++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_v6.cc
@@ -166,6 +166,8 @@
       break;
   }
 
+  if (anchor_rect.width() == 0)
+    anchor_rect.set_width(1);
   return anchor_rect;
 }
 
@@ -257,8 +259,10 @@
     menu_type = MenuType::TYPE_3DOT_PARENT_MENU;
 
   // Place anchor to the end of the possible position.
-  gfx::Rect anchor_rect =
-      GetAnchorRect(menu_type, bounds, parent_window->GetBounds());
+  gfx::Rect anchor_rect = GetAnchorRect(
+      menu_type, bounds,
+      gfx::ScaleToRoundedRect(parent_window->GetBounds(),
+                              1.0 / parent_window->buffer_scale()));
 
   zxdg_positioner_v6_set_anchor_rect(positioner, anchor_rect.x(),
                                      anchor_rect.y(), anchor_rect.width(),
@@ -284,11 +288,10 @@
   // Wayland requires doing so in respect to parent window's origin. To properly
   // place windows, the bounds are translated and adjusted according to the
   // Wayland compositor needs during WaylandWindow::CreateXdgPopup call.
-  gfx::Rect new_bounds(x, y, width, height);
   WaylandWindow* window =
       static_cast<XDGPopupWrapperV6*>(data)->wayland_window_;
   DCHECK(window);
-  window->HandlePopupConfigure(new_bounds);
+  window->HandlePopupConfigure({x, y, width, height});
 }
 
 // static
diff --git a/ui/ozone/platform/wayland/test/mock_surface.cc b/ui/ozone/platform/wayland/test/mock_surface.cc
index bab5b77..7669ea4 100644
--- a/ui/ozone/platform/wayland/test/mock_surface.cc
+++ b/ui/ozone/platform/wayland/test/mock_surface.cc
@@ -41,6 +41,10 @@
   GetUserDataAs<MockSurface>(resource)->Commit();
 }
 
+void SetBufferScale(wl_client* client, wl_resource* resource, int32_t scale) {
+  GetUserDataAs<MockSurface>(resource)->SetBufferScale(scale);
+}
+
 }  // namespace
 
 const struct wl_surface_interface kMockSurfaceImpl = {
@@ -52,7 +56,7 @@
     SetInputRegion,   // set_input_region
     Commit,           // commit
     nullptr,          // set_buffer_transform
-    nullptr,          // set_buffer_scale
+    SetBufferScale,   // set_buffer_scale
     nullptr,          // damage_buffer
 };
 
diff --git a/ui/ozone/platform/wayland/test/mock_surface.h b/ui/ozone/platform/wayland/test/mock_surface.h
index 0f83878b..1531c48 100644
--- a/ui/ozone/platform/wayland/test/mock_surface.h
+++ b/ui/ozone/platform/wayland/test/mock_surface.h
@@ -36,6 +36,7 @@
   MOCK_METHOD4(Damage,
                void(int32_t x, int32_t y, int32_t width, int32_t height));
   MOCK_METHOD0(Commit, void());
+  MOCK_METHOD1(SetBufferScale, void(int32_t scale));
 
   void set_xdg_surface(std::unique_ptr<MockXdgSurface> xdg_surface) {
     xdg_surface_ = std::move(xdg_surface);
diff --git a/ui/ozone/platform/wayland/test/test_output.cc b/ui/ozone/platform/wayland/test/test_output.cc
index 4abdc319..bbc6475 100644
--- a/ui/ozone/platform/wayland/test/test_output.cc
+++ b/ui/ozone/platform/wayland/test/test_output.cc
@@ -31,4 +31,9 @@
   wl_output_send_done(resource());
 }
 
+void TestOutput::SetScale(int32_t factor) {
+  wl_output_send_scale(resource(), factor);
+  wl_output_send_done(resource());
+}
+
 }  // namespace wl
diff --git a/ui/ozone/platform/wayland/test/test_output.h b/ui/ozone/platform/wayland/test/test_output.h
index bbd6848c..8dffd41 100644
--- a/ui/ozone/platform/wayland/test/test_output.h
+++ b/ui/ozone/platform/wayland/test/test_output.h
@@ -20,6 +20,8 @@
   const gfx::Rect GetRect() { return rect_; }
   void OnBind() override;
 
+  void SetScale(int32_t factor);
+
  private:
   gfx::Rect rect_;
 
diff --git a/ui/ozone/platform/wayland/test/wayland_test.cc b/ui/ozone/platform/wayland/test/wayland_test.cc
index e96443b..ed36b2a 100644
--- a/ui/ozone/platform/wayland/test/wayland_test.cc
+++ b/ui/ozone/platform/wayland/test/wayland_test.cc
@@ -6,6 +6,8 @@
 
 #include "base/run_loop.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_screen.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/platform_window/platform_window_init_properties.h"
 
@@ -41,6 +43,8 @@
 void WaylandTest::SetUp() {
   ASSERT_TRUE(server_.Start(GetParam()));
   ASSERT_TRUE(connection_->Initialize());
+  screen_ = connection_->wayland_output_manager()->CreateWaylandScreen(
+      connection_.get());
   EXPECT_CALL(delegate_, OnAcceleratedWidgetAvailable(_))
       .WillOnce(SaveArg<0>(&widget_));
   PlatformWindowInitProperties properties;
diff --git a/ui/ozone/platform/wayland/test/wayland_test.h b/ui/ozone/platform/wayland/test/wayland_test.h
index 461d279..0c4103e1 100644
--- a/ui/ozone/platform/wayland/test/wayland_test.h
+++ b/ui/ozone/platform/wayland/test/wayland_test.h
@@ -27,6 +27,8 @@
 
 namespace ui {
 
+class WaylandScreen;
+
 const uint32_t kXdgShellV5 = 5;
 const uint32_t kXdgShellV6 = 6;
 
@@ -51,6 +53,7 @@
   MockPlatformWindowDelegate delegate_;
   std::unique_ptr<WaylandConnectionProxy> connection_proxy_;
   std::unique_ptr<WaylandConnection> connection_;
+  std::unique_ptr<WaylandScreen> screen_;
   std::unique_ptr<WaylandWindow> window_;
   gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
 
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 08e0d409..6dff2aa 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -309,6 +309,10 @@
   accessible_name_ = name;
 }
 
+base::string16 Combobox::GetAccessibleName() const {
+  return accessible_name_;
+}
+
 void Combobox::SetInvalid(bool invalid) {
   if (invalid == invalid_)
     return;
@@ -319,7 +323,7 @@
     focus_ring_->SetInvalid(invalid);
 
   UpdateBorder();
-  SchedulePaint();
+  OnPropertyChanged(&selected_index_, kPropertyEffectsPaint);
 }
 
 void Combobox::Layout() {
@@ -658,7 +662,10 @@
 }
 
 BEGIN_METADATA(Combobox)
+METADATA_PARENT_CLASS(View)
 ADD_PROPERTY_METADATA(Combobox, int, SelectedIndex)
+ADD_PROPERTY_METADATA(Combobox, bool, Invalid)
+ADD_PROPERTY_METADATA(Combobox, base::string16, AccessibleName)
 END_METADATA()
 
 }  // namespace views
diff --git a/ui/views/controls/combobox/combobox.h b/ui/views/controls/combobox/combobox.h
index 3bb2252e..727b05a 100644
--- a/ui/views/controls/combobox/combobox.h
+++ b/ui/views/controls/combobox/combobox.h
@@ -77,12 +77,13 @@
 
   // Set the accessible name of the combobox.
   void SetAccessibleName(const base::string16& name);
+  base::string16 GetAccessibleName() const;
 
   // Visually marks the combobox as having an invalid value selected.
   // When invalid, it paints with white text on a red background.
   // Callers are responsible for restoring validity with selection changes.
   void SetInvalid(bool invalid);
-  bool invalid() const { return invalid_; }
+  bool GetInvalid() const { return invalid_; }
 
   // Overridden from View:
   gfx::Size CalculatePreferredSize() const override;
diff --git a/ui/views/controls/menu/submenu_view.cc b/ui/views/controls/menu/submenu_view.cc
index ac11f57e..b054b1fe 100644
--- a/ui/views/controls/menu/submenu_view.cc
+++ b/ui/views/controls/menu/submenu_view.cc
@@ -159,16 +159,16 @@
       const MenuItemView* menu = static_cast<const MenuItemView*>(child);
       const MenuItemView::MenuItemDimensions& dimensions =
           menu->GetDimensions();
-      max_simple_width = std::max(
-          max_simple_width, dimensions.standard_width);
+      max_simple_width = std::max(max_simple_width, dimensions.standard_width);
       max_minor_text_width_ =
           std::max(max_minor_text_width_, dimensions.minor_text_width);
-      max_complex_width = std::max(max_complex_width,
-          dimensions.standard_width + dimensions.children_width);
+      max_complex_width =
+          std::max(max_complex_width,
+                   dimensions.standard_width + dimensions.children_width);
       touchable_minimum_width = dimensions.standard_width;
     } else {
-      max_complex_width = std::max(max_complex_width,
-                                   child->GetPreferredSize().width());
+      max_complex_width =
+          std::max(max_complex_width, child->GetPreferredSize().width());
     }
   }
   if (max_minor_text_width_ > 0)
@@ -176,10 +176,10 @@
 
   // Finish calculating our optimum width.
   gfx::Insets insets = GetInsets();
-  int width = std::max(max_complex_width,
-                       std::max(max_simple_width + max_minor_text_width_ +
-                                    insets.width(),
-                                minimum_preferred_width_ - 2 * insets.width()));
+  int width = std::max(
+      max_complex_width,
+      std::max(max_simple_width + max_minor_text_width_ + insets.width(),
+               minimum_preferred_width_ - 2 * insets.width()));
 
   if (parent_menu_item_->GetMenuController() &&
       parent_menu_item_->GetMenuController()->use_touchable_layout()) {
@@ -316,8 +316,8 @@
       if (scrolled_to_top(*i))
         i = next_iter;
     }
-    ScrollRectToVisible(gfx::Rect(gfx::Point(0, scroll_target),
-                                  vis_bounds.size()));
+    ScrollRectToVisible(
+        gfx::Rect(gfx::Point(0, scroll_target), vis_bounds.size()));
     vis_bounds = GetVisibleBounds();
   }
 
diff --git a/ui/views/metadata/metadata_types.h b/ui/views/metadata/metadata_types.h
index 077520f..c8d8177 100644
--- a/ui/views/metadata/metadata_types.h
+++ b/ui/views/metadata/metadata_types.h
@@ -144,7 +144,10 @@
 // (so it will trigger things like property changed notifications).
 template <typename TClass,
           typename TValue,
-          void (TClass::*Set)(const TValue value),
+          void (TClass::*Set)(
+              typename std::conditional<std::is_fundamental<TValue>::value,
+                                        TValue,
+                                        const TValue&>::type),
           TValue (TClass::*Get)() const>
 class ClassPropertyMetaData : public MemberMetaDataBase {
  public:
diff --git a/ui/views/metadata/type_conversion.cc b/ui/views/metadata/type_conversion.cc
index 273a5fa..59467ad 100644
--- a/ui/views/metadata/type_conversion.cc
+++ b/ui/views/metadata/type_conversion.cc
@@ -17,6 +17,12 @@
 /***** String Conversions *****/
 
 template <>
+base::string16 ConvertToString<base::string16>(
+    const base::string16& source_value) {
+  return source_value;
+}
+
+template <>
 base::string16 ConvertToString<int8_t>(const int8_t& source_value) {
   return base::NumberToString16(source_value);
 }
diff --git a/ui/views/metadata/type_conversion.h b/ui/views/metadata/type_conversion.h
index 2c982c8..c991793 100644
--- a/ui/views/metadata/type_conversion.h
+++ b/ui/views/metadata/type_conversion.h
@@ -40,6 +40,10 @@
 base::string16 ConvertToString(const TSource& source_value) = delete;
 
 template <>
+VIEWS_EXPORT base::string16 ConvertToString<base::string16>(
+    const base::string16& source_value);
+
+template <>
 VIEWS_EXPORT base::string16 ConvertToString<int8_t>(const int8_t& source_value);
 
 template <>
@@ -87,6 +91,16 @@
   }
 };
 
+// A specialization used for string16 conversions. Since it simply passes
+// the value, it is used for both converting to and from a string16 value.
+template <>
+class TypeConverter<base::string16, base::string16> {
+ public:
+  static base::string16 Convert(const base::string16& source_val) {
+    return ConvertToString<base::string16>(source_val);
+  }
+};
+
 template <typename TTarget>
 TTarget ConvertFromString(const base::string16& source_value) = delete;
 
diff --git a/ui/views/widget/desktop_aura/desktop_screen_ozone.cc b/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
index 727a8da..0fa4243 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
@@ -42,7 +42,7 @@
   display::Display display(display_snapshot->display_id());
   display.set_bounds(gfx::Rect(scaled_size));
   display.set_work_area(display.bounds());
-  display.set_device_scale_factor(device_scale_factor);
+  display.SetDeviceScaleFactor(device_scale_factor);
 
   ProcessDisplayChanged(display, true /* is_primary */);
 }
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc b/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
index e4ce4e64..175db65 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
@@ -440,25 +440,25 @@
   NotifyDisplaysChanged(displays);
   ResetDisplayChanges();
 
-  displays[0].set_device_scale_factor(2.5f);
+  displays[0].SetDeviceScaleFactor(2.5f);
   NotifyDisplaysChanged(displays);
   EXPECT_EQ(1u, changed_display_.size());
   EXPECT_EQ(2.5f, gfx::GetFontRenderParamsDeviceScaleFactor());
 
-  displays[1].set_device_scale_factor(2.5f);
+  displays[1].SetDeviceScaleFactor(2.5f);
   NotifyDisplaysChanged(displays);
   EXPECT_EQ(2u, changed_display_.size());
 
-  displays[0].set_device_scale_factor(2.5f);
+  displays[0].SetDeviceScaleFactor(2.5f);
   NotifyDisplaysChanged(displays);
   EXPECT_EQ(2u, changed_display_.size());
 
-  displays[1].set_device_scale_factor(2.5f);
+  displays[1].SetDeviceScaleFactor(2.5f);
   NotifyDisplaysChanged(displays);
   EXPECT_EQ(2u, changed_display_.size());
 
-  displays[0].set_device_scale_factor(1.f);
-  displays[1].set_device_scale_factor(1.f);
+  displays[0].SetDeviceScaleFactor(1.f);
+  displays[1].SetDeviceScaleFactor(1.f);
   NotifyDisplaysChanged(displays);
   EXPECT_EQ(4u, changed_display_.size());
   EXPECT_EQ(1.f, gfx::GetFontRenderParamsDeviceScaleFactor());